initial commit
This commit is contained in:
35
app/api/categories/route.ts
Normal file
35
app/api/categories/route.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { HttpError } from "@/lib/errors";
|
||||
import { readJson, route } from "@/lib/http";
|
||||
import { categoryCounts, mutatePosts, readPosts } from "@/lib/store";
|
||||
import { SLUG_RE } from "@/lib/validate";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export const GET = route(async () => {
|
||||
const { posts, revision } = await readPosts();
|
||||
return Response.json({ categories: categoryCounts(posts), revision });
|
||||
});
|
||||
|
||||
/**
|
||||
* Body: { from, to, revision? }. Moves every post in `from` to `to`; if `to`
|
||||
* is already in use this is a merge. Categories are derived from posts, so a
|
||||
* category disappears once no post uses it.
|
||||
*/
|
||||
export const PATCH = route(async (req) => {
|
||||
const { from, to, revision: expected } = await readJson<{ from?: string; to?: string; revision?: string }>(req);
|
||||
const target = to?.trim() ?? "";
|
||||
if (!from) throw new HttpError(400, "from is required");
|
||||
if (!SLUG_RE.test(target)) throw new HttpError(400, "category must be lowercase kebab-case");
|
||||
|
||||
const { result, revision } = await mutatePosts(expected, (posts) => {
|
||||
let changed = 0;
|
||||
for (const post of posts) {
|
||||
if (post.category !== from) continue;
|
||||
post.category = target;
|
||||
changed++;
|
||||
}
|
||||
if (!changed) throw new HttpError(404, `no posts in category "${from}"`);
|
||||
return changed;
|
||||
});
|
||||
return Response.json({ changed: result, revision });
|
||||
});
|
||||
Reference in New Issue
Block a user