import { db } from '#lib/server/db/index.js'; import { listItemCompletions, lists } from '#lib/server/db/schema/index.js'; import { requireAdmin } from '#lib/server/authorization.js'; import { uniqueListSlug } from '#lib/server/slugify.js'; import { listImageUrl } from '#lib/server/r2.js'; import { eq } from 'drizzle-orm'; import { fail, redirect } from '@sveltejs/kit'; import type { Actions, PageServerLoad } from './$types'; export const load: PageServerLoad = async ({ locals }) => { const rows = await db.query.lists.findMany({ with: { items: { columns: { id: true } } }, orderBy: { id: 'desc' } }); const completed = new Set( locals.user ? ( await db .select({ itemId: listItemCompletions.itemId }) .from(listItemCompletions) .where(eq(listItemCompletions.userId, locals.user.id)) ).map((row) => row.itemId) : [] ); return { lists: rows.map(({ items, ...list }) => ({ ...list, total: items.length, checked: list.isProgress ? items.filter((item) => completed.has(item.id)).length : 0 })) }; }; 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.' }); const slug = await uniqueListSlug(name); await db.insert(lists).values({ name, slug, isProgress: type === 'progress', pictureUrl }); redirect(303, `/lists/${slug}`); } };