Files
shd.build/src/routes/isac/contributor-guidelines/+page.server.ts
T
jb dd84dff055
Validate and deploy production / validate (push) Successful in 23s
Validate and deploy staging / validate (push) Successful in 50s
Validate and deploy production / deploy (push) Failing after 40s
Validate and deploy staging / deploy (push) Failing after 7s
feat: add community publishing and news syndication
2026-08-01 21:42:09 -04:00

94 lines
3.5 KiB
TypeScript

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);
},
};