TypeScript 98.3%
CSS 0.9%
Shell 0.7%
1import { NextResponse } from "next/server";2import { z } from "zod";3import { apiError, parseBody } from "@/lib/api.ts";4import { assertSameOrigin, requireRole } from "@/lib/auth/session.ts";5import { all, run } from "@/lib/db/index.ts";67export async function GET() {8 try {9 await requireRole("instructor");10 return NextResponse.json({ announcements: all("SELECT * FROM announcements ORDER BY id DESC LIMIT 100") });11 } catch (e) {12 return apiError(e);13 }14}1516const createSchema = z.object({17 action: z.literal("create"),18 title: z.string().min(1).max(200),19 body: z.string().min(1).max(10_000),20 courseCode: z.enum(["IMM1003", "IMM1033"]).nullable(),21 pinned: z.boolean().default(false),22});23const updateSchema = z.object({24 action: z.literal("update"),25 id: z.number().int().positive(),26 active: z.boolean().optional(),27 pinned: z.boolean().optional(),28});29const deleteSchema = z.object({ action: z.literal("delete"), id: z.number().int().positive() });3031export async function POST(req: Request) {32 try {33 await assertSameOrigin();34 const user = await requireRole("instructor");35 const body = await parseBody(req, z.discriminatedUnion("action", [createSchema, updateSchema, deleteSchema]));36 if (body.action === "create") {37 run(38 "INSERT INTO announcements (title, body, course_code, pinned, created_by) VALUES (?, ?, ?, ?, ?)",39 body.title, body.body, body.courseCode, body.pinned ? 1 : 0, user.id40 );41 } else if (body.action === "update") {42 if (body.active !== undefined) run("UPDATE announcements SET active = ? WHERE id = ?", body.active ? 1 : 0, body.id);43 if (body.pinned !== undefined) run("UPDATE announcements SET pinned = ? WHERE id = ?", body.pinned ? 1 : 0, body.id);44 } else {45 run("DELETE FROM announcements WHERE id = ?", body.id);46 }47 return NextResponse.json({ ok: true });48 } catch (e) {49 return apiError(e);50 }51}52