import { NextResponse } from "next/server"; import prisma from "@/lib/prisma"; import { z } from "zod"; const createPostSchema = z.object({ boardId: z.string().min(1), authorId: z.string().optional(), title: z.string().min(1), content: z.string().min(1), isAnonymous: z.boolean().optional(), }); export async function POST(req: Request) { const body = await req.json(); const parsed = createPostSchema.safeParse(body); if (!parsed.success) { return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 }); } const { boardId, authorId, title, content, isAnonymous } = parsed.data; const board = await prisma.board.findUnique({ where: { id: boardId } }); const requiresApproval = board?.requiresApproval ?? false; const post = await prisma.post.create({ data: { boardId, authorId: authorId ?? null, title, content, isAnonymous: !!isAnonymous, status: requiresApproval ? "hidden" : "published", }, }); return NextResponse.json({ post }, { status: 201 }); } const listQuerySchema = z.object({ page: z.coerce.number().min(1).default(1), pageSize: z.coerce.number().min(1).max(100).default(10), boardId: z.string().optional(), q: z.string().optional(), sort: z.enum(["recent", "popular"]).default("recent").optional(), }); export async function GET(req: Request) { const { searchParams } = new URL(req.url); const parsed = listQuerySchema.safeParse(Object.fromEntries(searchParams)); if (!parsed.success) { return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 }); } const { page, pageSize, boardId, q, sort = "recent" } = parsed.data; const where = { ...(boardId ? { boardId } : {}), ...(q ? { OR: [ { title: { contains: q } }, { content: { contains: q } }, ], } : {}), } as const; const [total, items] = await Promise.all([ prisma.post.count({ where }), prisma.post.findMany({ where, orderBy: sort === "popular" ? [{ isPinned: "desc" }, { stat: { recommendCount: "desc" } }, { createdAt: "desc" }] : [{ isPinned: "desc" }, { createdAt: "desc" }], skip: (page - 1) * pageSize, take: pageSize, select: { id: true, title: true, createdAt: true, boardId: true, isPinned: true, status: true, stat: { select: { recommendCount: true, views: true, commentsCount: true } }, }, }), ]); return NextResponse.json({ total, page, pageSize, items, sort }); }