SPB Git
2.3 KB · 16 lines typescript
1import { z } from "zod";2import { eq } from "drizzle-orm";3import { db, schema, sql } from "@/db";4import { requireUser, jsonError } from "@/lib/auth/guard";5import { audit } from "@/lib/audit";6const body = z.object({ slug: z.string().regex(/^[a-z0-9-]+$/), title: z.string().min(3).max(120), description: z.string().min(10).max(2000), published: z.boolean().default(false), items: z.array(z.object({ tool: z.string(), blurb: z.string().max(400).optional() })).default([]) });7export async function GET() { try { await requireUser(); const cols = await sql`SELECT c.*, (SELECT coalesce(jsonb_agg(jsonb_build_object('tool', t.slug, 'blurb', ci.blurb) ORDER BY ci.position), '[]') FROM collection_items ci JOIN tools t ON t.id=ci.tool_id WHERE ci.collection_id=c.id) AS items FROM collections c ORDER BY c.sort_order, c.title`; return Response.json(cols); } catch (e) { return jsonError(e); } }8export async function POST(req: Request) {9  try { const s = await requireUser(req); const b = body.parse(await req.json());10    const [c] = await db.insert(schema.collections).values({ slug: b.slug, title: b.title, description: b.description, published: b.published }).onConflictDoUpdate({ target: schema.collections.slug, set: { title: b.title, description: b.description, published: b.published, updatedAt: new Date() } }).returning({ id: schema.collections.id });11    await db.delete(schema.collectionItems).where(eq(schema.collectionItems.collectionId, c.id));12    for (const [i, it] of b.items.entries()) { const [t] = await db.select({ id: schema.tools.id }).from(schema.tools).where(eq(schema.tools.slug, it.tool)); if (t) await db.insert(schema.collectionItems).values({ collectionId: c.id, toolId: t.id, position: i, blurb: it.blurb ?? null }); }13    await audit({ id: s.id, name: s.email }, "collection.save", { type: "collection", id: c.id }, { slug: b.slug }); return Response.json({ ok: true, id: c.id }); } catch (e) { return jsonError(e); }14}15export async function DELETE(req: Request) { try { const s = await requireUser(req); const { slug } = await req.json(); await db.delete(schema.collections).where(eq(schema.collections.slug, String(slug))); await audit({ id: s.id, name: s.email }, "collection.delete", undefined, { slug }); return Response.json({ ok: true }); } catch (e) { return jsonError(e); } }16
Files · main
Menu

Theme