doc handler uses const and js, I give upT-T

This commit is contained in:
realaravinth 2021-05-04 15:18:07 +05:30
parent 1e1ec187dc
commit f817f49182
No known key found for this signature in database
GPG key ID: AD9F0F08E855ED88
7 changed files with 273 additions and 22 deletions

View file

@ -92,23 +92,29 @@ mod tests {
use crate::*; use crate::*;
#[actix_rt::test] #[actix_rt::test]
async fn docs_work() { async fn docs_works() {
const INDEX: &str = "/docs"; const FILE: &str = "favicon-32x32.png";
const FILE: &str = "/docs/favicon-32x32.png";
const SPEC: &str = "/docs/openapi.json";
let mut app = test::init_service(App::new().configure(services)).await; let mut app = test::init_service(App::new().configure(services)).await;
let resp = let resp = test::call_service(
test::call_service(&mut app, test::TestRequest::get().uri(INDEX).to_request()).await; &mut app,
test::TestRequest::get().uri(DOCS.home).to_request(),
)
.await;
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
let resp = let resp = test::call_service(
test::call_service(&mut app, test::TestRequest::get().uri(FILE).to_request()).await; &mut app,
test::TestRequest::get().uri(DOCS.spec).to_request(),
)
.await;
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
let uri = format!("{}{}", DOCS.home, FILE);
let resp = let resp =
test::call_service(&mut app, test::TestRequest::get().uri(SPEC).to_request()).await; test::call_service(&mut app, test::TestRequest::get().uri(&uri).to_request()).await;
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
} }
} }

View file

@ -1,4 +1,4 @@
<fieldset class="sitekey__level-container"> <fieldset class="sitekey__level-container" id="level-group-<.= level .>">
<legend class="sitekey__level-title"> <legend class="sitekey__level-title">
Level <.= level .> Level <.= level .>
</legend> </legend>

View file

@ -14,9 +14,15 @@
* You should have received a copy of the GNU Affero General Public License * 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/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import getNumLevels from './levels/getNumLevels';
import validateLevel from './levels/validateLevel'; import validateLevel from './levels/validateLevel';
import getNumLevels from './levels/getNumLevels';
import {LEVELS} from './levels/';
import * as UpdateLevel from './levels/updateLevel'; import * as UpdateLevel from './levels/updateLevel';
import {
getRemoveButtonHTML,
addRemoveLevelButtonEventListener,
} from './removeLevelButton';
import CONST from './const';
const ADD_LEVEL_BUTTON = 'sitekey-form__level-add-level-button'; const ADD_LEVEL_BUTTON = 'sitekey-form__level-add-level-button';
@ -27,21 +33,27 @@ const ADD_LEVEL_BUTTON = 'sitekey-form__level-add-level-button';
*/ */
const addLevel = (e: Event) => { const addLevel = (e: Event) => {
const eventTarget = <HTMLElement>e.target; const eventTarget = <HTMLElement>e.target;
const PARENT = <HTMLElement>eventTarget.parentElement; const PARENT = <HTMLLabelElement>eventTarget.parentElement;
const FIELDSET = <HTMLElement>PARENT.parentElement; const FIELDSET = <HTMLElement>PARENT.parentElement;
const numLevels = getNumLevels(); const onScreenLevel = getNumLevels();
const isValid = validateLevel(numLevels); const isValid = validateLevel(onScreenLevel);
console.log(`[addLevelButton] isValid: ${isValid}`); console.log(`[addLevelButton] isValid: ${isValid}`);
if (!isValid) { if (!isValid) {
return console.error('Aborting level addition'); return console.error('Aborting level addition');
} }
PARENT.remove(); eventTarget.remove();
PARENT.innerHTML = getRemoveButtonHTML(onScreenLevel);
PARENT.htmlFor = `${CONST.REMOVE_LEVEL_BUTTON_ID_WITHOUT_LEVEL}${onScreenLevel}`;
//FIELDSET.innerHTML += getRemoveButtonHTML(numLevels);
addRemoveLevelButtonEventListener(onScreenLevel);
const newLevelHTML = getHtml(numLevels + 1); //PARENT.remove();
const newLevelHTML = getHtml(onScreenLevel + 1);
FIELDSET.insertAdjacentHTML('afterend', newLevelHTML); FIELDSET.insertAdjacentHTML('afterend', newLevelHTML);
UpdateLevel.register(numLevels); UpdateLevel.register(onScreenLevel);
addLevelButtonAddEventListener(); addLevelButtonAddEventListener();
}; };
@ -60,8 +72,9 @@ const addLevelButtonAddEventListener = () => {
*/ */
const getHtml = (level: number) => { const getHtml = (level: number) => {
console.debug(`[generating HTML getHtml]level: ${level}`); console.debug(`[generating HTML getHtml]level: ${level}`);
const HTML = ` const HTML = `
<fieldset class="sitekey__level-container"> <fieldset class="sitekey__level-container" id="level-group-${level}">
<legend class="sitekey__level-title"> <legend class="sitekey__level-title">
Level ${level} Level ${level}
</legend> </legend>

View file

@ -16,20 +16,33 @@
*/ */
const LABEL_INNER_TEXT_WITHOUT_LEVEL = 'Level '; const LABEL_INNER_TEXT_WITHOUT_LEVEL = 'Level ';
const LABEL_CLASS = 'sitekey-form__level-label';
const INPUT_ID_WITHOUT_LEVEL = 'level'; const INPUT_ID_WITHOUT_LEVEL = 'level';
const LABEL_CLASS = 'sitekey-form__label'; const LEVEL_INPUT_CLASS = 'sitekey-form__level-input';
const VISITOR_WITHOUT_LEVEL = 'visitor'; const VISITOR_WITHOUT_LEVEL = 'visitor';
const DIFFICULTY_WITHOUT_LEVEL = 'difficulty'; const DIFFICULTY_WITHOUT_LEVEL = 'difficulty';
const LEVEL_CONTAINER_CLASS = "sitekey__level-container";
const LEVEL_CONTAINER_CLASS = 'sitekey__level-container';
const LEVEL_FIELDSET_ID_WITHOUT_LEVEL = 'level-group-';
const LEGEND_CLASS = 'sitekey__level-title';
const REMOVE_LEVEL_BUTTON_ID_WITHOUT_LEVEL = 'remove-level';
const REMOVE_LEVEL_LABEL_TEXT = "Remove Level";
const CONST = { const CONST = {
LABEL_CLASS, LABEL_CLASS,
INPUT_ID_WITHOUT_LEVEL, INPUT_ID_WITHOUT_LEVEL,
LEVEL_INPUT_CLASS,
LABEL_INNER_TEXT_WITHOUT_LEVEL, LABEL_INNER_TEXT_WITHOUT_LEVEL,
VISITOR_WITHOUT_LEVEL, VISITOR_WITHOUT_LEVEL,
DIFFICULTY_WITHOUT_LEVEL, DIFFICULTY_WITHOUT_LEVEL,
LEVEL_CONTAINER_CLASS, LEVEL_CONTAINER_CLASS,
} LEVEL_FIELDSET_ID_WITHOUT_LEVEL,
LEGEND_CLASS,
REMOVE_LEVEL_BUTTON_ID_WITHOUT_LEVEL,
REMOVE_LEVEL_LABEL_TEXT,
};
export default CONST; export default CONST;

View file

@ -1,4 +1,4 @@
<fieldset class="sitekey__level-container"> <fieldset class="sitekey__level-container" id="level-group-<.= level .>">
<legend class="sitekey__level-title"> <legend class="sitekey__level-title">
Level <.= level .> Level <.= level .>
</legend> </legend>

View file

@ -15,6 +15,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import getNumLevels from './getNumLevels';
/** Datatype represenging an mCaptcha level */ /** Datatype represenging an mCaptcha level */
export type Level = { export type Level = {
difficulty_factor: number; difficulty_factor: number;
@ -24,9 +26,13 @@ export type Level = {
/** Datatype representing a collection of mCaptcha levels */ /** Datatype representing a collection of mCaptcha levels */
class Levels { class Levels {
levels: Array<Level>; levels: Array<Level>;
numOnScreen: number;
numRecoreded: number;
constructor() { constructor() {
this.levels = []; this.levels = [];
this.numRecoreded = 0;
this.numOnScreen = getNumLevels();
} }
add = (newLevel: Level) => { add = (newLevel: Level) => {
@ -66,6 +72,8 @@ class Levels {
throw new Error(msg); throw new Error(msg);
} else { } else {
this.levels.push(newLevel); this.levels.push(newLevel);
this.numOnScreen += 1;
this.numRecoreded += 1;
} }
}; };
@ -79,6 +87,16 @@ export const LEVELS = (function() {
return { return {
/** get levels */ /** get levels */
getLevels: () => levels.get(), getLevels: () => levels.get(),
/**
* get levels displayed on screen.
* This includes the one with add level button
* */
getOnScreen: () => levels.numOnScreen,
/**
* get levels recorded using LEVELS
* This excludes the one with add level button
* */
getRecored: () => levels.numRecoreded,
/** add new level */ /** add new level */
add: (newLevel: Level) => levels.add(newLevel), add: (newLevel: Level) => levels.add(newLevel),
@ -96,6 +114,47 @@ export const LEVELS = (function() {
tmpLevel.add(levels.levels[i]); tmpLevel.add(levels.levels[i]);
} }
} }
levels.levels = tmpLevel.levels;
console.log(`post update:`);
LEVELS.print();
return true;
} catch (e) {
console.log(e);
return false;
}
},
print: () =>
levels.levels.forEach(level =>
console.debug(
`difficulty_factor: ${level.difficulty_factor} visitor ${level.visitor_threshold}`,
),
),
/** remove level */
remove: (id: number) => {
console.debug(`[LEVELS] received order to remove ${id} element`);
const tmpLevel = new Levels();
id -= 1;
try {
for (let i = 0; i < levels.levels.length; i++) {
if (id != i) {
tmpLevel.add(levels.levels[i]);
} else {
console.debug(`[LEVELS] removing ${i} element`);
const rmElement = levels.levels[i];
console.debug(
`[LEVELS] removing element:
difficulty_factor: ${rmElement.difficulty_factor}
visitor_threshold: ${rmElement.visitor_threshold}`,
);
}
}
levels.levels = tmpLevel.levels;
console.debug('Post remove:');
LEVELS.print();
return true; return true;
} catch (e) { } catch (e) {
console.log(e); console.log(e);

View file

@ -0,0 +1,160 @@
/*
* 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 {LEVELS} from './levels/index';
import getNumLevels from './levels/getNumLevels';
import CONST from './const';
const REMOVE_LEVEL_BUTTON = 'sitekey-form__level-remove-level-button';
/**
* Gets executed when 'Remove' Button is clicked to remove levels
*/
const removeLevel = (e: Event) => {
const eventTarget = <HTMLElement>e.target;
const PARENT = <HTMLElement>eventTarget.parentElement;
const FIELDSET = <HTMLElement>PARENT.parentElement;
const levelNum = parseInt(
eventTarget.id.slice(CONST.REMOVE_LEVEL_BUTTON_ID_WITHOUT_LEVEL.length),
);
if (Number.isNaN(levelNum)) {
const msg =
'[removeLevelButton.ts] error in parsing level number from remove button ID';
//console.error(msg);
throw new Error(msg);
}
updateLevelNumbersOnDOM(levelNum);
LEVELS.remove(levelNum);
FIELDSET.remove();
};
/** update level number on fieldset legends and their ids too */
const updateLevelNumbersOnDOM = (id: number) => {
const numLevels = getNumLevels();
if (id + 1 == numLevels) {
// this is the first elemet so have to remove fist element
// and downgrade the add thingy
}
// since I'm doing id+1, I have to remove id after I'm done
// with inclreasing level numbers
for (let i = id+1; i <= numLevels; i++) {
const newLevel = i-1;
const levelGroup = document.querySelector(
`#${CONST.LEVEL_FIELDSET_ID_WITHOUT_LEVEL}${i}`,
);
if (levelGroup === null) {
const msg = `[removeLevelButton.ts]:
error when trying to fetch level group field set ${i}. got null`;
//console.error(msg);
throw new Error(msg);
}
// rename legend
levelGroup.getElementsByTagName(
'legend',
)[0].innerText = `Level ${newLevel}`;
// rename labels
const labels = <NodeListOf<HTMLLabelElement>>(
levelGroup.querySelectorAll(`.${CONST.LABEL_CLASS}`)
);
//console.log(labels);
labels.forEach(label => {
//console.log(`${label.htmlFor}`);
if (label.htmlFor.includes(CONST.VISITOR_WITHOUT_LEVEL)) {
label.htmlFor = `${CONST.VISITOR_WITHOUT_LEVEL}${newLevel}`;
}
if (label.htmlFor.includes(CONST.DIFFICULTY_WITHOUT_LEVEL)) {
label.htmlFor = `${CONST.DIFFICULTY_WITHOUT_LEVEL}${newLevel}`;
}
});
// rename inputs
const inputs = <NodeListOf<HTMLInputElement>>(
levelGroup.querySelectorAll(`.${CONST.LEVEL_INPUT_CLASS}`)
);
//console.log(inputs);
inputs.forEach(input => {
if (input.id.includes(CONST.VISITOR_WITHOUT_LEVEL)) {
//console.log(`${input.id}`);
//console.log('changing visitor_threshold input');
input.id = `${CONST.VISITOR_WITHOUT_LEVEL}${newLevel}`;
}
if (input.id.includes(CONST.DIFFICULTY_WITHOUT_LEVEL)) {
//console.log('changing difficulty input');
input.id = `${CONST.DIFFICULTY_WITHOUT_LEVEL}${newLevel}`;
}
});
levelGroup.id = `${CONST.LEVEL_FIELDSET_ID_WITHOUT_LEVEL}${newLevel}`;
/* TODO
* change field set ID
* change legend inner Text
* change visitor lable for value
* change visitor input id
* change difficulty for value
* change difficulty input id
*/
}
};
/** adds onclick event listener */
export const addRemoveLevelButtonEventListener = (level: number) => {
const removeButton = <HTMLElement>(
document.querySelector(
`#${CONST.REMOVE_LEVEL_BUTTON_ID_WITHOUT_LEVEL}${level}`,
)
);
removeButton.addEventListener('click', removeLevel);
};
/** adds onclick event listener to all remove buttons */
export const addRemoveLevelButtonEventListenerAll = () => {
const removeButtons = document.querySelectorAll(`.${REMOVE_LEVEL_BUTTON}`);
removeButtons.forEach(button =>
button.addEventListener('click', removeLevel),
);
};
/**
* Generate Remove button HTML. On-click handler should be added
* seprately
*/
export const getRemoveButtonHTML = (level: number) => {
//console.debug(`[generating HTML getHtml]level: ${level}`);
const HTML = `
${CONST.REMOVE_LEVEL_LABEL_TEXT}
<input
class="sitekey-form__level-remove-level-button"
type="button"
name="${CONST.REMOVE_LEVEL_BUTTON_ID_WITHOUT_LEVEL}${level}"
id="${CONST.REMOVE_LEVEL_BUTTON_ID_WITHOUT_LEVEL}${level}"
value="x"
/>
</fieldset>
`;
return HTML;
};