feat: per-user visibility (own/shared), anonymous generations, private sessions (generate+forget), NSFW model gating

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNQ8ghPfzAfsyVYd6HgFb6
This commit is contained in:
tillandClaude Opus 4.8 committed 2026-07-23 21:46:47 +00:00
1 parent 2588a54eb7
commit e6b325eb53
14 files changed
+186 -35

No files matched your search

+10 -2
View File
@@ -7,17 +7,25 @@ const json = (b: unknown, s = 200) =>
new Response(JSON.stringify(b), { status: s, headers: { 'Content-Type': 'application/json' } });
export const GET: APIRoute = async () => {
const users = await query('SELECT id, username, role, display_name, created_at FROM users ORDER BY username');
const users = await query('SELECT id, username, role, display_name, private_forced, created_at FROM users ORDER BY username');
return json({ users });
};
// POST: neuen Nutzer anlegen ODER Passwort setzen (bei vorhandenem username/id).
// POST: neuen Nutzer anlegen ODER Passwort/Attribute setzen (bei vorhandenem username/id).
export const POST: APIRoute = async ({ request }) => {
const b = await request.json();
if (b.id && b.password) {
await query('UPDATE users SET password_hash=$2 WHERE id=$1', [b.id, await hashPassword(b.password)]);
return json({ ok: true });
}
if (b.id && 'private_forced' in b) {
await query('UPDATE users SET private_forced=$2 WHERE id=$1', [b.id, !!b.private_forced]);
return json({ ok: true });
}
if (b.id && b.role) {
await query(`UPDATE users SET role=$2 WHERE id=$1`, [b.id, b.role === 'admin' ? 'admin' : 'user']);
return json({ ok: true });
}
if (!b.username || !b.password) return json({ error: 'username + password nötig.' }, 400);
const exists = await one('SELECT id FROM users WHERE username=$1', [b.username.trim()]);
if (exists) return json({ error: 'Benutzername vergeben.' }, 400);