import { requireAdmin } from '#lib/server/authorization.js'; import { uniqueListSlug } from '#lib/server/slugify.js'; import { listImageUrl } from '#lib/server/r2.js'; import { createList, listSummaries } from '#lib/server/lists.js'; import { listTables, type TableSummary } from '#lib/server/data-editor.js'; import { isOwner } from '#lib/server/owner.js'; import { fail, redirect } from '@sveltejs/kit'; import type { Actions, PageServerLoad } from './$types'; export const load: PageServerLoad = async (event) => { const owner = isOwner(event); // The database browser (every schema/table) is only ever loaded for the owner. const [lists, tables] = await Promise.all([ listSummaries(), owner ? listTables() : Promise.resolve([] as TableSummary[]) ]); if (owner) event.setHeaders({ 'cache-control': 'private, no-store' }); return { lists, tables }; }; export const actions: Actions = { newList: async (event) => { requireAdmin(event); const form = await event.request.formData(); const name = String(form.get('name') ?? '').trim(); const type = String(form.get('type') ?? ''); const pictureKey = String(form.get('pictureKey') ?? '').trim(); const picture = form.get('picture'); if (!name || name.length > 200) return fail(400, { message: 'Enter a list name of 1–200 characters.' }); if (type !== 'normal' && type !== 'progress') return fail(400, { message: 'Choose a list type.' }); if (picture instanceof File && picture.size > 0) return fail(400, { message: 'Enable JavaScript to upload an image.' }); const pictureUrl = pictureKey ? listImageUrl(pictureKey) : null; if (pictureKey && !pictureUrl) return fail(400, { message: 'Invalid uploaded picture.' }); // meta.tables.slug allows at most 63 characters const slug = (await uniqueListSlug(name.slice(0, 60))).slice(0, 63).replace(/-+$/, ''); await createList({ slug, name, isProgress: type === 'progress', pictureUrl }); redirect(303, `/lists/${slug}`); } };