diff --git a/src/data.rs b/src/data.rs index a73e5b33..1a8dbde9 100644 --- a/src/data.rs +++ b/src/data.rs @@ -177,6 +177,7 @@ impl Data { mailer: Self::get_mailer(), }; + #[cfg(not(debug_assertions))] init.join().unwrap(); Arc::new(data) diff --git a/templates/api/v1/routes.ts b/templates/api/v1/routes.ts index 4e8820cc..ff914199 100644 --- a/templates/api/v1/routes.ts +++ b/templates/api/v1/routes.ts @@ -17,48 +17,28 @@ const ROUTES = { registerUser: '/api/v1/signup', - loginUser: '/api/v1/signin', - signoutUser: '/api/v1/signout', - deleteAccount: '/api/v1/account/delete', - usernameExists: '/api/v1/account/username/exists', - emailExists: '/api/v1/account/email/exists', - healthCheck: '/api/v1/meta/health', - buildDetails: '/api/v1/meta/build', - addDomain: '/api/v1/mcaptcha/domain/add', - challengeDomain: '/api/v1/mcaptcha/domain/domain/verify/challenge/get', - proveDomain: '/api/v1/mcaptcha/domain/domain/verify/challenge/prove', - deleteDomain: '/api/v1/mcaptcha/domain/delete', - addToken: '/api/v1/mcaptcha/domain/token/add', - updateTokenKey: '/api/v1/mcaptcha/domain/token/update', - getTokenKey: '/api/v1/mcaptcha/domain/token/get', - deleteToken: '/api/v1/mcaptcha/domain/token/delete', - addTokenLevels: '/api/v1/mcaptcha/domain/token/levels/add', - updateTokenLevels: '/api/v1/mcaptcha/domain/token/levels/update', - deleteTokenLevels: '/api/v1/mcaptcha/domain/token/levels/delete', - getTokenLevels: '/api/v1/mcaptcha/domain/token/levels/get', - getTokenDuration: '/api/v1/mcaptcha/domain/token/token/get', - updateTokenDuration: '/api/v1/mcaptcha/domain/token/token/update', + markNotificationRead: '/api/v1/notifications/read', }; export default ROUTES; diff --git a/templates/index.ts b/templates/index.ts index 8d1db03c..d277fe8c 100644 --- a/templates/index.ts +++ b/templates/index.ts @@ -23,6 +23,7 @@ import * as panel from './panel/ts/index'; import * as addSiteKey from './panel/sitekey/add/ts'; import * as editSitekey from './panel/sitekey/edit/'; import * as listSitekeys from './panel/sitekey/list/ts'; +import * as notidications from './panel/notifications/ts'; import {MODE} from './logger'; import log from './logger'; @@ -50,9 +51,10 @@ const router = new Router(); router.register(VIEWS.panelHome, panel.index); router.register(VIEWS.registerUser, register.index); router.register(VIEWS.loginUser, login.index); +router.register(VIEWS.notifications, notidications.index); router.register(VIEWS.listSitekey, listSitekeys.index); router.register(VIEWS.addSiteKey, addSiteKey.index); -router.register(VIEWS.editSitekey("[A-Z,a-z,0-9]+"), editSitekey.index); +router.register(VIEWS.editSitekey('[A-Z),a-z,0-9]+'), editSitekey.index); try { router.route(); diff --git a/templates/panel/index.html b/templates/panel/index.html index c241c15a..1e363d31 100644 --- a/templates/panel/index.html +++ b/templates/panel/index.html @@ -53,6 +53,7 @@ include!("./navbar/index.html"); .>
+ <. let key = format!("/sitekey/{}", &sitekey.key); .> <. include!("./sitekey/view/__edit-sitekey-icon.html"); .>
diff --git a/templates/panel/notifications/index.html b/templates/panel/notifications/index.html index 0eb2eb6c..e890ca17 100644 --- a/templates/panel/notifications/index.html +++ b/templates/panel/notifications/index.html @@ -14,7 +14,7 @@ include!("../navbar/index.html"); .> <. for notification in n.iter() { .> - +

<.= notification.heading .> @@ -34,6 +34,7 @@ include!("../navbar/index.html"); .> src="<.= crate::FILES .get("./static/cache/img/svg/check.svg") .unwrap() .>" + data-id="<.= notification.id .>" alt="Mark Read" /> diff --git a/templates/panel/notifications/main.scss b/templates/panel/notifications/main.scss index 88c62b44..d9c65ffb 100644 --- a/templates/panel/notifications/main.scss +++ b/templates/panel/notifications/main.scss @@ -35,7 +35,7 @@ } .notification__mark-read-btn:hover { - cursor: grab; + cursor: pointer; background-color: $light-grey; } diff --git a/templates/panel/notifications/ts/index.ts b/templates/panel/notifications/ts/index.ts new file mode 100644 index 00000000..97104ccc --- /dev/null +++ b/templates/panel/notifications/ts/index.ts @@ -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 genJsonPayload from '../../../utils/genJsonPayload'; +import createError from '../../../components/error'; + +import ROUTES from '../../../api/v1/routes'; + +const BTN = document.querySelectorAll('.notification__mark-read-btn'); +const TABLE_BODY = document.querySelector('.notification__body'); + +const notification_record = (id: number) => + TABLE_BODY.querySelector(`#notification__item-${id}`); + +const markRead = async (e: Event) => { + const element = e.target; + + const id = Number.parseInt(element.dataset.id); + + const payload = { + id, + }; + + const res = await fetch(ROUTES.markNotificationRead, genJsonPayload(payload)); + if (res.ok) { + notification_record(id).remove(); + } else { + const err = await res.json(); + createError(err.error); + } +}; + +const addMarkReadEventListenet = () => { + BTN.forEach(btn => { + btn.addEventListener('click', markRead, true); + }); +}; + +export const index = () => { + addMarkReadEventListenet(); +}; diff --git a/templates/panel/sitekey/edit/index.ts b/templates/panel/sitekey/edit/index.ts index 30510ff6..72e7e892 100644 --- a/templates/panel/sitekey/edit/index.ts +++ b/templates/panel/sitekey/edit/index.ts @@ -30,8 +30,7 @@ import createError from '../../../components/error'; import VIEWS from '../../../views/v1/routes'; -const BTN = document.querySelector('.sitekey-form__submit'); -const key = BTN.dataset.sitekey; +const BTN_CLASS = document.querySelector('sitekey-form__submit'); const submit = async (e: Event) => { e.preventDefault(); @@ -44,6 +43,9 @@ const submit = async (e: Event) => { const levels = LEVELS.getLevels(); console.debug(`[form submition]: levels: ${levels}`); + const btn = document.querySelector(`${BTN_CLASS}`); + const key = btn.dataset.sitekey; + const payload = { levels, duration, diff --git a/templates/panel/sitekey/list/index.html b/templates/panel/sitekey/list/index.html index b11dbc30..215204af 100644 --- a/templates/panel/sitekey/list/index.html +++ b/templates/panel/sitekey/list/index.html @@ -44,6 +44,7 @@ include!("../../navbar/index.html"); .>
+ <. let key = format!("/sitekey/{}", &sitekey.key); .> <. include!("../view/__edit-sitekey-icon.html"); .>
diff --git a/templates/panel/sitekey/view/__edit-sitekey-icon.html b/templates/panel/sitekey/view/__edit-sitekey-icon.html index 5f0ab3af..a6123e43 100644 --- a/templates/panel/sitekey/view/__edit-sitekey-icon.html +++ b/templates/panel/sitekey/view/__edit-sitekey-icon.html @@ -1,4 +1,4 @@ - + " alt="Edit sitekey" /> diff --git a/templates/panel/sitekey/view/__form-top.html b/templates/panel/sitekey/view/__form-top.html index cc897bab..466ced91 100644 --- a/templates/panel/sitekey/view/__form-top.html +++ b/templates/panel/sitekey/view/__form-top.html @@ -20,6 +20,7 @@ /> <. if READONLY { .> + <. let key = "."; .> <. include!("./__edit-sitekey-icon.html"); .> <. } .>

diff --git a/templates/router.test.ts b/templates/router.test.ts index a2dfef22..138f1545 100644 --- a/templates/router.test.ts +++ b/templates/router.test.ts @@ -27,7 +27,7 @@ const panelResult = 'hello from panel'; const panelRoute = '/panel'; const panel = () => (result.result = panelResult); -const settingsRoute = '/settings/'; +const settingsRoute = '/sitekey/'; const settingsResult = 'hello from settings'; const settings = () => (result.result = settingsResult); @@ -41,9 +41,9 @@ const emptyUriErr = 'uri is empty'; const unregisteredRouteErr = "Route isn't registered"; const router = new Router(); +router.register(patternRoute, pattern); router.register(panelRoute, panel); router.register(settingsRoute, settings); -router.register(patternRoute, pattern); it('checks if Router works', () => { window.history.pushState({}, '', examplePatternRoute); diff --git a/templates/router.ts b/templates/router.ts index 5251f926..229ccccf 100644 --- a/templates/router.ts +++ b/templates/router.ts @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -/** Removes trailing slashed from URI */ +/** Removes trailing slash from URI */ const normalizeUri = (uri: string) => { uri = uri.trim(); if (uri.length == 0) { @@ -54,7 +54,7 @@ export class Router { register(uri: string, fn: () => void) { uri = normalizeUri(uri); - let pattern = new RegExp(`^${uri}(.*)`); + let pattern = new RegExp(`^${uri}$`); let patterString = pattern.toString(); if ( @@ -83,18 +83,21 @@ export class Router { route() { const path = normalizeUri(window.location.pathname); - let fn: () => void | undefined; + let fn: undefined | (() => void); - this.routes.forEach(route => { - if (path.match(route.pattern)) { - fn = route.fn; + if ( + this.routes.find(route => { + if (path.match(route.pattern)) { + fn = route.fn; + return true; + } + }) + ) { + if (fn === undefined) { + throw new Error("Route isn't registered"); + } else { + return fn(); } - }); - - if (fn === undefined) { - throw new Error("Route isn't registered"); } - - return fn(); } } diff --git a/templates/views/v1/routes.ts b/templates/views/v1/routes.ts index 8fb33d5a..288b5131 100644 --- a/templates/views/v1/routes.ts +++ b/templates/views/v1/routes.ts @@ -21,6 +21,7 @@ const ROUTES = { signoutUser: '/api/v1/signout', panelHome: '/', docsHome: '/docs/', + notifications: '/notifications', listSitekey: '/sitekeys/', viewSitekey: (key: string) => `/sitekey/${key}/`, editSitekey: (key: string) => `/sitekey/${key}/edit/`,