import { Router } from "@oak/oak"; import { APIErrorCode, APIException, type APIResponse, type Comment, isCreateCommentRequest, isUpdateCommentRequest, } from "../model/interfaces.ts"; import { authMiddleware } from "../middleware/auth.ts"; import { verifyJWT } from "../lib/jwt.ts"; import { createComment, deleteComment, getComments, updateComment, } from "../services/comment-service.ts"; import { getDump } from "../services/dump-service.ts"; import { broadcastCommentCreated, broadcastCommentDeleted, broadcastCommentUpdated, } from "../services/ws-service.ts"; const router = new Router({ prefix: "/api" }); // GET /api/dumps/:dumpId/comments — optional auth (to access private dump comments) router.get("/dumps/:dumpId/comments", async (ctx) => { let requestingUserId: string | undefined; const authHeader = ctx.request.headers.get("Authorization"); if (authHeader?.startsWith("Bearer ")) { const payload = await verifyJWT(authHeader.substring(7)); if (payload) requestingUserId = payload.userId; } const dump = getDump(ctx.params.dumpId, requestingUserId); const comments = getComments(dump.id); const responseBody: APIResponse = { success: true, data: comments, }; ctx.response.body = responseBody; }); // POST /api/dumps/:dumpId/comments — auth required router.post("/dumps/:dumpId/comments", authMiddleware, async (ctx) => { const userId = ctx.state.user.userId as string; const dump = getDump(ctx.params.dumpId, userId); const body = await ctx.request.body.json(); if (!isCreateCommentRequest(body)) { throw new APIException( APIErrorCode.VALIDATION_ERROR, 400, "Invalid comment data", ); } const comment = createComment( dump.id, userId, body.body, body.parentId ?? undefined, ); if (!dump.isPrivate) broadcastCommentCreated(comment); const responseBody: APIResponse = { success: true, data: comment }; ctx.response.status = 201; ctx.response.body = responseBody; }); // PATCH /api/comments/:commentId — auth required router.patch("/comments/:commentId", authMiddleware, async (ctx) => { const userId = ctx.state.user.userId as string; const isAdmin = (ctx.state.user.isAdmin ?? false) as boolean; const body = await ctx.request.body.json(); if (!isUpdateCommentRequest(body)) { throw new APIException( APIErrorCode.VALIDATION_ERROR, 400, "Invalid comment data", ); } const { comment, isPrivate } = updateComment( ctx.params.commentId, body.body, userId, isAdmin, ); if (!isPrivate) broadcastCommentUpdated(comment); const responseBody: APIResponse = { success: true, data: comment }; ctx.response.body = responseBody; }); // DELETE /api/comments/:commentId — auth required router.delete("/comments/:commentId", authMiddleware, (ctx) => { const userId = ctx.state.user.userId as string; const isAdmin = (ctx.state.user.isAdmin ?? false) as boolean; const { dumpId, isPrivate } = deleteComment( ctx.params.commentId, userId, isAdmin, ); if (!isPrivate) broadcastCommentDeleted(ctx.params.commentId, dumpId); const responseBody: APIResponse = { success: true, data: null }; ctx.response.body = responseBody; }); export default router;