From 0c16c027e96529b5fb1a11aeb6f34f661211ff4a Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Fri, 19 Jun 2020 19:12:43 +1200 Subject: [PATCH] Add settings restore link --- src/site/api/settings.js | 33 ++++++++++++++++----- src/site/api/utils/getsettings.js | 4 +-- src/site/html/static/js/settings_message.js | 2 ++ src/site/pug/settings.pug | 5 +++- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/site/api/settings.js b/src/site/api/settings.js index d64e2a3..f9c3c14 100644 --- a/src/site/api/settings.js +++ b/src/site/api/settings.js @@ -8,6 +8,7 @@ const db = require("../../lib/db") module.exports = [ { route: "/settings", methods: ["GET"], code: async ({req, url}) => { + const token = getToken(req) const settings = getSettings(req) // console.log(settings) const csrf = generateCSRF() @@ -19,6 +20,7 @@ module.exports = [ returnURL: url.searchParams.get("referrer") || "/", constants, settings, + token, csrf, status, message @@ -28,7 +30,7 @@ module.exports = [ { route: "/settings/(stay|return)", methods: ["POST"], upload: true, code: async ({req, body, fill, url}) => { const action = fill[0] - const oldToken = getToken(req) + const token = getToken(req) const params = new URLSearchParams(body.toString()) if (!checkCSRF(params.get("csrf"))) { const returnParams = new URLSearchParams() @@ -55,14 +57,17 @@ module.exports = [ prepared[setting.name] = valueCorrectType } // console.log(prepared) - const checkPrepared = db.prepare("SELECT token FROM UserSettings WHERE token = ?") - do { - prepared.token = crypto.randomBytes(16).toString("hex") - } while (checkPrepared.get(prepared.token)) + if (token) { + prepared.token = token + } else { + const checkPrepared = db.prepare("SELECT token FROM UserSettings WHERE token = ?") + do { + prepared.token = crypto.randomBytes(16).toString("hex") + } while (checkPrepared.get(prepared.token)) + } prepared.created = Date.now() const fields = constants.user_settings.map(s => s.name) - db.prepare(`INSERT INTO UserSettings (token, created, ${fields.join(", ")}) VALUES (@token, @created, ${fields.map(f => "@"+f).join(", ")})`).run(prepared) - db.prepare("DELETE FROM UserSettings WHERE token = ?").run(oldToken) + db.prepare(`REPLACE INTO UserSettings (token, created, ${fields.join(", ")}) VALUES (@token, @created, ${fields.map(f => "@"+f).join(", ")})`).run(prepared) const expires = new Date(Date.now() + 4000*24*60*60*1000).toUTCString() let location if (action === "return" && url.searchParams.has("referrer")) { @@ -86,5 +91,19 @@ module.exports = [ content: "Redirecting..." } } + }, + { + route: "/applysettings/([0-9a-f]+)", methods: ["GET"], code: async ({fill}) => { + const expires = new Date(Date.now() + 4000*24*60*60*1000).toUTCString() + return { + statusCode: 302, + headers: { + "Location": "/", + "Set-Cookie": `settings=${fill[0]}; Path=/; Expires=${expires}; SameSite=Lax` + }, + contentType: "text/html; charset=UTF-8", + content: "Settings restored. Redirecting..." + } + } } ] diff --git a/src/site/api/utils/getsettings.js b/src/site/api/utils/getsettings.js index b6b526b..8c7de22 100644 --- a/src/site/api/utils/getsettings.js +++ b/src/site/api/utils/getsettings.js @@ -1,5 +1,5 @@ const crypto = require("crypto") -const {parse} = require("cookie") +const {parse: parseCookie} = require("cookie") const constants = require("../../../lib/constants") const db = require("../../../lib/db") @@ -22,7 +22,7 @@ function addDefaults(input = {}) { function getToken(req) { if (!req.headers.cookie) return null - const cookie = parse(req.headers.cookie) + const cookie = parseCookie(req.headers.cookie) const token = cookie.settings if (token) return token else return null diff --git a/src/site/html/static/js/settings_message.js b/src/site/html/static/js/settings_message.js index 4173217..55eb2f4 100644 --- a/src/site/html/static/js/settings_message.js +++ b/src/site/html/static/js/settings_message.js @@ -4,3 +4,5 @@ if (params.has("status")) { params.delete("message") history.replaceState(null, "", "?" + params.toString()) } + +document.getElementById("restore-link").addEventListener("click", event => event.preventDefault()) diff --git a/src/site/pug/settings.pug b/src/site/pug/settings.pug index 99b3cdd..ce879a0 100644 --- a/src/site/pug/settings.pug +++ b/src/site/pug/settings.pug @@ -30,10 +30,10 @@ html head title Settings | Bibliogram include includes/head + script(src=getStaticURL("html", "/static/js/settings_message.js") type="module") body.settings-page if status && message .status-notice(class=status)= message - script(src=getStaticURL("html", "/static/js/settings_message.js") type="module") main.settings form(action=returnAction method="post" enctype="application/x-www-form-urlencoded") input(type="hidden" name="csrf" value=csrf) @@ -129,6 +129,9 @@ html label.pill(for=thisID tabindex=0 onkeypress=`[" ", "Enter"].includes(event.key) && this.click()`) Label span.fake-checkbox + if token + p You can restore and sync saved settings by #[a(href=`/applysettings/${token}`)#restore-link bookmarking this link.] + .action-container span.home-link-container: a(href=returnURL).home-link ← Return button(type="submit" formaction=stayAction).save-button Save