From 98719670dfd1bd29d8751a277b62f77836a0117e Mon Sep 17 00:00:00 2001 From: realaravinth Date: Tue, 4 May 2021 18:34:36 +0530 Subject: [PATCH] sitekey list --- migrations/20210310122617_mcaptcha_config.sql | 2 +- src/api/v1/mcaptcha/levels.rs | 8 +- src/api/v1/mcaptcha/mcaptcha.rs | 24 ++++-- src/errors.rs | 2 - src/pages/panel/sitekey/list.rs | 79 +++++++++++++++++-- src/pages/panel/sitekey/mod.rs | 4 +- src/tests/mod.rs | 2 + templates/_vars.scss | 1 + templates/components/_box.scss | 40 ++++++++++ templates/errors/index.html | 15 ++-- templates/errors/main.scss | 19 +---- templates/index.ts | 4 +- templates/panel/add-site-key/form.ts | 4 +- templates/panel/site-keys/index.html | 20 ++++- templates/panel/site-keys/main.scss | 55 +++++++++++++ 15 files changed, 230 insertions(+), 49 deletions(-) create mode 100644 templates/components/_box.scss create mode 100644 templates/panel/site-keys/main.scss diff --git a/migrations/20210310122617_mcaptcha_config.sql b/migrations/20210310122617_mcaptcha_config.sql index 9ae6eb34..ba2dc9d6 100644 --- a/migrations/20210310122617_mcaptcha_config.sql +++ b/migrations/20210310122617_mcaptcha_config.sql @@ -2,6 +2,6 @@ CREATE TABLE IF NOT EXISTS mcaptcha_config ( config_id SERIAL PRIMARY KEY NOT NULL, user_id INTEGER NOT NULL references mcaptcha_users(ID) ON DELETE CASCADE, key varchar(100) NOT NULL UNIQUE, - name varchar(100) DEFAULT NULL, + name varchar(100) NOT NULL, duration integer NOT NULL DEFAULT 30 ); diff --git a/src/api/v1/mcaptcha/levels.rs b/src/api/v1/mcaptcha/levels.rs index 5d4ed730..8a2b4666 100644 --- a/src/api/v1/mcaptcha/levels.rs +++ b/src/api/v1/mcaptcha/levels.rs @@ -17,6 +17,7 @@ use actix_identity::Identity; use actix_web::{web, HttpResponse, Responder}; +use log::debug; use m_captcha::{defense::Level, DefenseBuilder}; use serde::{Deserialize, Serialize}; @@ -54,6 +55,7 @@ pub mod routes { pub struct AddLevels { pub levels: Vec, pub duration: u32, + pub description: String, } pub fn services(cfg: &mut web::ServiceConfig) { @@ -104,7 +106,11 @@ async fn add_levels( defense.build()?; - let mcaptcha_config = add_mcaptcha_util(payload.duration, &data, &id).await?; + debug!("creating config"); + let mcaptcha_config = + add_mcaptcha_util(payload.duration, &payload.description, &data, &id).await?; + + debug!("config created"); for level in payload.levels.iter() { let difficulty_factor = level.difficulty_factor as i32; diff --git a/src/api/v1/mcaptcha/mcaptcha.rs b/src/api/v1/mcaptcha/mcaptcha.rs index 905e7b61..7cb8629d 100644 --- a/src/api/v1/mcaptcha/mcaptcha.rs +++ b/src/api/v1/mcaptcha/mcaptcha.rs @@ -83,13 +83,15 @@ pub struct MCaptchaID { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct MCaptchaDetails { - pub name: Option, + pub name: String, pub key: String, } // this should be called from within add levels +#[inline] pub async fn add_mcaptcha_util( duration: u32, + description: &str, data: &Data, id: &Identity, ) -> ServiceResult { @@ -102,12 +104,13 @@ pub async fn add_mcaptcha_util( key = get_random(32); let res = sqlx::query!( - "INSERT INTO mcaptcha_config - (key, user_id, duration) - VALUES ($1, (SELECT ID FROM mcaptcha_users WHERE name = $2), $3)", + "INSERT INTO mcaptcha_config + (key, user_id, duration, name) + VALUES ($1, (SELECT ID FROM mcaptcha_users WHERE name = $2), $3, $4)", &key, &username, - duration as i32 + duration as i32, + description, ) .execute(&data.db) .await; @@ -125,7 +128,10 @@ pub async fn add_mcaptcha_util( Err(e) => Err(e)?, Ok(_) => { - resp = MCaptchaDetails { key, name: None }; + resp = MCaptchaDetails { + key, + name: description.to_owned(), + }; break; } } @@ -133,10 +139,12 @@ pub async fn add_mcaptcha_util( Ok(resp) } -// this should be called from within add levels +// TODO deprecate this async fn add_mcaptcha(data: web::Data, id: Identity) -> ServiceResult { let duration = 30; - let resp = add_mcaptcha_util(duration, &data, &id).await?; + let description = "dummy"; + + let resp = add_mcaptcha_util(duration, description, &data, &id).await?; Ok(HttpResponse::Ok().json(resp)) } diff --git a/src/errors.rs b/src/errors.rs index 51459c07..531ff839 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -24,9 +24,7 @@ use actix_web::{ HttpResponse, }; use argon2_creds::errors::CredsError; -//use awc::error::SendRequestError; use derive_more::{Display, Error}; -use lazy_static::lazy_static; use m_captcha::errors::CaptchaError; use serde::{Deserialize, Serialize}; use url::ParseError; diff --git a/src/pages/panel/sitekey/list.rs b/src/pages/panel/sitekey/list.rs index fe263353..16c26232 100644 --- a/src/pages/panel/sitekey/list.rs +++ b/src/pages/panel/sitekey/list.rs @@ -19,25 +19,92 @@ use actix_identity::Identity; use actix_web::{web, HttpResponse, Responder}; use sailfish::TemplateOnce; -//use crate::api::v1::mcaptcha::mcaptcha::MCaptchaDetails; +use crate::api::v1::mcaptcha::mcaptcha::MCaptchaDetails; use crate::errors::*; use crate::Data; #[derive(TemplateOnce, Clone)] #[template(path = "panel/site-keys/index.html")] -pub struct IndexPage; +pub struct IndexPage { + sitekeys: SiteKeys, +} const PAGE: &str = "SiteKeys"; -impl Default for IndexPage { - fn default() -> Self { - IndexPage +impl IndexPage { + fn new(sitekeys: SiteKeys) -> Self { + IndexPage { sitekeys } } } pub async fn list_sitekeys(data: web::Data, id: Identity) -> PageResult { - let body = IndexPage::default().render_once().unwrap(); + let username = id.identity().unwrap(); + let res = sqlx::query_as!( + MCaptchaDetails, + "SELECT key, name from mcaptcha_config WHERE + user_id = (SELECT ID FROM mcaptcha_users WHERE name = $1) ", + &username, + ) + .fetch_all(&data.db) + .await?; + + let body = IndexPage::new(res).render_once().unwrap(); Ok(HttpResponse::Ok() .content_type("text/html; charset=utf-8") .body(body)) } + +type SiteKeys = Vec; + +#[cfg(test)] +mod test { + use actix_web::http::StatusCode; + use actix_web::test; + use actix_web::web::Bytes; + + use crate::tests::*; + use crate::*; + + #[actix_rt::test] + async fn list_sitekeys_work() { + const NAME: &str = "listsitekeyuser"; + const PASSWORD: &str = "longpassworddomain"; + const EMAIL: &str = "listsitekeyuser@a.com"; + + { + let data = Data::new().await; + delete_user(NAME, &data).await; + } + + register_and_signin(NAME, EMAIL, PASSWORD).await; + let (data, _, signin_resp, key) = add_levels_util(NAME, PASSWORD).await; + let cookies = get_cookie!(signin_resp); + + let mut app = get_app!(data).await; + + let list_sitekey_resp = test::call_service( + &mut app, + test::TestRequest::get() + .uri(PAGES.panel.sitekey.list) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + + assert_eq!(list_sitekey_resp.status(), StatusCode::OK); + + let body: Bytes = test::read_body(list_sitekey_resp).await; + let body = String::from_utf8(body.to_vec()).unwrap(); + + // Bytes::from(key.key) + // .iter() + // .for_each(|e| assert!(body.contains(e))); + // + // Bytes::from(key.name) + // .iter() + // .for_each(|e| assert!(body.contains(e))); + + assert!(body.contains(&key.key)); + assert!(body.contains(&key.name)); + } +} diff --git a/src/pages/panel/sitekey/mod.rs b/src/pages/panel/sitekey/mod.rs index c6e0d8a1..9412c3dc 100644 --- a/src/pages/panel/sitekey/mod.rs +++ b/src/pages/panel/sitekey/mod.rs @@ -22,13 +22,15 @@ pub mod routes { pub struct Sitekey { pub list: &'static str, pub add: &'static str, + pub view: &'static str, } impl Sitekey { pub const fn new() -> Self { Sitekey { - list: "/sitekey", + list: "/sitekey/list", add: "/sitekey/add", + view: "/sitekey/{key}/view", } } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 5318e53b..bb24da84 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -57,6 +57,7 @@ macro_rules! get_app { )) .configure(crate::api::v1::pow::services) .configure(crate::api::v1::services) + .configure(crate::pages::services) .data($data.clone()), ) }; @@ -189,6 +190,7 @@ pub async fn add_levels_util( let add_level = AddLevels { levels: levels.clone(), duration: 30, + description: "dummy".into(), }; // 1. add level diff --git a/templates/_vars.scss b/templates/_vars.scss index d8d2a25b..6359d39a 100644 --- a/templates/_vars.scss +++ b/templates/_vars.scss @@ -24,3 +24,4 @@ $secondary-backdrop: #2b2c30; $light-grey: rgba(0, 0, 0, 0.125); $white: #fff; $form-content-width: 90%; +$black-text: #000; diff --git a/templates/components/_box.scss b/templates/components/_box.scss new file mode 100644 index 00000000..3b82ddb1 --- /dev/null +++ b/templates/components/_box.scss @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * 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 . + */ + +@import '../vars'; + +@mixin box-title { + padding-left: 10px; + font-size: 1rem; + padding: 0.75rem 1.25rem; + box-sizing: border-box; + text-align: left; + width: 100%; + border-bottom: 0.1px solid $light-grey; +} + +@mixin box { + display: flex; + flex-direction: column; + width: 90%; + justify-content: center; + align-items: center; + box-sizing: content-box; + background-color: $white; + margin: auto; + padding-bottom: 30px; +} diff --git a/templates/errors/index.html b/templates/errors/index.html index 59c8752e..b07f95ce 100644 --- a/templates/errors/index.html +++ b/templates/errors/index.html @@ -1,12 +1,9 @@ <. include!("../components/headers.html"); .> -
-
-
-

<.= title .>

-

<.= message .>

-
+
+
+

<.= title .>

+

<.= message .>

- -
- + + <. include!("../components/footers.html"); .> diff --git a/templates/errors/main.scss b/templates/errors/main.scss index d37a5228..12b9b52e 100644 --- a/templates/errors/main.scss +++ b/templates/errors/main.scss @@ -17,27 +17,14 @@ @import '../reset'; @import '../vars'; +@import '../components/box'; .error-box { - display: flex; - flex-direction: column; - width: 90%; - justify-content: center; - align-items: center; - box-sizing: content-box; - background-color: $white; - margin: auto; - padding-bottom: 30px; + @include box; } .error-title { - padding-left: 10px; - font-size: 1rem; - padding: 0.75rem 1.25rem; - box-sizing: border-box; - text-align: left; - width: 100%; - border-bottom: 0.1px solid $light-grey; + @include box-title; } .error-message { diff --git a/templates/index.ts b/templates/index.ts index 346ab079..fb88885b 100644 --- a/templates/index.ts +++ b/templates/index.ts @@ -24,14 +24,14 @@ import * as addSiteKey from './panel/add-site-key/'; import VIEWS from './views/v1/routes'; - import './auth/forms.scss'; import './panel/main.scss'; import './panel/header/sidebar/main.scss'; import './panel/taskbar/main.scss'; import './panel/help-banner/main.scss'; import './panel/add-site-key/main.scss'; - +import './panel/site-keys/main.scss'; +import './errors/main.scss'; const router = new Router(); diff --git a/templates/panel/add-site-key/form.ts b/templates/panel/add-site-key/form.ts index beb69a2a..4a3b9cee 100644 --- a/templates/panel/add-site-key/form.ts +++ b/templates/panel/add-site-key/form.ts @@ -53,6 +53,7 @@ const validateDescription = (e: Event) => { const val = inputElement.value; const filed = 'Description'; isBlankString(val, filed, e); + return val; }; const validateDuration = (e: Event) => { @@ -71,7 +72,7 @@ const validateDuration = (e: Event) => { const submit = async (e: Event) => { e.preventDefault(); - validateDescription(e); + const description = validateDescription(e); const duration = validateDuration(e); const formUrl = getFormUrl(FORM); @@ -82,6 +83,7 @@ const submit = async (e: Event) => { const payload = { levels: levels, duration, + description, }; console.debug(`[form submition] json payload: ${JSON.stringify(payload)}`); diff --git a/templates/panel/site-keys/index.html b/templates/panel/site-keys/index.html index 67c3de62..9cb77482 100644 --- a/templates/panel/site-keys/index.html +++ b/templates/panel/site-keys/index.html @@ -1,5 +1,5 @@ -<. include!("../../components/headers.html"); .> <. include!("../header/index.html"); -.> +<. include!("../../components/headers.html"); .> <. +include!("../header/index.html"); .>
<. include!("../taskbar/index.html"); .> <. @@ -7,7 +7,23 @@
+
diff --git a/templates/panel/site-keys/main.scss b/templates/panel/site-keys/main.scss new file mode 100644 index 00000000..32f7da35 --- /dev/null +++ b/templates/panel/site-keys/main.scss @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * 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 . + */ + +@import '../../reset'; +@import '../../vars'; +@import '../../components/box'; + +.sitekey-list__box { + @include box; + padding-bottom: 0px; +} + +.sitekey-list__title { + @include box-title; +} + +.sitekey-list__item-container { + display: block; + width: 100%; + box-sizing: border-box; + border-bottom: 0.1px solid $light-grey; + padding: 20px; + color: $black-text; +} + +.sitekey-list__item { + display: flex; + width: 100%; +} + +.sitekey-list__item-container:hover { + background-color: $light-grey; +} + +.sitekey-list__name { + flex: 3; +} + +.sitekey-list__key { + flex: 1; +}