Files
portal/src/routes/(protected)/admin/proclamations/+page.server.ts
T
NeilClack 5e8851e070 Fix lint debt from admin overhaul; make check/lint/test/build green
- Scope @typescript-eslint/no-explicit-any off for *.spec.ts test doubles
- Type enhance() submit callbacks with SubmitFunction in api-keys page
- Drop as-any casts in proclamations upsert by using typed form data
- Fix useless regex escapes in profiles phone validation
- Remove unused locals param from api-keys load
- Use resolve() for admin nav/error links; store literal hrefs in adminModels
- Update README admin section and ADMIN_OVERHAUL lint caveat
2026-09-10 09:43:16 -05:00

129 lines
3.6 KiB
TypeScript

import type { PageServerLoad } from './$types';
import { prisma } from '$lib/db';
import { superValidate } from 'sveltekit-superforms/server';
import { zod4 } from 'sveltekit-superforms/adapters';
import { z } from 'zod';
import { superFormErrorsToFieldErrors } from '$lib/superform-errors';
const ProclamationSchema = z.object({
name: z.string().min(1, 'Required'),
solfeggioFrequencyId: z.coerce.number().int(),
categoryId: z.coerce.number().int(),
groupId: z.coerce.number().int(),
content: z.string().optional().default('')
});
function isSuper(locals: App.Locals): boolean {
return ((locals.user as { roleId?: number } | null)?.roleId ?? 4) <= 1;
}
export const load: PageServerLoad = async ({ locals }) => {
const [proclamations, frequencies, categories, groups] = await Promise.all([
prisma.proclamation.findMany({
include: { category: true, group: true, solfeggioFrequency: true },
orderBy: { name: 'asc' }
}),
prisma.solfeggioFrequency.findMany({
select: { id: true, name: true, value: true },
orderBy: { name: 'asc' }
}),
prisma.proclamationCategory.findMany({
select: { id: true, name: true },
orderBy: { name: 'asc' }
}),
prisma.proclamationGroup.findMany({
select: { id: true, name: true },
orderBy: { sortOrder: 'asc' }
})
]);
const records = proclamations as unknown as Record<string, unknown>[];
// Strip content from non-Super users
if (!isSuper(locals)) {
for (const record of records) {
delete record.content;
}
}
return { records, frequencies, categories, groups };
};
export const actions = {
upsert: async ({ request, locals }) => {
if (!locals.user) {
return { success: false, action: 'upsert', error: 'Unauthorized' };
}
if (!isSuper(locals)) {
return {
success: false,
action: 'upsert',
error: 'Only Super admins can edit proclamations'
};
}
const formData = await request.formData();
const form = await superValidate(formData, zod4(ProclamationSchema));
if (!form.valid) {
const { error: formError, fieldErrors } = superFormErrorsToFieldErrors(
form.errors as Record<string, unknown>
);
return { success: false, action: 'upsert', error: formError, fieldErrors };
}
const rawId = formData.get('id')?.toString();
try {
if (rawId) {
const existing = await prisma.proclamation.findUnique({ where: { id: rawId } });
if (!existing) {
return { success: false, action: 'upsert', error: 'Record not found' };
}
await prisma.proclamation.update({ where: { id: rawId }, data: form.data });
} else {
await prisma.proclamation.create({ data: form.data });
}
} catch (e: unknown) {
if (e && typeof e === 'object' && 'code' in e && (e as { code: string }).code === 'P2002') {
return {
success: false,
action: 'upsert',
error: 'A record with this name already exists.'
};
}
throw e;
}
return { success: true, action: 'upsert' };
},
delete: async ({ request, locals }) => {
if (!isSuper(locals)) {
return {
success: false,
action: 'delete',
error: 'Only Super admins can delete proclamations'
};
}
const formData = await request.formData();
const rawId = formData.get('id')?.toString();
if (!rawId) return { success: false, action: 'delete', error: 'Missing id' };
try {
await prisma.proclamation.delete({ where: { id: rawId } });
} catch (e: unknown) {
if (e && typeof e === 'object' && 'code' in e && (e as { code: string }).code === 'P2003') {
return {
success: false,
action: 'delete',
error: 'Cannot delete: this proclamation is assigned to users.'
};
}
throw e;
}
return { success: true, action: 'delete' };
}
};