import { NextRequest, NextResponse } from "next/server"; import crypto from "node:crypto"; import { z } from "zod"; import { db, supportTickets, eq, desc } from "@epicure/db"; import { requireSession } from "@/lib/api-auth"; import { sendEmail, supportTicketReceivedHtml } from "@/lib/email"; import { createGiteaIssue } from "@/lib/gitea"; const CreateTicketBody = z.object({ type: z.enum(["bug", "suggestion", "question"]), title: z.string().trim().min(3).max(200), description: z.string().trim().min(10).max(5000), }); export async function GET() { const { session, response } = await requireSession(); if (response) return response; const rows = await db .select() .from(supportTickets) .where(eq(supportTickets.userId, session!.user.id)) .orderBy(desc(supportTickets.createdAt)); return NextResponse.json(rows); } export async function POST(req: NextRequest) { const { session, response } = await requireSession(); if (response) return response; const body = (await req.json()) as unknown; const parsed = CreateTicketBody.safeParse(body); if (!parsed.success) { return NextResponse.json( { error: "Validation error", issues: parsed.error.issues }, { status: 400 } ); } const { type, title, description } = parsed.data; const id = crypto.randomUUID(); const now = new Date(); const { url: giteaIssueUrl, error: giteaError } = await createGiteaIssue({ type, title, body: `${description}\n\n---\nReported via Epicure support form by user \`${session!.user.id}\`.`, }); await db.insert(supportTickets).values({ id, userId: session!.user.id, type, title, description, status: "open", giteaIssueUrl, giteaError, createdAt: now, updatedAt: now, }); const baseUrl = process.env["BETTER_AUTH_URL"] ?? "http://localhost:3000"; const ticketUrl = `${baseUrl}/support`; if (session!.user.email) { try { await sendEmail({ to: session!.user.email, subject: "We got your message — Epicure", html: supportTicketReceivedHtml({ type, title, ticketUrl, giteaIssueUrl }), }); } catch { // Ticket is saved either way — email failure shouldn't fail the request. } } return NextResponse.json( { id, userId: session!.user.id, type, title, description, status: "open" as const, giteaIssueUrl, giteaError, createdAt: now.toISOString(), updatedAt: now.toISOString(), }, { status: 201 } ); }