Files
veille-reglementaire/server/scheduledRoutes.ts
Manus Deploy 76a71ebc2c feat: fusion multi-département RSS, enrichissement catégorie/niveau/territoire
- Ajout colonnes territoires (JSON) dans veille_items et departements (JSON) dans aap_items
- Logique de fusion : articles similaires (même sujet, départements différents) fusionnés en un seul
- Extraction automatique : catégorie (Handicap/PA/Enfance/Précarité/Sanitaire/Autre), niveau et territoire
- Endpoint POST /api/scheduled/rss-migrate pour migration des articles existants
- Correction patterns détection : Loire, Rhône (sans Lyon seul), Auvergne-Rhône-Alpes protégé
2026-04-28 19:19:06 -04:00

85 lines
2.8 KiB
TypeScript

/**
* Routes pour les tâches planifiées.
* POST /api/scheduled/rss-fetch — déclenche la lecture de tous les flux RSS actifs.
* POST /api/scheduled/rss-migrate — met à jour les articles existants avec les champs enrichis.
* Protégé par cookie de session (rôle "user" minimum, conforme aux tâches planifiées Manus).
*/
import express, { Router, Request, Response } from "express";
import { parse as parseCookieHeader } from "cookie";
import { verifyLocalToken, LOCAL_AUTH_COOKIE } from "./localAuth";
import { sdk } from "./_core/sdk";
import { runRssFetch, migrateExistingItems } from "./rssEngine";
const router: Router = express.Router();
/**
* Middleware d'authentification léger :
* accepte soit un cookie veille_local_auth (utilisateurs locaux),
* soit un cookie Manus OAuth (app_session_id via sdk.authenticateRequest).
*/
async function requireAuth(req: Request, res: Response, next: () => void) {
try {
const cookieHeader = req.headers.cookie ?? "";
const cookies = parseCookieHeader(cookieHeader);
// 1. Cookie local
const localToken = cookies[LOCAL_AUTH_COOKIE];
if (localToken) {
const user = await verifyLocalToken(localToken);
if (user) return next();
}
// 2. Cookie Manus OAuth
try {
await sdk.authenticateRequest(req);
return next();
} catch (_) { /* pas de session OAuth valide */ }
res.status(401).json({ error: "Non authentifié" });
} catch (e) {
res.status(401).json({ error: "Erreur d'authentification" });
}
}
/**
* POST /api/scheduled/rss-fetch
* Déclenche la lecture de tous les flux RSS actifs et insère les nouveaux articles.
*/
router.post("/api/scheduled/rss-fetch", requireAuth, async (req: Request, res: Response) => {
console.log("[Scheduled] Déclenchement de la lecture RSS...");
try {
const summary = await runRssFetch();
res.json({
success: true,
summary,
});
} catch (e: unknown) {
const msg = e instanceof Error ? e.message : String(e);
console.error("[Scheduled/rss-fetch] Erreur:", msg);
res.status(500).json({ success: false, error: msg });
}
});
/**
* POST /api/scheduled/rss-migrate
* Met à jour les articles existants (veille_items et aap_items) avec les champs enrichis :
* - veille_items : catégorie, niveau, territoire
* - aap_items : région, département
*/
router.post("/api/scheduled/rss-migrate", requireAuth, async (req: Request, res: Response) => {
console.log("[Scheduled] Migration des articles existants...");
try {
const summary = await migrateExistingItems();
res.json({
success: true,
summary,
});
} catch (e: unknown) {
const msg = e instanceof Error ? e.message : String(e);
console.error("[Scheduled/rss-migrate] Erreur:", msg);
res.status(500).json({ success: false, error: msg });
}
});
export default router;