From a0efc6c628bd66c1eaf2ebafaee93205ff84cb83 Mon Sep 17 00:00:00 2001 From: DragonDuck24 Date: Mon, 30 Mar 2026 15:44:11 -0500 Subject: [PATCH] updates --- src/hooks.server.ts | 2 + src/lib/auth/index.server.ts | 10 +- src/lib/components/custom/item-listing.svelte | 30 ++--- src/routes/account/+page.server.ts | 60 ++++++++- src/routes/account/+page.svelte | 120 +++++++++++------- src/routes/items/+page.svelte | 6 +- 6 files changed, 158 insertions(+), 70 deletions(-) diff --git a/src/hooks.server.ts b/src/hooks.server.ts index d232a6d..f7a78cd 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -14,7 +14,9 @@ export const handle = async ({ event, resolve }) => { event.locals.user = null; } else { try { + console.log(jwt.verify(JWT, process.env.JWT_SECRET)); event.locals.user = jwt.verify(JWT, process.env.JWT_SECRET); + // console.log(event.locals.user); } catch { event.cookies.delete('jwt', { path: '/' }); event.locals.user = null; diff --git a/src/lib/auth/index.server.ts b/src/lib/auth/index.server.ts index 78bad42..4be39d5 100644 --- a/src/lib/auth/index.server.ts +++ b/src/lib/auth/index.server.ts @@ -1,4 +1,4 @@ -import type { User, UserPayload } from '$lib/types/user'; +import { DefaultUserSettings, type User, type UserPayload } from '$lib/types/user'; import bcrypt from 'bcrypt'; import sql from '$lib/db/db.server'; import { type Cookies, error } from '@sveltejs/kit'; @@ -9,7 +9,10 @@ export function setJWTCookie(cookies: Cookies, user: User) { const payload = { id: user.id, email: user.email, - name: user.name + name: user.name, + settings: user.settings || DefaultUserSettings, + createdAt: user.createdAt, + lastSignIn: user.lastSignIn }; if (process.env.JWT_SECRET === undefined) { @@ -65,8 +68,7 @@ export async function login(email: string, password: string): Promise { if (await bcrypt.compare(password, user.passwordHash!)) { delete user.passwordHash; - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - sql` + await sql` UPDATE users SET last_sign_in = NOW() WHERE id = ${user.id}; diff --git a/src/lib/components/custom/item-listing.svelte b/src/lib/components/custom/item-listing.svelte index 880c162..17059b9 100644 --- a/src/lib/components/custom/item-listing.svelte +++ b/src/lib/components/custom/item-listing.svelte @@ -16,19 +16,21 @@ import { approveDenyItem, restoreClaimedItem } from '$lib/db/items.remote'; import { invalidateAll } from '$app/navigation'; import NoImagePlaceholder from './no-image-placeholder.svelte'; + import type { User } from '$lib/types/user'; export let item: Item = {}; - export let admin = false; + export let user: User | null = null; + // export let admin = false; export let editCallback: (item: Item) => void; export let inquireCallback: (item: Item) => void; export let claimCallback: (item: Item) => void; let timeSincePosted: number | string = (new Date().getTime() - item.foundDate.getTime()) / 1000 / 60 / 60 / 24; // days - if (timeSincePosted < 1) { - timeSincePosted = '<1'; - } else { - timeSincePosted = Math.round(timeSincePosted); - } + // if (timeSincePosted < 1) { + // timeSincePosted = '<1'; + // } else { + // timeSincePosted = Math.round(timeSincePosted); + // } @@ -39,20 +41,14 @@ alt="Lost item"> {:else}
-
-

No image available

{/if}
- - -
- {#if item.transferred} In Lost & Found {:else} @@ -62,8 +58,9 @@ - {timeSincePosted} - day{(timeSincePosted === 1 || timeSincePosted === '<1') ? '' : 's'} ago + {timeSincePosted < 1 ? "<1" : Math.round(timeSincePosted)} + day{(timeSincePosted <= 1) ? '' : 's'} ago @@ -72,9 +69,7 @@ -
-
{item.description}
{#if item.foundLocation}
@@ -82,8 +77,7 @@
{item.foundLocation}
{/if} - - {#if admin} + {#if user !== null}
{#if item.approvedDate === null} diff --git a/src/routes/account/+page.server.ts b/src/routes/account/+page.server.ts index 0fee0f8..d0c50fd 100644 --- a/src/routes/account/+page.server.ts +++ b/src/routes/account/+page.server.ts @@ -1,6 +1,9 @@ import type { PageServerLoad } from '$types'; import sql from '$lib/db/db.server'; -import type { User } from '$lib/types/user'; +import type { User, UserSettings } from '$lib/types/user'; +import { type Actions, error, fail } from '@sveltejs/kit'; +import { getFormString, getRequiredFormString } from '$lib/shared'; +import bcrypt from 'bcrypt'; export const load: PageServerLoad = async ({ locals }) => { if (!locals || !locals.user) { @@ -15,3 +18,58 @@ export const load: PageServerLoad = async ({ locals }) => { return { userData }; }; + +export const actions: Actions = { + default: async ({ request, url, locals, params }) => { + if (!locals || !locals.user) { + throw error(403, 'Need to be logged in!'); + } + + const data = await request.formData(); + + let name: string; + let email: string; + let newPassword: string | null; + let retypeNewPassword: string | null; + let staleItemDays: number; + let notifyAllApprovedInquiries: boolean; + let notifyAllTurnedInInquiries: boolean; + + try { + name = getRequiredFormString(data, 'name'); + email = getRequiredFormString(data, 'email'); + newPassword = getFormString(data, 'newPassword'); + retypeNewPassword = getFormString(data, 'retypeNewPassword'); + staleItemDays = parseInt(getRequiredFormString(data, 'staleItemDays')); + notifyAllApprovedInquiries = getFormString(data, 'notifyAllApprovedInquiries') == 'on'; + notifyAllTurnedInInquiries = getFormString(data, 'notifyAllTurnedInInquiries') == 'on'; + + if (newPassword !== retypeNewPassword) { + fail(400, { password: 'New passwords dont match!' }); + } + const passwordHash = await bcrypt.hash(newPassword!, 12); + + const settings: UserSettings = { + staleItemDays, + notifyAllApprovedInquiries, + notifyAllTurnedInInquiries + }; + + return await sql` + UPDATE users SET name = ${name}, + email = ${email}, + password_hash = ${passwordHash}, + settings = ${settings.toString()} + WHERE id = ${locals.user.id} + RETURNING *; + `; + } catch (e) { + return fail(400, { + message: e instanceof Error ? e.message : 'Unknown error occurred', + success: false + }); + } + + return { success: true }; + } +} satisfies Actions; diff --git a/src/routes/account/+page.svelte b/src/routes/account/+page.svelte index c72dee1..080b441 100644 --- a/src/routes/account/+page.svelte +++ b/src/routes/account/+page.svelte @@ -17,16 +17,16 @@ window.location.href = '/'; } - let form = $derived({ - name: data.userData.name, - email: data.userData.email, - staleItemDays: - data.userData.settings?.staleItemDays ?? DefaultUserSettings.staleItemDays, - notifyAllApprovedInquiries: - data.userData.settings?.notifyAllApprovedInquiries ?? false, - notifyAllTurnedInInquiries: - data.userData.settings?.notifyAllTurnedInInquiries ?? false - }); + // Use top-level variables for two-way binding. Binding to object properties + // like `form.name` doesn't create proper reactive two-way bindings in Svelte. + let name: string = $state(data.userData.name); + let email: string = $state(data.userData.email); + let staleItemDays: number = + $state(data.userData.settings?.staleItemDays ?? DefaultUserSettings.staleItemDays); + let notifyAllApprovedInquiries: boolean = + $state(data.userData.settings?.notifyAllApprovedInquiries ?? false); + let notifyAllTurnedInInquiries: boolean = + $state(data.userData.settings?.notifyAllTurnedInInquiries ?? false); const formatDate = (date: Date | string) => { const d = new Date(date); @@ -50,6 +50,7 @@
+
@@ -57,64 +58,95 @@
- - + +
- - + +
- - + +
+ +
+ + +
+
-

Notifications

- +

Settings

-
-

Notify All Approved

-

- Receive notifications when inquiries are approved. -

-
- +
+

Stale Item Days

+

+ Number of days without activity before items show up as stale. +

+
+ +
-
-

Notify All Turned In

-

- Receive notifications when inquiries are turned in. -

-
+ + +
+ +
+
- Member since {formatDate(data.userData.createdAt)} ยท Last sign in {formatDate( - data.userData.lastSignIn - )} +

+ + Member since {formatDate(data.userData.createdAt)} +

+

+ + Last sign in {formatDate(data.userData.lastSignIn)} +

@@ -127,4 +159,4 @@ -
\ No newline at end of file +
diff --git a/src/routes/items/+page.svelte b/src/routes/items/+page.svelte index 5b16393..e77a828 100644 --- a/src/routes/items/+page.svelte +++ b/src/routes/items/+page.svelte @@ -86,7 +86,7 @@ {#each data.items as item (item.id)} {#if item.approvedDate === null} - {/if} {/each} @@ -102,7 +102,7 @@ {#each data.items as item (item.id)} {#if item.approvedDate !== null && item.claimedDate === null} - {/if} {/each} @@ -115,7 +115,7 @@ {#each data.items as item (item.id)} {#if item.claimedDate !== null} - {/if} {/each}