feat(plugins): content-pages + legal-pages (Phase 4.1 + 4.3)
Plugin content-pages : - Modèle Prisma ContentPage (slug PK, title, body markdown, category, published) - lib/content-pages.ts : helpers upsert/get/list/unpublish - lib/markdown.ts : mini-renderer markdown server-side sans deps externe (h1-h3, paragraphes, gras/italique, liens, listes ul/ol, hr, blockquote, échappement HTML) - ContentPageRenderer server component, applique le theme Guyane (font-serif) - 5 pages seedées : /a-propos, /faq, /comment-ca-marche, /pour-comites-entreprise, /devenir-loueur - Routes publiques + force-dynamic + guard requirePluginOr404 Plugin legal-pages : - Réutilise le même modèle ContentPage, catégorie 'legal' - 3 pages seedées : /cgv, /mentions-legales, /politique-de-confidentialite (contenu de base, à valider par avocat avant prod réelle) Admin : - /admin/content-pages : table par catégorie, statut publié/dépublié - /admin/content-pages/[slug] : éditeur markdown + toggle publié - PATCH /api/admin/content-pages/[slug] Hooks plugin : - onEnable seed + republish toutes les pages - onDisable dépublie toute la catégorie sans la supprimer (preserve les edits)
This commit is contained in:
parent
ae8f79b436
commit
68f37f554f
20 changed files with 1116 additions and 0 deletions
39
src/app/api/admin/content-pages/[slug]/route.ts
Normal file
39
src/app/api/admin/content-pages/[slug]/route.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { auth } from "@/auth";
|
||||
import { requireRole } from "@/lib/authorization";
|
||||
import { UserRole } from "@/generated/prisma/enums";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
const patchSchema = z.object({
|
||||
title: z.string().min(1).max(200).optional(),
|
||||
body: z.string().max(100_000).optional(),
|
||||
published: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export async function PATCH(req: Request, ctx: { params: Promise<{ slug: string }> }) {
|
||||
await requireRole([UserRole.ADMIN]);
|
||||
const { slug } = await ctx.params;
|
||||
const session = await auth();
|
||||
const parsed = patchSchema.safeParse(await req.json().catch(() => ({})));
|
||||
if (!parsed.success) {
|
||||
return NextResponse.json({ error: "Invalid payload" }, { status: 400 });
|
||||
}
|
||||
const existing = await prisma.contentPage.findUnique({ where: { slug } });
|
||||
if (!existing) return NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
const updated = await prisma.contentPage.update({
|
||||
where: { slug },
|
||||
data: {
|
||||
...(parsed.data.title !== undefined ? { title: parsed.data.title } : {}),
|
||||
...(parsed.data.body !== undefined ? { body: parsed.data.body } : {}),
|
||||
...(parsed.data.published !== undefined ? { published: parsed.data.published } : {}),
|
||||
lastEditedBy: session?.user?.email ?? session?.user?.id ?? null,
|
||||
},
|
||||
});
|
||||
return NextResponse.json({
|
||||
slug: updated.slug,
|
||||
title: updated.title,
|
||||
published: updated.published,
|
||||
updatedAt: updated.updatedAt,
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue