// Public REST API — post a reply to a help-center ticket. // // Bearer-authed. POST inserts a reply ({ content }) authored by the current user // into website_help_center_ticket_replies. The target ticket must exist and // belong to the authed user. Fail-soft: never a 500. import { apiError, apiJson } from "@/lib/api"; import { bearerUserId } from "@/lib/api-auth"; import { prisma } from "@/lib/prisma"; export const dynamic = "force-dynamic"; // POST /api/tickets/:id/reply body: { content } export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) { const uid = await bearerUserId(req); if (!uid) return apiError("Unauthorized", 401); const { id } = await params; if (!/^\d+$/.test(id)) return apiError("Invalid ticket id"); const ticketId = BigInt(id); const body = (await req.json().catch(() => ({}))) as { content?: unknown }; const content = String(body.content ?? "").trim().slice(0, 5000); if (!content) return apiError("Content is required"); try { // Ownership check — only the ticket owner may reply. const ticket = await prisma.websiteHelpCenterTickets.findUnique({ where: { id: ticketId }, select: { id: true, userId: true }, }); if (!ticket || ticket.userId !== uid) return apiError("Ticket not found", 404); const now = new Date(); const reply = await prisma.websiteHelpCenterTicketReplies.create({ data: { ticketId, userId: uid, content, createdAt: now, updatedAt: now, }, select: { id: true, userId: true, content: true, createdAt: true }, }); // Touch the parent ticket so its updatedAt reflects the latest activity. prisma.websiteHelpCenterTickets .update({ where: { id: ticketId }, data: { updatedAt: now }, select: { id: true } }) .catch(() => {}); return apiJson( { reply: { id: reply.id, userId: reply.userId, content: reply.content, createdAt: reply.createdAt, }, }, { status: 201 }, ); } catch { return apiError("Failed to post reply", 503); } }