Files
gerbeur/api/routes/categories.ts
khannurien fae25f3e6c
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 2m52s
v3: added site-wide categories, added admin category management, various visual fixes
2026-06-28 16:23:44 +00:00

118 lines
2.8 KiB
TypeScript

import { Router } from "@oak/oak";
import {
APIErrorCode,
APIException,
type APIResponse,
type Category,
type Dump,
isCreateCategoryRequest,
isUpdateCategoryRequest,
type PaginatedData,
} from "../model/interfaces.ts";
import { authMiddleware, requirePermission } from "../middleware/auth.ts";
import { parseOptionalAuth } from "../lib/auth.ts";
import { parsePagination } from "../lib/pagination.ts";
import {
createCategory,
deleteCategory,
getCategoryBySlug,
listCategories,
listDumpsByCategory,
updateCategory,
} from "../services/category-service.ts";
const router = new Router({ prefix: "/api/categories" });
router.get("/", (ctx) => {
const responseBody: APIResponse<Category[]> = {
success: true,
data: listCategories(),
};
ctx.response.body = responseBody;
});
router.get("/:slug", (ctx) => {
const category = getCategoryBySlug(ctx.params.slug);
const responseBody: APIResponse<Category> = {
success: true,
data: category,
};
ctx.response.body = responseBody;
});
router.get("/:slug/dumps", async (ctx) => {
const requestingUserId = await parseOptionalAuth(ctx) ?? undefined;
const { page, limit } = parsePagination(ctx.request.url.searchParams);
const { items, total } = listDumpsByCategory(
ctx.params.slug,
page,
limit,
requestingUserId,
);
const responseBody: APIResponse<PaginatedData<Dump>> = {
success: true,
data: { items, total, hasMore: page * limit < total },
};
ctx.response.body = responseBody;
});
router.post(
"/",
authMiddleware,
requirePermission("category:manage"),
async (ctx) => {
const body = await ctx.request.body.json();
if (!isCreateCategoryRequest(body)) {
throw new APIException(
APIErrorCode.VALIDATION_ERROR,
400,
"Invalid category data",
);
}
const category = createCategory(body);
const responseBody: APIResponse<Category> = {
success: true,
data: category,
};
ctx.response.status = 201;
ctx.response.body = responseBody;
},
);
router.put(
"/:id",
authMiddleware,
requirePermission("category:manage"),
async (ctx) => {
const body = await ctx.request.body.json();
if (!isUpdateCategoryRequest(body)) {
throw new APIException(
APIErrorCode.VALIDATION_ERROR,
400,
"Invalid category data",
);
}
const category = updateCategory(ctx.params.id, body);
const responseBody: APIResponse<Category> = {
success: true,
data: category,
};
ctx.response.body = responseBody;
},
);
router.delete(
"/:id",
authMiddleware,
requirePermission("category:manage"),
(ctx) => {
deleteCategory(ctx.params.id);
const responseBody: APIResponse<null> = { success: true, data: null };
ctx.response.body = responseBody;
},
);
export default router;