/** * Serves the categories dumps and playlists are filed under, a set for each * kind, and changes them for those with `category:manage`. A dump category's * feed is `GET /api/dumps?category=:slug`, a playlist category's * `GET /api/playlists?category=:slug`. * * - `GET /api/categories` — public. Answers every category of both kinds, by * kind, then in order. * - `POST /api/categories` — permission `category:manage`. Creates a category * of the kind it names. * - `PUT /api/categories/:id` — permission `category:manage`. Updates a * category. * - `DELETE /api/categories/:id` — permission `category:manage`. Deletes a * category; its dumps or playlists 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;