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/`,