/** * Serves the categories dumps are filed under, and changes them for those with * `category:manage`. A category's feed is `GET /api/dumps?category=:slug`. * * - `GET /api/categories` — public. Answers every category, in order. * - `POST /api/categories` — permission `category:manage`. Creates a category. * - `PUT /api/categories/:id` — permission `category:manage`. Updates a * category. * - `DELETE /api/categories/:id` — permission `category:manage`. Deletes a * category; its dumps stay. * * @module */ import { Router } from "@oak/oak"; import { type APIResponse } from "../../shared/api.ts"; import { APIException } from "../lib/api-exception.ts"; import type { Category } from "../../shared/category.ts"; import { isCreateCategoryRequest, isUpdateCategoryRequest, } from "../validators/category.ts"; import { authMiddleware, requirePermission } from "../middleware/auth.ts"; import { createCategory, deleteCategory, listCategories, updateCategory, } from "../services/category-service.ts"; /** * Mounted by `api/main.ts` behind the error, Open Graph and CORS middleware. * An `APIException` thrown by a handler becomes the JSON error response there. */ const router: Router = new Router({ prefix: "/api/categories" }); router.get("/", (ctx) => { const responseBody: APIResponse = { success: true, data: listCategories(), }; ctx.response.body = responseBody; }); router.post( "/", authMiddleware, requirePermission("category:manage"), async (ctx) => { const body: unknown = await ctx.request.body.json(); if (!isCreateCategoryRequest(body)) { throw new APIException(400, "Invalid category data"); } const category = createCategory(body); const responseBody: APIResponse = { success: true, data: category, }; ctx.response.status = 201; ctx.response.body = responseBody; }, ); router.put( "/:id", authMiddleware, requirePermission("category:manage"), async (ctx) => { const body: unknown = await ctx.request.body.json(); if (!isUpdateCategoryRequest(body)) { throw new APIException(400, "Invalid category data"); } const category = updateCategory(ctx.params.id, body); const responseBody: APIResponse = { success: true, data: category, }; ctx.response.body = responseBody; }, ); router.delete( "/:id", authMiddleware, requirePermission("category:manage"), (ctx) => { deleteCategory(ctx.params.id); const responseBody: APIResponse = { success: true, data: null }; ctx.response.body = responseBody; }, ); export default router;