-
-
- {([
- { value: "daily", label: "Quotidienne", desc: "Chaque jour à l'heure choisie" },
- { value: "weekly", label: "Hebdomadaire", desc: "Un jour précis chaque semaine" },
- { value: "monthly", label: "Mensuelle", desc: "Un jour précis chaque mois" },
- { value: "interval", label: "Intervalle", desc: "Toutes les N heures" },
- ] as const).map((opt) => (
+
+
+ {(["scheduled", "interval"] as const).map((mode) => (
))}
- {/* Heure (tous les modes sauf intervalle) */}
- {(form.fetch_mode || "daily") !== "interval" && (
+ {/* Heure fixe */}
+ {(form.fetch_mode || "scheduled") === "scheduled" && (
-
+
set("import_time", e.target.value)}
/>
-
- )}
-
- {/* Jour de la semaine (hebdomadaire) */}
- {(form.fetch_mode || "daily") === "weekly" && (
-
-
-
- {[
- { label: "Lun", value: "1" },
- { label: "Mar", value: "2" },
- { label: "Mer", value: "3" },
- { label: "Jeu", value: "4" },
- { label: "Ven", value: "5" },
- { label: "Sam", value: "6" },
- { label: "Dim", value: "0" },
- ].map((d) => (
-
- ))}
-
-
- )}
-
- {/* Jour du mois (mensuel) */}
- {(form.fetch_mode || "daily") === "monthly" && (
-
-
-
set("fetch_month_day", e.target.value)}
- />
-
Maximum 28 pour garantir l'exécution tous les mois
+
+ Prochain import : demain à {form.import_time || "06:00"}
+
)}
{/* Intervalle */}
- {(form.fetch_mode || "daily") === "interval" && (
-
-
-
+ {(form.fetch_mode || "scheduled") === "interval" && (
+
+
+
{[
- { label: "1h", value: "60" },
- { label: "2h", value: "120" },
- { label: "4h", value: "240" },
- { label: "6h", value: "360" },
+ { label: "1h", value: "60" },
+ { label: "2h", value: "120" },
+ { label: "4h", value: "240" },
+ { label: "6h", value: "360" },
{ label: "12h", value: "720" },
{ label: "24h", value: "1440" },
].map((opt) => (
@@ -575,7 +524,7 @@ export default function SettingsPage() {
type="button"
onClick={() => set("fetch_interval_minutes", opt.value)}
className={cn(
- "w-14 py-2 rounded-lg border-2 text-sm font-medium transition-all",
+ "py-2 px-3 rounded-lg border-2 text-sm font-medium transition-all",
(form.fetch_interval_minutes || "1440") === opt.value
? "border-primary bg-primary/5 text-primary"
: "border-border hover:border-primary/40 text-foreground"
@@ -586,9 +535,7 @@ export default function SettingsPage() {
))}
- Import toutes les {parseInt(form.fetch_interval_minutes || "1440") >= 60
- ? `${parseInt(form.fetch_interval_minutes || "1440") / 60}h`
- : `${form.fetch_interval_minutes || "1440"} min`}
+ Import toutes les {(form.fetch_interval_minutes || "1440") === "60" ? "heure" : `${parseInt(form.fetch_interval_minutes || "1440") / 60} heures`}
)}
diff --git a/server/_core/index.ts b/server/_core/index.ts
index ee3955a..94531cc 100644
--- a/server/_core/index.ts
+++ b/server/_core/index.ts
@@ -35,46 +35,27 @@ let cronJob: ReturnType
| null = null;
export async function scheduleDailyImport() {
const importTime = (await getSetting("import_time")) || "06:00";
- const fetchMode = (await getSetting("fetch_mode")) || "daily";
+ const fetchMode = (await getSetting("fetch_mode")) || "scheduled";
const fetchIntervalMinutes = parseInt((await getSetting("fetch_interval_minutes")) || "1440", 10);
- const fetchWeekDay = (await getSetting("fetch_week_day")) || "1"; // 0=dim, 1=lun, ..., 6=sam
- const fetchMonthDay = (await getSetting("fetch_month_day")) || "1"; // 1-28
-
- const [hour, minute] = importTime.split(":").map(Number);
- const h = hour ?? 6;
- const m = minute ?? 0;
let cronExpr: string;
- let cronLabel: string;
-
if (fetchMode === "interval") {
const intervalMin = Math.max(60, fetchIntervalMinutes);
- if (intervalMin % 60 === 0) {
+ if (intervalMin < 60) {
+ cronExpr = `*/${intervalMin} * * * *`;
+ } else if (intervalMin % 60 === 0) {
const hours = intervalMin / 60;
- cronExpr = hours === 24 ? `0 ${m} ${h} * * *` : `0 ${m} */${hours} * * *`;
+ cronExpr = hours === 24 ? `0 0 * * *` : `0 */${hours} * * *`;
} else {
- cronExpr = `0 */${intervalMin} * * * *`;
+ cronExpr = `*/${intervalMin} * * * *`;
}
- const hours = intervalMin / 60;
- cronLabel = `Mode intervalle — toutes les ${hours >= 1 ? hours + "h" : intervalMin + "min"} (${cronExpr})`;
- } else if (fetchMode === "weekly") {
- // hebdomadaire : le jour choisi à l'heure choisie
- cronExpr = `0 ${m} ${h} * * ${fetchWeekDay}`;
- const jours = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"];
- cronLabel = `Mode hebdomadaire — chaque ${jours[parseInt(fetchWeekDay)] ?? "lundi"} à ${importTime} (${cronExpr})`;
- } else if (fetchMode === "monthly") {
- // mensuel : le jour du mois choisi à l'heure choisie
- const day = Math.min(28, Math.max(1, parseInt(fetchMonthDay)));
- cronExpr = `0 ${m} ${h} ${day} * *`;
- cronLabel = `Mode mensuel — le ${day} de chaque mois à ${importTime} (${cronExpr})`;
+ console.log(`[Cron] Mode intervalle — toutes les ${intervalMin} minutes (${cronExpr})`);
} else {
- // daily (défaut)
- cronExpr = `0 ${m} ${h} * * *`;
- cronLabel = `Mode quotidien — tous les jours à ${importTime} (${cronExpr})`;
+ const [hour, minute] = importTime.split(":").map(Number);
+ cronExpr = `0 ${minute ?? 0} ${hour ?? 6} * * *`;
+ console.log(`[Cron] Mode heure fixe — tous les jours à ${importTime} (${cronExpr})`);
}
- console.log(`[Cron] ${cronLabel}`);
-
if (cronJob) {
cronJob.stop();
cronJob = null;
diff --git a/server/routers.ts b/server/routers.ts
index 5652515..01a84c2 100644
--- a/server/routers.ts
+++ b/server/routers.ts
@@ -372,10 +372,8 @@ export const appRouter = router({
sharepoint_token: z.string().optional(),
auth_mode: z.enum(["local", "free"]).optional(),
import_time: z.string().optional(),
- fetch_mode: z.enum(["daily", "weekly", "monthly", "interval", "scheduled"]).optional(),
+ fetch_mode: z.enum(["scheduled", "interval"]).optional(),
fetch_interval_minutes: z.string().optional(),
- fetch_week_day: z.string().optional(),
- fetch_month_day: z.string().optional(),
})
)
.mutation(async ({ input }) => {
@@ -385,7 +383,7 @@ export const appRouter = router({
}
await setSettings(toSave);
// Recharger le cron si la planification a changé
- if (toSave.import_time || toSave.fetch_mode || toSave.fetch_interval_minutes || toSave.fetch_week_day || toSave.fetch_month_day) {
+ if (toSave.import_time || toSave.fetch_mode || toSave.fetch_interval_minutes) {
await scheduleDailyImport();
}
return { success: true };
diff --git a/server/rssEngine.ts b/server/rssEngine.ts
index 9d4bf21..e1e3b34 100644
--- a/server/rssEngine.ts
+++ b/server/rssEngine.ts
@@ -203,11 +203,29 @@ export function detectVeilleNiveauTerritoire(text: string): { niveau: VeilleNive
// ─── Extraction automatique pour les AAP ─────────────────────────────────────
+/**
+ * Détecte le niveau de localisation le plus fin dans le texte :
+ * - Département AuRA si mentionné → region = "Auvergne-Rhône-Alpes", departement = "Nom (num)"
+ * - Région AuRA si mentionnée → region = "Auvergne-Rhône-Alpes", departement = null
+ * - Sinon → region = "National", departement = null
+ */
export function detectAapGeo(text: string): { region: string; departement: string | null } {
const dept = detectDepartment(text);
+ if (dept) {
+ return {
+ region: "Auvergne-Rhône-Alpes",
+ departement: `${dept.name} (${dept.num})`,
+ };
+ }
+ if (isRegional(text)) {
+ return {
+ region: "Auvergne-Rhône-Alpes",
+ departement: null,
+ };
+ }
return {
- region: "Auvergne-Rhône-Alpes",
- departement: dept ? `${dept.name} (${dept.num})` : null,
+ region: "National",
+ departement: null,
};
}
diff --git a/todo.md b/todo.md
index 3666b0d..5759101 100644
--- a/todo.md
+++ b/todo.md
@@ -182,8 +182,3 @@
- [x] Backend routers.ts : exposer et sauvegarder ces deux nouveaux paramètres
- [x] Frontend Settings.tsx : sélecteur mode (heure fixe / intervalle) + sélecteur intervalle (1h, 2h, 4h, 6h, 12h, 24h)
- [x] Déployer en recette
-
-## Fréquence de planification enrichie
-- [x] Backend index.ts : générer l'expression cron selon quotidien/hebdomadaire (jour)/mensuel/intervalle
-- [x] Frontend Settings.tsx : sélecteur fréquence (quotidien, hebdo + jour, mensuel, intervalle) + heure
-- [ ] Déployer en recette