Files
core/src/modules/posts/docs/programmatic.md
T
hykocx a57bf3607b docs(posts): add API and Next.js integration documentation
Add three documentation files for the posts module:
- `api.md`: public API reference (list, slug, categories, images)
- `admin-api.md`: admin API reference with all CRUD endpoints
- `integration.md`: Next.js integration examples with code snippets
2026-04-12 15:59:37 -04:00

3.1 KiB

Usage programmatique — Module Posts

Idéal pour les cron jobs, scripts d'import ou fetchers automatisés.

Fonctions disponibles

import {
  createPost,       // Créer un post
  updatePost,       // Modifier un post
  getPostBySlug,    // Chercher par slug
  getPostByField,   // Chercher par n'importe quel champ JSONB
  upsertPost,       // Créer ou mettre à jour (idempotent)
  getPosts,         // Liste avec pagination
  deletePost,       // Supprimer
} from '@zen/core/modules/posts/crud';

upsertPost(postType, rawData, uniqueField)

Crée le post s'il n'existe pas, le met à jour sinon.

  • postType : le type de post ('cve', 'actualite'...)
  • rawData : les données du post (mêmes champs que pour createPost)
  • uniqueField : le champ de déduplication ('slug' par défaut)

Retourne { post, created: boolean }.

Champs relation dans rawData

Les champs relation reçoivent un tableau d'IDs de posts existants.

// Correct
{ tags: [7, 8, 12], source: [3] }

// Incorrect
{ tags: ['openssh', 'vuln'], source: { id: 3 } }

Si les posts liés n'existent pas encore, les créer d'abord avec upsertPost puis utiliser leurs IDs.


Exemple : fetcher de CVE

// src/cron/fetch-cves.js
import { upsertPost } from '@zen/core/modules/posts/crud';

export async function fetchAndImportCVEs() {
  const response = await fetch('https://api.example.com/cves/recent');
  const { cves } = await response.json();

  const results = { created: 0, updated: 0, errors: 0 };

  for (const cve of cves) {
    try {
      // Résoudre les relations : s'assurer que les tags existent
      const tagIds = [];
      for (const tagName of (cve.tags || [])) {
        const { post: tag } = await upsertPost('tag', { title: tagName }, 'slug');
        tagIds.push(tag.id);
      }

      // Upsert du CVE, dédupliqué sur cve_id
      const { created } = await upsertPost('cve', {
        title: cve.title,
        cve_id: cve.id,
        severity: cve.severity,
        score: String(cve.cvssScore),
        product: cve.affectedProduct,
        date: cve.publishedAt,
        description: cve.description,
        tags: tagIds,
      }, 'cve_id');

      created ? results.created++ : results.updated++;
    } catch (err) {
      console.error(`[CVE import] Error for ${cve.id}:`, err.message);
      results.errors++;
    }
  }

  console.log(`[CVE import] Done — created: ${results.created}, updated: ${results.updated}, errors: ${results.errors}`);
  return results;
}

Exemple : fetcher d'actualités avec source

import { upsertPost } from '@zen/core/modules/posts/crud';

export async function fetchAndImportActualites(sourceName, articles) {
  // S'assurer que la source existe
  const { post: source } = await upsertPost('source', { title: sourceName }, 'slug');

  for (const article of articles) {
    await upsertPost('actualite', {
      title: article.title,
      date: article.publishedAt,
      resume: article.summary,
      content: article.content,
      source: [source.id],
      tags: [],
    }, 'slug');
  }
}