import { Router, Request } from 'express'; import { eq } from 'drizzle-orm'; import { db } from '../db/client'; import { settings, users } from '../db/schema'; import { AuthedRequest } from '../auth'; const router = Router(); // The API shape is unchanged from the single-user days — one flat object with // these keys — but storage is now split (FEATURE_User_Accounts.md): `theme` and // `weight_unit` are per-user preferences on the caller's `users` row, the rest // stay global in the settings table. A NULL user pref falls back to the global // value, so a fresh account inherits the rabbitry-wide defaults until the user // picks their own. Client consumers (ThemeSync, useWeightUnit, Settings page) // are agnostic to the split. const GLOBAL_KEYS = ['rabbitry_name', 'kit_prefix', 'default_breed'] as const; const USER_KEYS = ['theme', 'weight_unit'] as const; const ALLOWED_KEYS = [...GLOBAL_KEYS, ...USER_KEYS] as string[]; function mergedSettings(userId: number): Record { const result: Record = {}; for (const row of db.select().from(settings).all()) { result[row.key] = row.value; } const prefs = db .select({ theme: users.theme, weightUnit: users.weightUnit }) .from(users) .where(eq(users.id, userId)) .get(); if (prefs?.theme != null) result.theme = prefs.theme; if (prefs?.weightUnit != null) result.weight_unit = prefs.weightUnit; return result; } function currentUserId(req: Request): number { return (req as AuthedRequest).user!.id; } router.get('/', (req, res) => { res.json(mergedSettings(currentUserId(req))); }); router.patch('/', (req, res) => { const keys = Object.keys(req.body); const unknownKey = keys.find((key) => !ALLOWED_KEYS.includes(key)); if (unknownKey) { res.status(400).json({ error: `Unknown setting: ${unknownKey}` }); return; } const userId = currentUserId(req); const userPatch: { theme?: string; weightUnit?: string } = {}; if ('theme' in req.body) userPatch.theme = req.body.theme; if ('weight_unit' in req.body) userPatch.weightUnit = req.body.weight_unit; if (Object.keys(userPatch).length > 0) { db.update(users).set(userPatch).where(eq(users.id, userId)).run(); } for (const key of keys) { if ((USER_KEYS as readonly string[]).includes(key)) continue; db.update(settings).set({ value: req.body[key] }).where(eq(settings.key, key)).run(); } res.json(mergedSettings(userId)); }); export default router;