import { fail } from '@sveltejs/kit'; import type { Actions, PageServerLoad } from './$types'; import { createTaxonomy, deleteTaxonomy, getTaxonomy, type TaxonomyKind } from '#lib/server/content.js'; import { getMailConfig } from '#lib/server/config.js'; import { inviteUser, isRole, listOpenInvitations, listUsers, requireBarkeeper, revokeInvitation, setUserLocked, setUserRole, validEmail } from '#lib/server/auth.js'; export const load: PageServerLoad = ({ locals }) => { requireBarkeeper(locals.user); return { taxonomy: getTaxonomy(), users: listUsers(), invitations: listOpenInvitations(), mailTransport: getMailConfig().transport }; }; function actionError(cause: unknown): string { const code = cause instanceof Error ? cause.message : ''; if (code === 'USER_EXISTS') return 'Für diese E-Mail existiert bereits ein Konto.'; if (code === 'SELF_LOCK') return 'Das eigene Konto kann nicht gesperrt werden.'; if (code === 'LAST_BARKEEPER') return 'Mindestens ein aktiver Barkeeper muss erhalten bleiben.'; if (code === 'NOT_FOUND') return 'Der Eintrag wurde nicht gefunden.'; if (code === 'TAXONOMY_EXISTS') return 'Dieser Name ist bereits vorhanden.'; if (code === 'TAXONOMY_IN_USE') return 'Verwendete oder für Vorlagen benötigte Einträge können nicht entfernt werden.'; if (code === 'INVALID_COLOR') return 'Bitte eine gültige Farbe wählen.'; if (code === 'INVALID_TAXONOMY') return 'Bitte einen gültigen Namen eingeben.'; return 'Die Aktion konnte nicht ausgeführt werden.'; } export const actions = { invite: async ({ locals, request }) => { const actor = requireBarkeeper(locals.user); const data = await request.formData(); const email = String(data.get('email') || '').trim(); const role = String(data.get('role') || ''); if (!validEmail(email) || !isRole(role)) { return fail(400, { intent: 'invite', email, error: 'E-Mail und Rolle bitte prüfen.' }); } try { const transport = await inviteUser(actor, email, role); return { intent: 'invite', success: transport === 'local' ? 'Einladung wurde in der lokalen Mail-Outbox abgelegt.' : 'Einladung wurde versandt.' }; } catch (cause) { return fail(400, { intent: 'invite', email, error: actionError(cause) }); } }, role: async ({ locals, request }) => { const actor = requireBarkeeper(locals.user); const data = await request.formData(); const userId = String(data.get('userId') || ''); const role = String(data.get('role') || ''); if (!userId || !isRole(role)) return fail(400, { intent: 'role', error: 'Ungültige Rolle.' }); try { setUserRole(actor, userId, role); return { intent: 'role', success: 'Rolle aktualisiert.' }; } catch (cause) { return fail(400, { intent: 'role', error: actionError(cause) }); } }, lock: async ({ locals, request }) => { const actor = requireBarkeeper(locals.user); const data = await request.formData(); try { setUserLocked(actor, String(data.get('userId') || ''), true); return { intent: 'lock', success: 'Konto gesperrt und bestehende Sitzungen beendet.' }; } catch (cause) { return fail(400, { intent: 'lock', error: actionError(cause) }); } }, unlock: async ({ locals, request }) => { const actor = requireBarkeeper(locals.user); const data = await request.formData(); try { setUserLocked(actor, String(data.get('userId') || ''), false); return { intent: 'unlock', success: 'Konto entsperrt.' }; } catch (cause) { return fail(400, { intent: 'unlock', error: actionError(cause) }); } }, revokeInvitation: async ({ locals, request }) => { const actor = requireBarkeeper(locals.user); const data = await request.formData(); revokeInvitation(actor, String(data.get('invitationId') || '')); return { intent: 'revokeInvitation', success: 'Einladung widerrufen.' }; }, createTaxonomy: async ({ locals, request }) => { requireBarkeeper(locals.user); const data = await request.formData(); const kind = String(data.get('kind') || '') as TaxonomyKind; if (!['category', 'format', 'topic'].includes(kind)) { return fail(400, { intent: 'taxonomy', error: 'Ungültige Taxonomieart.' }); } try { createTaxonomy(kind, String(data.get('name') || ''), String(data.get('color') || '')); return { intent: 'taxonomy', success: 'Eintrag angelegt.' }; } catch (cause) { return fail(400, { intent: 'taxonomy', error: actionError(cause) }); } }, deleteTaxonomy: async ({ locals, request }) => { requireBarkeeper(locals.user); const data = await request.formData(); const kind = String(data.get('kind') || '') as TaxonomyKind; if (!['category', 'format', 'topic'].includes(kind)) { return fail(400, { intent: 'taxonomy', error: 'Ungültige Taxonomieart.' }); } try { deleteTaxonomy(kind, String(data.get('taxonomyId') || '')); return { intent: 'taxonomy', success: 'Eintrag entfernt.' }; } catch (cause) { return fail(400, { intent: 'taxonomy', error: actionError(cause) }); } } } satisfies Actions;