import { HttpError } from "@batch-cooking/error-tools"; import { wrapAsyncHandler } from "@batch-cooking/express-tools"; import { createForgejoIssueSchema, ErrorCode, listContactMessagesQuerySchema, } from "@batch-cooking/shared"; import { Router } from "express"; import { requireAdmin } from "../../middlewares/require-admin.js"; import { createForgejoIssueFromMessage, getForgejoStatus, listContactMessages, } from "./admin-contact.service.js"; /** * Router mounted at `/admin/api/contact` (via `admin.routes.ts`) — behind * {@link requireAdmin}. Backs the `/admin/messages` page: the read-only list * of contact-form messages (issue #80), plus "create a Forgejo issue from * this message" (issue #81). Still no message-mutation routes — the message * itself stays read-only. */ export const adminContactRouter = Router(); adminContactRouter.get( "/", requireAdmin, wrapAsyncHandler(async (req, res) => { res .status(200) .json(await listContactMessages(listContactMessagesQuerySchema.parse(req.query))); }), ); // Static path — declared before `/:id/...` so it's never parsed as an id. adminContactRouter.get( "/forgejo/status", requireAdmin, wrapAsyncHandler(async (_req, res) => { res.status(200).json(getForgejoStatus()); }), ); adminContactRouter.post( "/:id/forgejo-issue", requireAdmin, wrapAsyncHandler(async (req, res) => { const id = Number(req.params.id); if (!Number.isInteger(id) || id <= 0) { throw new HttpError( 400, ErrorCode.VALIDATION_ERROR, `Not a valid contact message id: ${req.params.id}`, ); } const input = createForgejoIssueSchema.parse(req.body); res.status(200).json(await createForgejoIssueFromMessage(id, input)); }), );