import { fail, redirect } from '@sveltejs/kit'; import { randomUUID } from 'node:crypto'; import { getSessionUser } from '$lib/server/auth/session'; import { getPermissions } from '$lib/server/auth/authorization'; import { getDatabase } from '$lib/server/database'; import { CONTRIBUTOR_GUIDELINES_VERSION, getContributorMode, } from '$lib/server/contributor-mode'; import { recordIsacAudit } from '$lib/server/audit'; import type { Actions, PageServerLoad } from './$types'; const safeReturn = (value: FormDataEntryValue | null) => { const path = String(value ?? '/isac/attributes'); return path.startsWith('/isac/') && !path.startsWith('//') ? path : '/isac/attributes'; }; export const load: PageServerLoad = async ({ cookies, url }) => { const user = await getSessionUser(cookies); if (!user) redirect(303, '/sign-in'); const permissions = await getPermissions(user); const eligible = permissions.includes('*') || permissions.includes('data.propose'); if (!eligible) redirect(303, '/isac/attributes'); return { contributorMode: await getContributorMode(user.id), returnTo: safeReturn(url.searchParams.get('returnTo')), }; }; export const actions: Actions = { enable: async ({ cookies, request }) => { const user = await getSessionUser(cookies); if (!user) redirect(303, '/sign-in'); const permissions = await getPermissions(user); if (!permissions.includes('*') && !permissions.includes('data.propose')) return fail(403, { contributorError: 'This account is not eligible to contribute data.', }); const form = await request.formData(); if (form.get('acceptGuidelines') !== 'on') return fail(400, { contributorError: 'Accept the contributor guidelines to enable contributor mode.', }); const returnTo = safeReturn(form.get('returnTo')); const database = await getDatabase(); const before = await getContributorMode(user.id); const now = new Date().toISOString(); await ( await database.prepare(`INSERT INTO contributor_agreements(user_id,guidelines_version,accepted_at,enabled,enabled_at,disabled_at) VALUES(?,?,?,1,?,NULL) ON CONFLICT(user_id) DO UPDATE SET guidelines_version=excluded.guidelines_version,accepted_at=excluded.accepted_at, enabled=1,enabled_at=excluded.enabled_at,disabled_at=NULL`) ).run(user.id, CONTRIBUTOR_GUIDELINES_VERSION, now, now); await recordIsacAudit({ actorId: user.id, category: 'data_moderation', action: before.accepted ? 'contributor.enabled' : 'contributor.guidelines_accepted', entityId: user.id, before, after: await getContributorMode(user.id), }); redirect(303, returnTo); }, disable: async ({ cookies, request }) => { const user = await getSessionUser(cookies); if (!user) redirect(303, '/sign-in'); const returnTo = safeReturn((await request.formData()).get('returnTo')); const database = await getDatabase(); const before = await getContributorMode(user.id); if (before.enabled) { await ( await database.prepare( 'UPDATE contributor_agreements SET enabled=0,disabled_at=? WHERE user_id=?', ) ).run(new Date().toISOString(), user.id); await recordIsacAudit({ actorId: user.id, category: 'data_moderation', action: 'contributor.disabled', entityId: user.id, before, after: await getContributorMode(user.id), }); } redirect(303, returnTo); }, };