feat(settings/smtp): bouton Test SMTP dans Settings (envoi mail HTML pro a destinataire)
- Endpoint POST /settings/smtp/test (Form 'recipient', defaut kalid.moutaouakil@gmail.com) envoie un mail HTML pro confirmant que SMTP fonctionne (header bleu degrade, metadonnees envoyeur/date/destinataire en card) - UI Settings > SMTP: champ destinataire test pre-rempli + bouton 'Envoyer test' AJAX sans reload, status vert/rouge en dessous - Reuse send_html_mail du mail_service
This commit is contained in:
parent
98d0ad0a3d
commit
bfd91634bb
@ -238,6 +238,61 @@ async def settings_save(request: Request, section: str, db=Depends(get_db)):
|
|||||||
return templates.TemplateResponse("settings.html", ctx)
|
return templates.TemplateResponse("settings.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/settings/smtp/test")
|
||||||
|
async def settings_smtp_test(request: Request, db=Depends(get_db),
|
||||||
|
recipient: str = Form("kalid.moutaouakil@gmail.com")):
|
||||||
|
"""Envoie un mail test à `recipient` pour valider la config SMTP."""
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
user = get_current_user(request)
|
||||||
|
if not user:
|
||||||
|
return JSONResponse({"ok": False, "msg": "Non authentifié"}, status_code=401)
|
||||||
|
perms = get_user_perms(db, user)
|
||||||
|
if not can_edit(perms, "settings"):
|
||||||
|
return JSONResponse({"ok": False, "msg": "Permission refusée"}, status_code=403)
|
||||||
|
to = (recipient or "").strip()
|
||||||
|
if not to:
|
||||||
|
return JSONResponse({"ok": False, "msg": "Destinataire vide"}, status_code=400)
|
||||||
|
|
||||||
|
sender = user.get("sub") or user.get("username") or "PatchCenter"
|
||||||
|
from datetime import datetime as _dt
|
||||||
|
now_str = _dt.now().strftime("%d/%m/%Y %H:%M:%S")
|
||||||
|
|
||||||
|
subject = f"[PatchCenter] Test SMTP — {now_str}"
|
||||||
|
html = f"""<!DOCTYPE html><html><body style="font-family:'Segoe UI',Arial,sans-serif;background:#f3f4f6;padding:24px;">
|
||||||
|
<table role="presentation" width="600" cellspacing="0" cellpadding="0" style="background:#fff;border-radius:8px;margin:0 auto;box-shadow:0 1px 3px rgba(0,0,0,.08);">
|
||||||
|
<tr><td style="background:linear-gradient(90deg,#1e3a8a 0%,#1e40af 100%);padding:20px 28px;color:#fff;border-radius:8px 8px 0 0;">
|
||||||
|
<div style="font-size:11px;letter-spacing:0.15em;text-transform:uppercase;opacity:0.85;">SANEF — SecOps · PatchCenter</div>
|
||||||
|
<h1 style="margin:6px 0 0;font-size:20px;font-weight:600;">✅ Test SMTP réussi</h1>
|
||||||
|
</td></tr>
|
||||||
|
<tr><td style="padding:24px 28px;color:#1f2937;font-size:14px;line-height:1.6;">
|
||||||
|
<p>Bonjour,</p>
|
||||||
|
<p>Ce mail confirme que la configuration SMTP de <strong>PatchCenter</strong> fonctionne correctement.</p>
|
||||||
|
<table role="presentation" width="100%" cellspacing="0" cellpadding="0"
|
||||||
|
style="border-left:4px solid #2563eb;background:#eff6ff;border-radius:4px;margin:16px 0;">
|
||||||
|
<tr><td style="padding:14px 18px;">
|
||||||
|
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="font-size:13px;">
|
||||||
|
<tr><td style="padding:3px 0;color:#6b7280;font-weight:600;width:40%;">Envoyé par :</td>
|
||||||
|
<td style="padding:3px 0;color:#1f2937;">{sender}</td></tr>
|
||||||
|
<tr><td style="padding:3px 0;color:#6b7280;font-weight:600;">Date d'envoi :</td>
|
||||||
|
<td style="padding:3px 0;color:#1f2937;">{now_str}</td></tr>
|
||||||
|
<tr><td style="padding:3px 0;color:#6b7280;font-weight:600;">Destinataire :</td>
|
||||||
|
<td style="padding:3px 0;color:#1f2937;">{to}</td></tr>
|
||||||
|
</table>
|
||||||
|
</td></tr>
|
||||||
|
</table>
|
||||||
|
<p style="color:#6b7280;font-size:13px;">Tu peux maintenant utiliser le bouton "Prévenance PCT" sur la page d'import patching.</p>
|
||||||
|
<p style="margin:24px 0 0;color:#6b7280;font-size:13px;">Cordialement,<br>L'équipe SecOps SANEF</p>
|
||||||
|
</td></tr>
|
||||||
|
<tr><td style="background:#f9fafb;padding:12px 28px;border-top:1px solid #e5e7eb;color:#9ca3af;font-size:11px;border-radius:0 0 8px 8px;">
|
||||||
|
Mail de test généré par <strong>PatchCenter</strong> via <code>/settings/smtp/test</code>.
|
||||||
|
</td></tr>
|
||||||
|
</table></body></html>"""
|
||||||
|
|
||||||
|
from ..services.mail_service import send_html_mail
|
||||||
|
res = send_html_mail(db, to=[to], subject=subject, html=html)
|
||||||
|
return JSONResponse(res)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/settings/ldap/test")
|
@router.post("/settings/ldap/test")
|
||||||
async def settings_ldap_test(request: Request, db=Depends(get_db)):
|
async def settings_ldap_test(request: Request, db=Depends(get_db)):
|
||||||
"""Teste la connexion LDAP avec le compte de bind."""
|
"""Teste la connexion LDAP avec le compte de bind."""
|
||||||
|
|||||||
@ -709,6 +709,46 @@
|
|||||||
</p>
|
</p>
|
||||||
{% if editable.smtp %}<button type="submit" class="btn-primary px-4 py-2 text-sm">Sauvegarder</button>{% endif %}
|
{% if editable.smtp %}<button type="submit" class="btn-primary px-4 py-2 text-sm">Sauvegarder</button>{% endif %}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{% if editable.smtp %}
|
||||||
|
<div class="mt-4 pt-3 border-t border-cyber-border">
|
||||||
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2">Test envoi SMTP</h4>
|
||||||
|
<div class="flex gap-2 items-end">
|
||||||
|
<div class="flex-1">
|
||||||
|
<label class="text-xs text-gray-500">Destinataire test</label>
|
||||||
|
<input type="text" id="smtp-test-recipient" value="kalid.moutaouakil@gmail.com" class="w-full">
|
||||||
|
</div>
|
||||||
|
<button type="button" id="smtp-test-btn" class="btn-sm bg-cyber-blue/20 text-cyber-blue px-4 py-2 text-xs whitespace-nowrap">📤 Envoyer test</button>
|
||||||
|
</div>
|
||||||
|
<div id="smtp-test-status" class="text-xs mt-2"></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
(function(){
|
||||||
|
const btn = document.getElementById('smtp-test-btn');
|
||||||
|
const inp = document.getElementById('smtp-test-recipient');
|
||||||
|
const out = document.getElementById('smtp-test-status');
|
||||||
|
if (!btn) return;
|
||||||
|
btn.addEventListener('click', async () => {
|
||||||
|
const to = (inp.value || '').trim();
|
||||||
|
if (!to) { alert('Renseigne un destinataire.'); return; }
|
||||||
|
btn.disabled = true; btn._txt = btn.textContent; btn.textContent = '⏳ Envoi…';
|
||||||
|
out.innerHTML = '<span class="text-cyber-yellow">⏳ Envoi en cours…</span>';
|
||||||
|
try {
|
||||||
|
const fd = new FormData(); fd.append('recipient', to);
|
||||||
|
const r = await fetch('/settings/smtp/test', {method:'POST', credentials:'same-origin', body:fd});
|
||||||
|
const j = await r.json();
|
||||||
|
out.innerHTML = j.ok
|
||||||
|
? `<span class="text-cyber-green">✅ ${j.msg || 'Envoyé'}</span>`
|
||||||
|
: `<span class="text-cyber-red">❌ ${j.msg || 'Échec'}</span>`;
|
||||||
|
} catch (e) {
|
||||||
|
out.innerHTML = `<span class="text-cyber-red">❌ Erreur réseau : ${e}</span>`;
|
||||||
|
} finally {
|
||||||
|
btn.disabled = false; btn.textContent = btn._txt || '📤 Envoyer test';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user