sitekey list

This commit is contained in:
realaravinth 2021-05-04 18:34:36 +05:30
parent 3ac95e1005
commit 98719670df
No known key found for this signature in database
GPG key ID: AD9F0F08E855ED88
15 changed files with 230 additions and 49 deletions

View file

@ -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
);

View file

@ -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<Level>,
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;

View file

@ -83,13 +83,15 @@ pub struct MCaptchaID {
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MCaptchaDetails {
pub name: Option<String>,
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<MCaptchaDetails> {
@ -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<Data>, id: Identity) -> ServiceResult<impl Responder> {
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))
}

View file

@ -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;

View file

@ -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<Data>, id: Identity) -> PageResult<impl Responder> {
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<MCaptchaDetails>;
#[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));
}
}

View file

@ -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",
}
}
}

View file

@ -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

View file

@ -24,3 +24,4 @@ $secondary-backdrop: #2b2c30;
$light-grey: rgba(0, 0, 0, 0.125);
$white: #fff;
$form-content-width: 90%;
$black-text: #000;

View file

@ -0,0 +1,40 @@
/*
* 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/>.
*/
@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;
}

View file

@ -1,12 +1,9 @@
<. include!("../components/headers.html"); .>
<main>
<div class="inner-container">
<div class="error-box">
<h1 class="error-title"><.= title .></h1>
<p class="error-message"><.= message .></p>
</div>
<div class="inner-container">
<div class="error-box">
<h1 class="error-title"><.= title .></h1>
<p class="error-message"><.= message .></p>
</div>
<!-- end of container -->
</main>
</div>
<!-- end of container -->
<. include!("../components/footers.html"); .>

View file

@ -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 {

View file

@ -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();

View file

@ -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)}`);

View file

@ -1,5 +1,5 @@
<. include!("../../components/headers.html"); .> <. include!("../header/index.html");
.>
<. include!("../../components/headers.html"); .> <.
include!("../header/index.html"); .>
<main>
<. include!("../taskbar/index.html"); .> <.
@ -7,7 +7,23 @@
<!-- Main content container -->
<div class="inner-container">
<!-- Main menu/ important actions roaster -->
<ul class="sitekey-list__box">
<h1 class="sitekey-list__title">Your Sitekeys</h1>
<. for sitekey in sitekeys.iter() { .>
<a href="/sitekey/<.= sitekey.key .>/view" class="sitekey-list__item-container">
<li class="sitekey-list__item">
<span class="sitekey-list__name">
<.= sitekey.name .>
</span>
<span class="sitekey-list__key">
<.= sitekey.key .>
</span>
</li>
</a>
<. } .>
</ul>
</div>
<!-- end of container -->
</main>

View file

@ -0,0 +1,55 @@
/*
* 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/>.
*/
@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;
}