Checkpoint: OAuth2 IMAP pour Office 365 : ajout du mode d'authentification OAuth2 pour l'import email (Azure AD Client Credentials), sélecteur basic/oauth2 dans l'UI, bouton "Tester la connexion IMAP", procédure testEmailConnection dans le router. Migration DB emailImportAuthMode appliquée.

This commit is contained in:
Manus
2026-06-05 05:54:21 -04:00
parent 22515e5414
commit 4ef130f21d
9 changed files with 2256 additions and 17 deletions

View File

@@ -35,6 +35,7 @@ export default function ImportSettings() {
const stopFolderServiceMutation = trpc.folderImportService.stop.useMutation();
const testAzureConnectionMutation = trpc.importSettings.testAzureConnection.useMutation();
const testSharePointUploadMutation = trpc.importSettings.testSharePointUpload.useMutation();
const testEmailConnectionMutation = trpc.importSettings.testEmailConnection.useMutation();
// Manual import
const [manualImportEnabled, setManualImportEnabled] = useState(true);
@@ -48,6 +49,7 @@ export default function ImportSettings() {
const [emailImportEnabled, setEmailImportEnabled] = useState(false);
const [emailImportAddress, setEmailImportAddress] = useState("");
const [emailImportPassword, setEmailImportPassword] = useState("");
const [emailImportAuthMode, setEmailImportAuthMode] = useState<"basic" | "oauth2">("basic");
const [emailImportHost, setEmailImportHost] = useState("");
const [emailImportPort, setEmailImportPort] = useState(993);
const [emailImportFrequency, setEmailImportFrequency] = useState(30);
@@ -76,6 +78,7 @@ export default function ImportSettings() {
setEmailImportEnabled(settings.emailImportEnabled === 1);
setEmailImportAddress(settings.emailImportAddress || "");
setEmailImportPassword(settings.emailImportPassword || "");
setEmailImportAuthMode(((settings as any).emailImportAuthMode as "basic" | "oauth2") || "basic");
setEmailImportHost(settings.emailImportHost || "");
setEmailImportPort(settings.emailImportPort || 993);
setEmailImportFrequency(settings.emailImportFrequency || 30);
@@ -148,6 +151,7 @@ export default function ImportSettings() {
emailImportSinceDate: emailImportSinceDate
? Math.floor(new Date(emailImportSinceDate + 'T00:00:00Z').getTime() / 1000)
: null,
emailImportAuthMode: emailImportAuthMode,
exportFolder: exportFolder || null,
exportFolderType: exportFolderType,
bapExportMode: computedExportMode() as "browser" | "folder" | "both",
@@ -396,6 +400,40 @@ export default function ImportSettings() {
{emailImportEnabled && (
<div className="space-y-4 p-4 bg-green-50/50 dark:bg-green-950/10 rounded-lg border-2 border-green-200 dark:border-green-800">
{/* Mode d'authentification */}
<div className="space-y-2">
<Label className="text-base font-medium">Mode d'authentification IMAP</Label>
<div className="flex gap-3">
<button
type="button"
onClick={() => setEmailImportAuthMode("basic")}
className={`flex-1 py-2 px-4 rounded-lg border-2 text-sm font-medium transition-colors ${
emailImportAuthMode === "basic"
? "border-blue-500 bg-blue-50 text-blue-700 dark:bg-blue-950/30 dark:text-blue-300"
: "border-muted bg-muted/30 text-muted-foreground hover:border-blue-300"
}`}
>
Basique (login/mot de passe)
</button>
<button
type="button"
onClick={() => setEmailImportAuthMode("oauth2")}
className={`flex-1 py-2 px-4 rounded-lg border-2 text-sm font-medium transition-colors ${
emailImportAuthMode === "oauth2"
? "border-purple-500 bg-purple-50 text-purple-700 dark:bg-purple-950/30 dark:text-purple-300"
: "border-muted bg-muted/30 text-muted-foreground hover:border-purple-300"
}`}
>
OAuth2 (Office 365 / Azure AD)
</button>
</div>
{emailImportAuthMode === "oauth2" && (
<div className="p-3 bg-purple-50 dark:bg-purple-950/20 rounded-lg border border-purple-200 dark:border-purple-800 text-sm text-purple-700 dark:text-purple-300">
<strong>Office 365 :</strong> Microsoft a désactivé l'auth basique pour Exchange Online. Utilisez ce mode avec les credentials Azure AD déjà configurés dans l'onglet Export.
</div>
)}
</div>
<div className="space-y-2">
<Label htmlFor="email-address" className="text-base font-medium">Adresse email</Label>
<Input
@@ -407,6 +445,7 @@ export default function ImportSettings() {
className="h-11"
/>
</div>
{emailImportAuthMode === "basic" && (
<div className="space-y-2">
<Label htmlFor="email-password" className="text-base font-medium">Mot de passe</Label>
<Input
@@ -418,6 +457,13 @@ export default function ImportSettings() {
className="h-11"
/>
</div>
)}
{emailImportAuthMode === "oauth2" && (
<div className="p-3 bg-muted/30 rounded-lg border text-sm text-muted-foreground">
<Wifi className="inline h-4 w-4 mr-1" />
En mode OAuth2, les credentials Azure AD (Tenant ID, Client ID, Client Secret) configurés dans l'onglet <strong>Export &gt; SharePoint</strong> seront utilisés automatiquement.
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="email-host" className="text-base font-medium">Serveur IMAP</Label>
@@ -475,6 +521,34 @@ export default function ImportSettings() {
</Button>
)}
</div>
{/* Bouton test connexion IMAP */}
<div className="pt-2">
<Button
variant="outline"
onClick={async () => {
try {
toast.info("Test de connexion IMAP en cours...");
const result = await testEmailConnectionMutation.mutateAsync();
if (result.success) {
toast.success(result.message);
} else {
toast.error(result.message, { duration: 8000 });
}
} catch (e: any) {
toast.error("Erreur : " + (e?.message || "inconnue"));
}
}}
disabled={testEmailConnectionMutation.isPending}
className="border-blue-300 hover:bg-blue-50 dark:hover:bg-blue-950/20"
>
{testEmailConnectionMutation.isPending
? <><Loader2 className="mr-2 h-4 w-4 animate-spin" />Test en cours...</>
: <><Wifi className="mr-2 h-4 w-4" />Tester la connexion IMAP</>
}
</Button>
<p className="text-xs text-muted-foreground mt-1">Vérifie que la connexion au serveur IMAP est fonctionnelle (sans importer d'emails)</p>
</div>
<div className="flex flex-wrap gap-3 pt-4 border-t border-green-200 dark:border-green-800">
{emailServiceStatus?.isRunning ? (
<>