feat: date de début de lecture emails dans paramètres import
This commit is contained in:
@@ -51,6 +51,8 @@ export default function ImportSettings() {
|
|||||||
const [emailImportHost, setEmailImportHost] = useState("");
|
const [emailImportHost, setEmailImportHost] = useState("");
|
||||||
const [emailImportPort, setEmailImportPort] = useState(993);
|
const [emailImportPort, setEmailImportPort] = useState(993);
|
||||||
const [emailImportFrequency, setEmailImportFrequency] = useState(30);
|
const [emailImportFrequency, setEmailImportFrequency] = useState(30);
|
||||||
|
// Date de début de lecture des emails (string ISO "YYYY-MM-DD" pour le champ <input type="date">)
|
||||||
|
const [emailImportSinceDate, setEmailImportSinceDate] = useState("");
|
||||||
|
|
||||||
// Export folder
|
// Export folder
|
||||||
const [exportFolder, setExportFolder] = useState("");
|
const [exportFolder, setExportFolder] = useState("");
|
||||||
@@ -77,6 +79,13 @@ export default function ImportSettings() {
|
|||||||
setEmailImportHost(settings.emailImportHost || "");
|
setEmailImportHost(settings.emailImportHost || "");
|
||||||
setEmailImportPort(settings.emailImportPort || 993);
|
setEmailImportPort(settings.emailImportPort || 993);
|
||||||
setEmailImportFrequency(settings.emailImportFrequency || 30);
|
setEmailImportFrequency(settings.emailImportFrequency || 30);
|
||||||
|
// Convertir le timestamp Unix (s) en string ISO pour l'input date
|
||||||
|
if ((settings as any).emailImportSinceDate) {
|
||||||
|
const d = new Date((settings as any).emailImportSinceDate * 1000);
|
||||||
|
setEmailImportSinceDate(d.toISOString().split('T')[0]);
|
||||||
|
} else {
|
||||||
|
setEmailImportSinceDate("");
|
||||||
|
}
|
||||||
setExportFolder(settings.exportFolder || "");
|
setExportFolder(settings.exportFolder || "");
|
||||||
const savedMode = (settings.bapExportMode as string) || "browser";
|
const savedMode = (settings.bapExportMode as string) || "browser";
|
||||||
setBapExportBrowser(savedMode === "browser" || savedMode === "both");
|
setBapExportBrowser(savedMode === "browser" || savedMode === "both");
|
||||||
@@ -136,6 +145,9 @@ export default function ImportSettings() {
|
|||||||
emailImportHost: emailImportHost || null,
|
emailImportHost: emailImportHost || null,
|
||||||
emailImportPort: emailImportPort,
|
emailImportPort: emailImportPort,
|
||||||
emailImportFrequency: emailImportFrequency,
|
emailImportFrequency: emailImportFrequency,
|
||||||
|
emailImportSinceDate: emailImportSinceDate
|
||||||
|
? Math.floor(new Date(emailImportSinceDate + 'T00:00:00Z').getTime() / 1000)
|
||||||
|
: null,
|
||||||
exportFolder: exportFolder || null,
|
exportFolder: exportFolder || null,
|
||||||
exportFolderType: exportFolderType,
|
exportFolderType: exportFolderType,
|
||||||
bapExportMode: computedExportMode() as "browser" | "folder" | "both",
|
bapExportMode: computedExportMode() as "browser" | "folder" | "both",
|
||||||
@@ -442,6 +454,27 @@ export default function ImportSettings() {
|
|||||||
className="h-11"
|
className="h-11"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="email-since-date" className="text-base font-medium">Ne pas lire les emails antérieurs au</Label>
|
||||||
|
<p className="text-sm text-muted-foreground">Les emails reçus avant cette date ne seront pas importés, même s'ils sont non lus. Laissez vide pour lire tous les emails non lus.</p>
|
||||||
|
<Input
|
||||||
|
id="email-since-date"
|
||||||
|
type="date"
|
||||||
|
value={emailImportSinceDate}
|
||||||
|
onChange={(e) => setEmailImportSinceDate(e.target.value)}
|
||||||
|
className="h-11"
|
||||||
|
/>
|
||||||
|
{emailImportSinceDate && (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="text-muted-foreground"
|
||||||
|
onClick={() => setEmailImportSinceDate("")}
|
||||||
|
>
|
||||||
|
Effacer la date limite
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="flex flex-wrap gap-3 pt-4 border-t border-green-200 dark:border-green-800">
|
<div className="flex flex-wrap gap-3 pt-4 border-t border-green-200 dark:border-green-800">
|
||||||
{emailServiceStatus?.isRunning ? (
|
{emailServiceStatus?.isRunning ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
1
drizzle/0026_perfect_richard_fisk.sql
Normal file
1
drizzle/0026_perfect_richard_fisk.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `importSettings` ADD `emailImportSinceDate` int;
|
||||||
1824
drizzle/meta/0026_snapshot.json
Normal file
1824
drizzle/meta/0026_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -183,6 +183,13 @@
|
|||||||
"when": 1778068255748,
|
"when": 1778068255748,
|
||||||
"tag": "0025_unknown_spencer_smythe",
|
"tag": "0025_unknown_spencer_smythe",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 26,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1780411851758,
|
||||||
|
"tag": "0026_perfect_richard_fisk",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -182,6 +182,7 @@ export const importSettings = mysqlTable("importSettings", {
|
|||||||
emailImportHost: varchar("emailImportHost", { length: 255 }), // IMAP server host
|
emailImportHost: varchar("emailImportHost", { length: 255 }), // IMAP server host
|
||||||
emailImportPort: int("emailImportPort").default(993), // IMAP port (default: 993 for SSL)
|
emailImportPort: int("emailImportPort").default(993), // IMAP port (default: 993 for SSL)
|
||||||
emailImportFrequency: int("emailImportFrequency").default(30).notNull(), // Frequency in minutes (default: 30)
|
emailImportFrequency: int("emailImportFrequency").default(30).notNull(), // Frequency in minutes (default: 30)
|
||||||
|
emailImportSinceDate: int("emailImportSinceDate"), // Timestamp Unix (s) — ne pas lire les emails antérieurs à cette date
|
||||||
|
|
||||||
// Export folder settings
|
// Export folder settings
|
||||||
exportFolder: text("exportFolder"), // Path to folder for exporting invoices
|
exportFolder: text("exportFolder"), // Path to folder for exporting invoices
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ interface EmailImportConfig {
|
|||||||
password: string;
|
password: string;
|
||||||
host: string;
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
|
sinceDate?: number; // Unix timestamp (s) — ne pas lire les emails antérieurs à cette date
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store active intervals for each user
|
// Store active intervals for each user
|
||||||
@@ -243,8 +244,17 @@ async function checkEmailsForPDFs(config: EmailImportConfig): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for unread emails
|
// Build search criteria: unread emails, optionally filtered by date
|
||||||
imap.search(["UNSEEN"], (err, results) => {
|
const searchCriteria: any[] = ["UNSEEN"];
|
||||||
|
if (config.sinceDate) {
|
||||||
|
// IMAP SINCE expects a date string like "1-Jan-2026"
|
||||||
|
const since = new Date(config.sinceDate * 1000);
|
||||||
|
const months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||||
|
const sinceStr = `${since.getDate()}-${months[since.getMonth()]}-${since.getFullYear()}`;
|
||||||
|
searchCriteria.push(["SINCE", sinceStr]);
|
||||||
|
console.log(`[EmailImport] Filtering emails since ${sinceStr} for user ${config.userId}`);
|
||||||
|
}
|
||||||
|
imap.search(searchCriteria, (err, results) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("[EmailImport] Error searching emails:", err);
|
console.error("[EmailImport] Error searching emails:", err);
|
||||||
imap.end();
|
imap.end();
|
||||||
@@ -397,6 +407,7 @@ export async function startEmailImportService(userId: number): Promise<boolean>
|
|||||||
password: settings.emailImportPassword,
|
password: settings.emailImportPassword,
|
||||||
host: settings.emailImportHost,
|
host: settings.emailImportHost,
|
||||||
port: settings.emailImportPort || 993,
|
port: settings.emailImportPort || 993,
|
||||||
|
sinceDate: settings.emailImportSinceDate ?? undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
const frequencyMs = (settings.emailImportFrequency || 30) * 60 * 1000; // Convert minutes to milliseconds
|
const frequencyMs = (settings.emailImportFrequency || 30) * 60 * 1000; // Convert minutes to milliseconds
|
||||||
@@ -468,6 +479,7 @@ export async function triggerEmailCheck(userId: number): Promise<{ success: bool
|
|||||||
password: settings.emailImportPassword,
|
password: settings.emailImportPassword,
|
||||||
host: settings.emailImportHost,
|
host: settings.emailImportHost,
|
||||||
port: settings.emailImportPort || 993,
|
port: settings.emailImportPort || 993,
|
||||||
|
sinceDate: settings.emailImportSinceDate ?? undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`[EmailImport] Manual check triggered for user ${userId}`);
|
console.log(`[EmailImport] Manual check triggered for user ${userId}`);
|
||||||
|
|||||||
@@ -1566,6 +1566,7 @@ export const appRouter = router({
|
|||||||
emailImportHost: z.string().nullable().optional(),
|
emailImportHost: z.string().nullable().optional(),
|
||||||
emailImportPort: z.number().min(1).max(65535).optional(),
|
emailImportPort: z.number().min(1).max(65535).optional(),
|
||||||
emailImportFrequency: z.number().min(1).optional(),
|
emailImportFrequency: z.number().min(1).optional(),
|
||||||
|
emailImportSinceDate: z.number().nullable().optional(), // Unix timestamp (s)
|
||||||
exportFolder: z.string().nullable().optional(),
|
exportFolder: z.string().nullable().optional(),
|
||||||
exportFolderType: z.enum(["local", "teams", "sharepoint"]).optional(),
|
exportFolderType: z.enum(["local", "teams", "sharepoint"]).optional(),
|
||||||
bapExportMode: z.enum(["browser", "folder", "both"]).optional(),
|
bapExportMode: z.enum(["browser", "folder", "both"]).optional(),
|
||||||
|
|||||||
Reference in New Issue
Block a user