import type { HttpContext } from '@adonisjs/core/http' import Post from '#models/post' import PostTransformer, { PostSummaryTransformer } from '#transformers/post_transformer' /** * BlogController — endpoints JSON publics pour le blog. * * L'API ne sert plus de HTML : le rendu des pages blog est délégué à * apps/landing (Astro SSR). Ce contrôleur expose uniquement les données. * * Routes (cf. start/routes.ts, sous /api/v1/posts) : * GET /api/v1/posts → liste des articles publiés (summary) * GET /api/v1/posts/:slug → article complet + articles liés * * Pas d'auth : le blog est public. Pas de pagination V1 (volume <100 articles * sur les 12 prochains mois — pas de besoin). On la rajoutera si nécessaire. * * Convention sérialisation : on passe des plain objects à `response.json` pour * matcher le pattern utilisé par clients_controller etc. (les autres contrôleurs * du codebase n'utilisent pas `serialize()` pour les arrays). */ export default class BlogController { /** * GET /api/v1/posts — liste publique, articles publiés du plus récent au * plus ancien, sans le contentHtml (payload léger pour la page liste). */ async index({ response }: HttpContext) { const posts = await Post.query().withScopes((s) => s.published()) return response.json({ data: posts.map((p) => new PostSummaryTransformer(p).toObject()), }) } /** * GET /api/v1/posts/:slug — article publié + 3 articles liés (intersection * de tags). 404 si non trouvé ou pas publié. */ async show({ params, response }: HttpContext) { const slug = String(params.slug ?? '') const post = await Post.query() .where('slug', slug) .where('status', 'published') .whereNotNull('publishedAt') .first() if (!post) { return response.status(404).json({ error: 'post_not_found' }) } const related = await Post.query().withScopes((s) => s.relatedTo(post)).limit(3) return response.json({ data: { post: new PostTransformer(post).toObject(), related: related.map((p) => new PostSummaryTransformer(p).toObject()), }, }) } }