Checkpoint: Ajout de la page de gestion des flux RSS : liste des flux, formulaire d'ajout/édition avec type (Veille/AAP), type par défaut, règles d'automatisme par mots-clés, paramètres de fréquence (heure fixe ou intervalle), activation/désactivation. Tables BDD rss_feeds et rss_settings. Procédures tRPC complètes. Navigation sidebar mise à jour.

This commit is contained in:
Manus
2026-04-25 16:44:09 -04:00
parent 4a17eaa04a
commit c3e1720e83
11 changed files with 1958 additions and 5 deletions

View File

@@ -22,6 +22,13 @@ import {
getIdeasByUser,
repondreIdea,
updateIdeaStatut,
getRssFeeds,
getRssFeedById,
createRssFeed,
updateRssFeed,
deleteRssFeed,
getRssSettings,
saveRssSettings,
} from "./db";
import { importVeille, importAAP, runFullImport, getImportConfig } from "./importer";
import { loginLocalUser, hashPassword, ensureAdminExists } from "./localAuth";
@@ -307,6 +314,94 @@ export const appRouter = router({
return { success: true };
}),
}),
});
// ─── Flux RSS ───────────────────────────────────────────────────────────────────────────────────
rss: router({
// Lister tous les flux
list: protectedProcedure.query(async () => {
return getRssFeeds();
}),
// Créer un flux
create: adminProcedure
.input(z.object({
url: z.string().url("URL invalide"),
name: z.string().min(1, "Nom requis").max(255),
feedType: z.enum(["veille", "aap"]),
defaultTypeVeille: z.enum(["reglementaire", "concurrentielle", "technologique", "generale"]).optional(),
defaultCategorieAap: z.enum(["Handicap", "PA", "Enfance", "Précarité", "Sanitaire", "Autre"]).optional(),
autoRules: z.array(z.object({
keyword: z.string(),
value: z.string(),
})).optional(),
isActive: z.boolean().optional().default(true),
}))
.mutation(async ({ input }) => {
const id = await createRssFeed({
url: input.url,
name: input.name,
feedType: input.feedType,
defaultTypeVeille: input.defaultTypeVeille ?? null,
defaultCategorieAap: input.defaultCategorieAap ?? null,
autoRules: input.autoRules ?? null,
isActive: input.isActive ?? true,
});
return { id };
}),
// Modifier un flux
update: adminProcedure
.input(z.object({
id: z.number().int().positive(),
url: z.string().url("URL invalide").optional(),
name: z.string().min(1).max(255).optional(),
feedType: z.enum(["veille", "aap"]).optional(),
defaultTypeVeille: z.enum(["reglementaire", "concurrentielle", "technologique", "generale"]).nullable().optional(),
defaultCategorieAap: z.enum(["Handicap", "PA", "Enfance", "Précarité", "Sanitaire", "Autre"]).nullable().optional(),
autoRules: z.array(z.object({
keyword: z.string(),
value: z.string(),
})).nullable().optional(),
isActive: z.boolean().optional(),
}))
.mutation(async ({ input }) => {
const { id, ...data } = input;
await updateRssFeed(id, data);
return { success: true };
}),
// Supprimer un flux
delete: adminProcedure
.input(z.object({ id: z.number().int().positive() }))
.mutation(async ({ input }) => {
await deleteRssFeed(input.id);
return { success: true };
}),
// Activer / désactiver un flux
toggleActive: adminProcedure
.input(z.object({ id: z.number().int().positive(), isActive: z.boolean() }))
.mutation(async ({ input }) => {
await updateRssFeed(input.id, { isActive: input.isActive });
return { success: true };
}),
// Lire les paramètres globaux RSS
getSettings: protectedProcedure.query(async () => {
return getRssSettings();
}),
// Sauvegarder les paramètres globaux RSS
saveSettings: adminProcedure
.input(z.object({
fetchIntervalMinutes: z.number().int().min(5).max(10080).optional(),
scheduledTime: z.string().regex(/^\d{2}:\d{2}$/, "Format HH:MM requis").optional(),
fetchMode: z.enum(["interval", "scheduled"]).optional(),
autoFetchEnabled: z.boolean().optional(),
}))
.mutation(async ({ input }) => {
await saveRssSettings(input);
return { success: true };
}),
}),
});
export type AppRouter = typeof appRouter;