feat(F-048): completed feature

This commit is contained in:
chattie
2026-08-19 07:17:14 +02:00
parent 8ee1938af9
commit 835ab66eda
187 changed files with 12361 additions and 1065 deletions

View File

@@ -1,9 +1,11 @@
import type { FastifyInstance } from 'fastify';
import type { FastifySchema } from 'fastify';
import type pg from 'pg';
import { z } from 'zod';
import type { Authenticate } from '../../../shared/auth.js';
import { requireRole } from '../../../shared/auth.js';
import { AppError } from '../../../shared/errors.js';
import { errorSchema } from '../../../shared/swagger.js';
import { parseJson } from '../../../shared/http-input.js';
import { CmsService } from '../application/cms-service.js';
import { DuplicateSlugError, PageNotFoundError, PageNotPublishedError } from '../domain/errors.js';
@@ -46,14 +48,25 @@ const slugParamSchema = z.object({ slug: z.string().min(1).max(160) });
export async function registerCmsRoutes(app: FastifyInstance, deps: CmsRoutesDeps): Promise<void> {
const service = new CmsService(new PgCmsRepository(deps.pool));
app.get('/cms/pages', async (request, reply) => {
const listPagesSchema: FastifySchema = {
tags: ['CMS'],
summary: 'List CMS pages (admin)',
response: { 401: errorSchema, 403: errorSchema },
};
app.get('/cms/pages', { schema: listPagesSchema }, async (request, reply) => {
const user = await deps.authenticate(request);
requireRole(user, 'admin');
const pages = await service.listAll();
return reply.send({ items: pages.map(serialize) });
});
app.post('/cms/pages', async (request, reply) => {
const createPageSchema: FastifySchema = {
tags: ['CMS'],
summary: 'Create CMS page (admin)',
body: { type: 'object' },
response: { 201: { type: 'object' }, 401: errorSchema, 403: errorSchema },
};
app.post('/cms/pages', { schema: createPageSchema }, async (request, reply) => {
const user = await deps.authenticate(request);
requireRole(user, 'admin');
const input = parseJson(createSchema, request.body);
@@ -65,7 +78,18 @@ export async function registerCmsRoutes(app: FastifyInstance, deps: CmsRoutesDep
}
});
app.patch('/cms/pages/:id', async (request, reply) => {
const updatePageSchema: FastifySchema = {
tags: ['CMS'],
summary: 'Update CMS page (admin)',
params: {
type: 'object',
required: ['id'],
properties: { id: { type: 'string', format: 'uuid' } },
},
body: { type: 'object' },
response: { 401: errorSchema, 403: errorSchema },
};
app.patch('/cms/pages/:id', { schema: updatePageSchema }, async (request, reply) => {
const user = await deps.authenticate(request);
requireRole(user, 'admin');
const { id } = idParamSchema.parse(request.params);
@@ -78,7 +102,17 @@ export async function registerCmsRoutes(app: FastifyInstance, deps: CmsRoutesDep
}
});
app.post('/cms/pages/:id/publish', async (request, reply) => {
const publishSchema: FastifySchema = {
tags: ['CMS'],
summary: 'Publish page (admin)',
params: {
type: 'object',
required: ['id'],
properties: { id: { type: 'string', format: 'uuid' } },
},
response: { 401: errorSchema, 403: errorSchema },
};
app.post('/cms/pages/:id/publish', { schema: publishSchema }, async (request, reply) => {
const user = await deps.authenticate(request);
requireRole(user, 'admin');
const { id } = idParamSchema.parse(request.params);
@@ -90,7 +124,17 @@ export async function registerCmsRoutes(app: FastifyInstance, deps: CmsRoutesDep
}
});
app.post('/cms/pages/:id/unpublish', async (request, reply) => {
const unpublishSchema: FastifySchema = {
tags: ['CMS'],
summary: 'Unpublish page (admin)',
params: {
type: 'object',
required: ['id'],
properties: { id: { type: 'string', format: 'uuid' } },
},
response: { 401: errorSchema, 403: errorSchema },
};
app.post('/cms/pages/:id/unpublish', { schema: unpublishSchema }, async (request, reply) => {
const user = await deps.authenticate(request);
requireRole(user, 'admin');
const { id } = idParamSchema.parse(request.params);
@@ -102,7 +146,13 @@ export async function registerCmsRoutes(app: FastifyInstance, deps: CmsRoutesDep
}
});
app.get('/cms/pages/:slug', async (request, reply) => {
const getPageSchema: FastifySchema = {
tags: ['CMS'],
summary: 'Get published page (público)',
params: { type: 'object', required: ['slug'], properties: { slug: { type: 'string' } } },
response: { 404: errorSchema },
};
app.get('/cms/pages/:slug', { schema: getPageSchema }, async (request, reply) => {
const { slug } = slugParamSchema.parse(request.params);
try {
const page = await service.getPublicPageBySlug(slug);