/** * @copyright nhcarrigan * @license Naomi's Public License * @author Naomi Carrigan */ import { validateBody } from "../../modules/validateBody.js"; import { logger } from "../../utils/logger.js"; import { sendMail } from "../../utils/mailer.js"; import type { PrismaClient } from "@prisma/client"; import type { Appeal, ErrorResponse, SuccessResponse } from "@repo/types"; import type { FastifyReply, FastifyRequest } from "fastify"; /** *Handles appeal form submissions. * @param database - The Prisma database client. * @param request - The request object. * @param response - The Fastify reply utility. */ export const submitAppealHandler = async( database: PrismaClient, request: FastifyRequest<{ Body: Appeal }>, response: FastifyReply<{ Reply: SuccessResponse | ErrorResponse }>, ): Promise => { try { const isInvalid = validateBody( // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We're passing a narrower type and TS hates that? request.body as unknown as Record, "appeals", ); if (isInvalid !== null) { await response.status(400).send({ error: isInvalid }); return; } const exists = await database.appeals.findUnique({ where: { email: request.body.email, }, }); if (exists !== null) { await response.status(429).send({ error: // eslint-disable-next-line stylistic/max-len -- This is a long string. "You have already submitted an appeal. Please wait for it to be reviewed.", }); return; } const data = { ...request.body }; // @ts-expect-error -- We're deleting a property here. delete data.consent; await database.appeals.create({ data, }); await sendMail("appeal", data); await response.send({ success: true }); } catch (error) { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- we bein' lazy. await logger.error("/submit/appeals", error as Error); await response.status(500).send({ error: error instanceof Error ? error.message : "Internal Server Error" }); } };