From c780470afe11e4cf872766078e9a0880489cbf02 Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 9 Sep 2023 00:58:02 +0200 Subject: [PATCH] move some settings to server side --- frontend/src/lib/api/entities.ts | 5 +++ frontend/src/lib/api/fetch.ts | 38 ++++++++++++++++---- frontend/src/lib/store.ts | 8 ++++- frontend/src/routes/nav/Navigation.svelte | 40 ++++++++++++++++++--- frontend/src/routes/settings/+page.svelte | 43 +++++++++++++++-------- 5 files changed, 107 insertions(+), 27 deletions(-) diff --git a/frontend/src/lib/api/entities.ts b/frontend/src/lib/api/entities.ts index 1b3a776..79b285a 100644 --- a/frontend/src/lib/api/entities.ts +++ b/frontend/src/lib/api/entities.ts @@ -62,6 +62,11 @@ export interface MeUser extends User { timezone: string | null; } +export interface Settings { + read_changelog: string; + read_settings_notice: string; +} + export interface Field { name: string; entries: FieldEntry[]; diff --git a/frontend/src/lib/api/fetch.ts b/frontend/src/lib/api/fetch.ts index 8448c75..8c74667 100644 --- a/frontend/src/lib/api/fetch.ts +++ b/frontend/src/lib/api/fetch.ts @@ -11,9 +11,16 @@ export async function apiFetch( body, token, headers, - }: { method?: string; body?: any; token?: string; headers?: Record }, + version, + }: { + method?: string; + body?: any; + token?: string; + headers?: Record; + version?: number; + }, ) { - const resp = await fetch(`${PUBLIC_BASE_URL}/api/v1${path}`, { + const resp = await fetch(`${PUBLIC_BASE_URL}/api/v${version || 1}${path}`, { method: method || "GET", headers: { ...(token ? { Authorization: token } : {}), @@ -28,12 +35,18 @@ export async function apiFetch( return data as T; } -export const apiFetchClient = async (path: string, method = "GET", body: any = null) => { +export const apiFetchClient = async ( + path: string, + method = "GET", + body: any = null, + version = 1, +) => { try { const data = await apiFetch(path, { method, body, token: localStorage.getItem("pronouns-token") || undefined, + version, }); return data; } catch (e) { @@ -55,9 +68,16 @@ export async function fastFetch( body, token, headers, - }: { method?: string; body?: any; token?: string; headers?: Record }, + version, + }: { + method?: string; + body?: any; + token?: string; + headers?: Record; + version?: number; + }, ) { - const resp = await fetch(`${PUBLIC_BASE_URL}/api/v1${path}`, { + const resp = await fetch(`${PUBLIC_BASE_URL}/api/v${version || 1}${path}`, { method: method || "GET", headers: { ...(token ? { Authorization: token } : {}), @@ -71,12 +91,18 @@ export async function fastFetch( } /** Fetches the specified path without parsing the response body. */ -export const fastFetchClient = async (path: string, method = "GET", body: any = null) => { +export const fastFetchClient = async ( + path: string, + method = "GET", + body: any = null, + version = 1, +) => { try { await fastFetch(path, { method, body, token: localStorage.getItem("pronouns-token") || undefined, + version, }); } catch (e) { if ((e as APIError).code === ErrorCode.InvalidToken) { diff --git a/frontend/src/lib/store.ts b/frontend/src/lib/store.ts index e00fc30..5c31360 100644 --- a/frontend/src/lib/store.ts +++ b/frontend/src/lib/store.ts @@ -1,7 +1,7 @@ import { writable } from "svelte/store"; import { browser } from "$app/environment"; -import type { MeUser } from "./api/entities"; +import type { MeUser, Settings } from "./api/entities"; const initialUserValue = null; export const userStore = writable(initialUserValue); @@ -13,4 +13,10 @@ const initialThemeValue = browser export const themeStore = writable(initialThemeValue); +const defaultSettingsValue = { + settings: { read_changelog: "0.0.0", read_settings_notice: "0" } as Settings, + current: false, +}; +export const settingsStore = writable(defaultSettingsValue); + export const CURRENT_CHANGELOG = "0.6.0"; diff --git a/frontend/src/routes/nav/Navigation.svelte b/frontend/src/routes/nav/Navigation.svelte index 8052181..39e01bf 100644 --- a/frontend/src/routes/nav/Navigation.svelte +++ b/frontend/src/routes/nav/Navigation.svelte @@ -17,13 +17,14 @@ } from "sveltestrap"; import Logo from "./Logo.svelte"; - import { userStore, themeStore, CURRENT_CHANGELOG } from "$lib/store"; + import { userStore, themeStore, CURRENT_CHANGELOG, settingsStore } from "$lib/store"; import { ErrorCode, type APIError, type MeUser, type Report, type Warning, + type Settings, } from "$lib/api/entities"; import { apiFetch, apiFetchClient } from "$lib/api/fetch"; import { addToast } from "$lib/toast"; @@ -37,14 +38,11 @@ let isAdmin = false; let numReports = 0; let numWarnings = 0; - let changelogRead = "99.99.99"; $: currentUser = $userStore; $: theme = $themeStore; onMount(() => { - changelogRead = localStorage.getItem("changelog-read") || "0.0.0"; - const localUser = localStorage.getItem("pronouns-user"); userStore.set(localUser ? JSON.parse(localUser) : null); @@ -78,6 +76,38 @@ }); } + apiFetchClient("/users/@me/settings", "GET", null, 2) + .then((data) => { + settingsStore.set({ current: true, settings: data }); + }) + .catch((e) => { + console.log("getting user settings:", e); + }); + + // TODO: is there a cleaner way to do this? also, remove this eventually + const oldChangelogRead = localStorage.getItem("changelog-read"); + const oldSettingsNotice = localStorage.getItem("alert-1681976313"); + if (oldChangelogRead || oldSettingsNotice) { + localStorage.removeItem("changelog-read"); + localStorage.removeItem("alert-1681976313"); + + apiFetchClient( + "/users/@me/settings", + "PATCH", + { + read_changelog: oldChangelogRead ? oldChangelogRead : undefined, + read_settings_notice: oldSettingsNotice ? "1681976313" : undefined, + }, + 2, + ) + .then((data) => { + settingsStore.set({ current: true, settings: data }); + }) + .catch((e) => { + console.log("updating user settings:", e); + }); + } + apiFetchClient("/auth/warnings") .then((warnings) => { if (warnings.length !== 0) { @@ -157,7 +187,7 @@ {/if} - {#if changelogRead < CURRENT_CHANGELOG} + {#if $settingsStore.current && $settingsStore.settings.read_changelog < CURRENT_CHANGELOG} Changelog v{CURRENT_CHANGELOG} diff --git a/frontend/src/routes/settings/+page.svelte b/frontend/src/routes/settings/+page.svelte index 163698d..92451e1 100644 --- a/frontend/src/routes/settings/+page.svelte +++ b/frontend/src/routes/settings/+page.svelte @@ -6,12 +6,13 @@ type APIError, MAX_MEMBERS, MAX_FIELDS, + type Settings, } from "$lib/api/entities"; import { apiFetchClient, fastFetchClient } from "$lib/api/fetch"; import { usernameRegex } from "$lib/api/regex"; import ErrorAlert from "$lib/components/ErrorAlert.svelte"; import FallbackImage from "$lib/components/FallbackImage.svelte"; - import { userStore } from "$lib/store"; + import { settingsStore, userStore } from "$lib/store"; import { addToast } from "$lib/toast"; import { Alert, @@ -91,21 +92,36 @@ } }; - const DONATE_ALERT_STORE = "alert-1681976313"; - let donateAlertOpen = false; - const closeDonateAlert = () => { - donateAlertOpen = false; - localStorage.setItem(DONATE_ALERT_STORE, "dismissed"); - }; + const CURRENT_ALERT = "1681976313"; + const closeDonateAlert = async () => { + try { + const settings = await apiFetchClient( + "/users/@me/settings", + "PATCH", + { + read_settings_notice: CURRENT_ALERT, + }, + 2, + ); - onMount(() => { - if (!localStorage.getItem(DONATE_ALERT_STORE)) { - donateAlertOpen = true; + settingsStore.set({ current: true, settings }); + error = null; + } catch (e) { + error = e as APIError; } - }); + }; - +{#if error} + +{/if} + + If you find pronouns.cc useful and have the means, I would really appreciate a donation {/if} - {#if error} - - {/if}