52 lines
2.1 KiB
TypeScript
52 lines
2.1 KiB
TypeScript
import { HttpError } from "@/lib/errors";
|
|
import { readJson, route } from "@/lib/http";
|
|
import { deleteImageDir, renameImageDir } from "@/lib/images";
|
|
import { findPost, mutatePosts, readPosts } from "@/lib/store";
|
|
import { validatePost } from "@/lib/validate";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
type Ctx = { params: Promise<{ slug: string }> };
|
|
|
|
export const GET = route<Ctx>(async (_req, { params }) => {
|
|
const { slug } = await params;
|
|
const { posts, revision } = await readPosts();
|
|
return Response.json({ post: findPost(posts, slug), revision });
|
|
});
|
|
|
|
/** Body: { post: PostInput, revision? }. A changed slug also moves the
|
|
* post's image folder and rewrites references to it. */
|
|
export const PUT = route<Ctx>(async (req, { params }) => {
|
|
const { slug } = await params;
|
|
const body = await readJson<{ post?: unknown; revision?: string }>(req);
|
|
const { post: input, errors } = validatePost(body.post);
|
|
if (!input) throw new HttpError(400, "invalid post", errors);
|
|
|
|
const { result, revision } = await mutatePosts(body.revision, async (posts) => {
|
|
const existing = findPost(posts, slug);
|
|
const updated = { ...input, id: existing.id };
|
|
if (input.slug !== slug) {
|
|
if (posts.some((p) => p.slug === input.slug)) {
|
|
throw new HttpError(409, `a post with slug "${input.slug}" already exists`);
|
|
}
|
|
await renameImageDir(updated, slug, input.slug);
|
|
}
|
|
// images is optional: an editor that cleared the gallery drops the key.
|
|
if (!input.images) delete (updated as { images?: unknown }).images;
|
|
posts[posts.indexOf(existing)] = updated;
|
|
return updated;
|
|
});
|
|
return Response.json({ post: result, revision });
|
|
});
|
|
|
|
/** Query: ?revision=…&images=1 (also delete the post's image folder). */
|
|
export const DELETE = route<Ctx>(async (req, { params }) => {
|
|
const { slug } = await params;
|
|
const url = new URL(req.url);
|
|
const { revision } = await mutatePosts(url.searchParams.get("revision") ?? undefined, (posts) => {
|
|
posts.splice(posts.indexOf(findPost(posts, slug)), 1);
|
|
});
|
|
if (url.searchParams.get("images") === "1") await deleteImageDir(slug);
|
|
return Response.json({ deleted: slug, revision });
|
|
});
|