mirror of
https://github.com/mCaptcha/mCaptcha.git
synced 2024-11-27 11:59:56 +03:00
notifications view
This commit is contained in:
parent
b7ec1bca22
commit
47cca5c9a7
14 changed files with 163 additions and 78 deletions
|
@ -107,6 +107,21 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"45d9e9fb6344fe3a18c2529d50c935d3837bfe25c96595beb6970d6067720578": {
|
||||
"query": "insert into mcaptcha_users \n (name , password, email, secret) values ($1, $2, $3, $4)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Varchar",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
}
|
||||
},
|
||||
"47fa50aecfb1499b0a18fa9299643017a1a8d69d4e9980032e0d8f745465d14f": {
|
||||
"query": "SELECT EXISTS (SELECT 1 from mcaptcha_users WHERE email = $1)",
|
||||
"describe": {
|
||||
|
@ -506,21 +521,6 @@
|
|||
"nullable": []
|
||||
}
|
||||
},
|
||||
"d64ed8a42ff8d8ff0db5a409c9d2ea7d61ea43c90e548a29a3a5a47679dbcd4b": {
|
||||
"query": "INSERT INTO mcaptcha_users \n (name , password, email, secret) VALUES ($1, $2, $3, $4)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Varchar",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
}
|
||||
},
|
||||
"d9a097cba4552c17b410fcb8745dd9b2eae5146f7b710006a50ae6aa2add54fa": {
|
||||
"query": "SELECT difficulty_factor, visitor_threshold FROM mcaptcha_levels WHERE\n config_id = (\n SELECT config_id FROM mcaptcha_config WHERE key = ($1)\n );",
|
||||
"describe": {
|
||||
|
|
|
@ -154,8 +154,8 @@ pub mod runners {
|
|||
let res;
|
||||
if let Some(email) = &payload.email {
|
||||
res = sqlx::query!(
|
||||
"INSERT INTO mcaptcha_users
|
||||
(name , password, email, secret) VALUES ($1, $2, $3, $4)",
|
||||
"insert into mcaptcha_users
|
||||
(name , password, email, secret) values ($1, $2, $3, $4)",
|
||||
&username,
|
||||
&hash,
|
||||
&email,
|
||||
|
@ -182,7 +182,7 @@ pub mod runners {
|
|||
if msg.contains("mcaptcha_users_name_key") {
|
||||
return Err(ServiceError::UsernameTaken);
|
||||
} else if msg.contains("mcaptcha_users_email_key") {
|
||||
return Err(ServiceError::EmailTaken);
|
||||
return Err(ServiceError::UsernameTaken);
|
||||
} else if msg.contains("mcaptcha_users_secret_key") {
|
||||
continue;
|
||||
} else {
|
||||
|
|
|
@ -21,7 +21,7 @@ pub mod account;
|
|||
pub mod auth;
|
||||
pub mod mcaptcha;
|
||||
pub mod meta;
|
||||
mod notifications;
|
||||
pub mod notifications;
|
||||
pub mod pow;
|
||||
mod routes;
|
||||
|
||||
|
|
|
@ -63,25 +63,39 @@ pub async fn get_notification(
|
|||
let receiver = id.identity().unwrap();
|
||||
// TODO handle error where payload.to doesnt exist
|
||||
|
||||
let mut notifications = sqlx::query_file_as!(
|
||||
Notification,
|
||||
"src/api/v1/notifications/get_all_unread.sql",
|
||||
&receiver
|
||||
)
|
||||
.fetch_all(&data.db)
|
||||
.await?;
|
||||
|
||||
let resp: Vec<NotificationResp> = notifications
|
||||
.drain(0..)
|
||||
.map(|x| {
|
||||
let y: NotificationResp = x.into();
|
||||
y
|
||||
})
|
||||
.collect();
|
||||
let resp = runner::get_notification(&data, &receiver).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(resp))
|
||||
}
|
||||
|
||||
pub mod runner {
|
||||
use super::*;
|
||||
pub async fn get_notification(
|
||||
data: &AppData,
|
||||
receiver: &str,
|
||||
) -> ServiceResult<Vec<NotificationResp>> {
|
||||
// TODO handle error where payload.to doesnt exist
|
||||
|
||||
let mut notifications = sqlx::query_file_as!(
|
||||
Notification,
|
||||
"src/api/v1/notifications/get_all_unread.sql",
|
||||
&receiver
|
||||
)
|
||||
.fetch_all(&data.db)
|
||||
.await?;
|
||||
|
||||
let resp = notifications
|
||||
.drain(0..)
|
||||
.map(|x| {
|
||||
let y: NotificationResp = x.into();
|
||||
y
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(resp)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use actix_web::http::{header, StatusCode};
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
mod add;
|
||||
mod get;
|
||||
mod mark_read;
|
||||
pub mod add;
|
||||
pub mod get;
|
||||
pub mod mark_read;
|
||||
|
||||
pub mod routes {
|
||||
|
||||
|
|
|
@ -44,11 +44,9 @@ async fn auth_works() {
|
|||
confirm_password: PASSWORD.into(),
|
||||
email: None,
|
||||
};
|
||||
let resp = test::call_service(
|
||||
&app,
|
||||
post_request!(&msg, ROUTES.auth.register).to_request(),
|
||||
)
|
||||
.await;
|
||||
let resp =
|
||||
test::call_service(&app, post_request!(&msg, ROUTES.auth.register).to_request())
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
// delete user
|
||||
delete_user(NAME, &data).await;
|
||||
|
|
14
src/data.rs
14
src/data.rs
|
@ -143,17 +143,19 @@ pub struct Data {
|
|||
}
|
||||
|
||||
impl Data {
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
/// create new instance of app data
|
||||
pub async fn new() -> Arc<Self> {
|
||||
let creds = ConfigBuilder::default()
|
||||
pub fn get_creds() -> Config {
|
||||
ConfigBuilder::default()
|
||||
.username_case_mapped(true)
|
||||
.profanity(true)
|
||||
.blacklist(true)
|
||||
.password_policy(PasswordPolicy::default())
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
.unwrap()
|
||||
}
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
/// create new instance of app data
|
||||
pub async fn new() -> Arc<Self> {
|
||||
let creds = Self::get_creds();
|
||||
let c = creds.clone();
|
||||
|
||||
let init = thread::spawn(move || {
|
||||
|
|
|
@ -123,11 +123,9 @@ mod tests {
|
|||
|
||||
let uri = format!("{}{}", DOCS.home, FILE);
|
||||
|
||||
let resp = test::call_service(
|
||||
&app,
|
||||
test::TestRequest::get().uri(&uri).to_request(),
|
||||
)
|
||||
.await;
|
||||
let resp =
|
||||
test::call_service(&app, test::TestRequest::get().uri(&uri).to_request())
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,14 +60,13 @@ mod tests {
|
|||
PAGES.home,
|
||||
PAGES.panel.sitekey.add,
|
||||
PAGES.panel.sitekey.list,
|
||||
PAGES.panel.notifications,
|
||||
];
|
||||
|
||||
for url in urls.iter() {
|
||||
let resp = test::call_service(
|
||||
&app,
|
||||
test::TestRequest::get().uri(url).to_request(),
|
||||
)
|
||||
.await;
|
||||
let resp =
|
||||
test::call_service(&app, test::TestRequest::get().uri(url).to_request())
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::FOUND);
|
||||
|
||||
let authenticated_resp = test::call_service(
|
||||
|
@ -91,11 +90,9 @@ mod tests {
|
|||
let urls = vec![PAGES.auth.login, PAGES.auth.join];
|
||||
|
||||
for url in urls.iter() {
|
||||
let resp = test::call_service(
|
||||
&app,
|
||||
test::TestRequest::get().uri(url).to_request(),
|
||||
)
|
||||
.await;
|
||||
let resp =
|
||||
test::call_service(&app, test::TestRequest::get().uri(url).to_request())
|
||||
.await;
|
||||
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use actix_identity::Identity;
|
|||
use actix_web::{HttpResponse, Responder};
|
||||
use sailfish::TemplateOnce;
|
||||
|
||||
mod notifications;
|
||||
pub mod sitekey;
|
||||
|
||||
use crate::errors::PageResult;
|
||||
|
@ -51,6 +52,7 @@ async fn panel(data: AppData, id: Identity) -> PageResult<impl Responder> {
|
|||
pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
|
||||
cfg.service(panel);
|
||||
sitekey::services(cfg);
|
||||
cfg.service(notifications::notifications);
|
||||
}
|
||||
|
||||
pub mod routes {
|
||||
|
@ -58,6 +60,7 @@ pub mod routes {
|
|||
pub struct Panel {
|
||||
pub home: &'static str,
|
||||
pub sitekey: Sitekey,
|
||||
pub notifications: &'static str,
|
||||
}
|
||||
|
||||
impl Panel {
|
||||
|
@ -65,6 +68,7 @@ pub mod routes {
|
|||
Panel {
|
||||
home: "/",
|
||||
sitekey: Sitekey::new(),
|
||||
notifications: "/notifications",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
52
src/pages/panel/notifications.rs
Normal file
52
src/pages/panel/notifications.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use actix_identity::Identity;
|
||||
use actix_web::{HttpResponse, Responder};
|
||||
use sailfish::TemplateOnce;
|
||||
|
||||
use crate::api::v1::notifications::get::{runner, NotificationResp};
|
||||
use crate::errors::PageResult;
|
||||
use crate::AppData;
|
||||
|
||||
#[derive(TemplateOnce)]
|
||||
#[template(path = "panel/notifications/index.html")]
|
||||
pub struct IndexPage {
|
||||
/// notifications
|
||||
n: Vec<NotificationResp>,
|
||||
}
|
||||
|
||||
impl IndexPage {
|
||||
fn new(n: Vec<NotificationResp>) -> Self {
|
||||
IndexPage { n }
|
||||
}
|
||||
}
|
||||
|
||||
const PAGE: &str = "Notifications";
|
||||
|
||||
#[my_codegen::get(path = "crate::PAGES.panel.notifications", wrap = "crate::CheckLogin")]
|
||||
pub async fn notifications(data: AppData, id: Identity) -> PageResult<impl Responder> {
|
||||
let receiver = id.identity().unwrap();
|
||||
// TODO handle error where payload.to doesnt exist
|
||||
|
||||
let notifications = runner::get_notification(&data, &receiver).await?;
|
||||
|
||||
let body = IndexPage::new(notifications).render_once().unwrap();
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("text/html; charset=utf-8")
|
||||
.body(body))
|
||||
}
|
|
@ -51,11 +51,9 @@ macro_rules! post_request {
|
|||
#[macro_export]
|
||||
macro_rules! get_works {
|
||||
($app:expr,$route:expr ) => {
|
||||
let list_sitekey_resp = test::call_service(
|
||||
&$app,
|
||||
test::TestRequest::get().uri($route).to_request(),
|
||||
)
|
||||
.await;
|
||||
let list_sitekey_resp =
|
||||
test::call_service(&$app, test::TestRequest::get().uri($route).to_request())
|
||||
.await;
|
||||
assert_eq!(list_sitekey_resp.status(), StatusCode::OK);
|
||||
};
|
||||
}
|
||||
|
@ -116,11 +114,9 @@ pub async fn register(name: &str, email: &str, password: &str) {
|
|||
confirm_password: password.into(),
|
||||
email: Some(email.into()),
|
||||
};
|
||||
let resp = test::call_service(
|
||||
&app,
|
||||
post_request!(&msg, ROUTES.auth.register).to_request(),
|
||||
)
|
||||
.await;
|
||||
let resp =
|
||||
test::call_service(&app, post_request!(&msg, ROUTES.auth.register).to_request())
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
|
@ -134,11 +130,9 @@ pub async fn signin(name: &str, password: &str) -> (Arc<Data>, Login, ServiceRes
|
|||
login: name.into(),
|
||||
password: password.into(),
|
||||
};
|
||||
let signin_resp = test::call_service(
|
||||
&app,
|
||||
post_request!(&creds, ROUTES.auth.login).to_request(),
|
||||
)
|
||||
.await;
|
||||
let signin_resp =
|
||||
test::call_service(&app, post_request!(&creds, ROUTES.auth.login).to_request())
|
||||
.await;
|
||||
assert_eq!(signin_resp.status(), StatusCode::OK);
|
||||
(data, creds, signin_resp)
|
||||
}
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
</li>
|
||||
|
||||
<li class="taskbar__action">
|
||||
<a href="<.= crate::PAGES.panel.notifications .>">
|
||||
<img class="taskbar__icon" src="<.=
|
||||
crate::FILES.get("./static/cache/img/svg/bell.svg").unwrap() .>"
|
||||
alt="Notifications" />
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="taskbar__action">
|
||||
|
|
24
templates/panel/notifications/index.html
Normal file
24
templates/panel/notifications/index.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<. include!("../../components/headers/index.html"); .>
|
||||
<. include!("../navbar/index.html"); .>
|
||||
<div class="tmp-layout">
|
||||
<. include!("../header/index.html"); .>
|
||||
|
||||
<main class="panel-main">
|
||||
<!-- Main content container -->
|
||||
<div class="inner-container">
|
||||
<!-- Main menu/ important actions roaster -->
|
||||
|
||||
<ul class="sitekey-list__box">
|
||||
<h1 class="sitekey-list__title">Your Notifications</h1>
|
||||
<. for notification in n.iter() { .>
|
||||
<li class="sitekey-list__item">
|
||||
<h3><.= notification.heading .> </h3>
|
||||
<p>From: <.= notification.name .> </p>
|
||||
<p>Received: <.= notification.received .> </p>
|
||||
<p>Message: <.= notification.message .> </p>
|
||||
<. } .>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<!-- end of container -->
|
||||
<. include!("../../components/footers.html"); .>
|
Loading…
Reference in a new issue