"""Envoi des emails de définition / réinitialisation de mot de passe.""" from __future__ import annotations import json import os from datetime import datetime from pathlib import Path from urllib.parse import quote from src.email_sender import send_email _ROOT = Path(__file__).resolve().parent.parent _DATA_DIR = Path(os.getenv("DATA_DIR", str(_ROOT / "data"))) _SETTINGS_PATH = _DATA_DIR / "settings.json" _TEMPLATES_DIR = _DATA_DIR / "email_templates" def _load_settings() -> dict: if _SETTINGS_PATH.exists(): try: return json.loads(_SETTINGS_PATH.read_text(encoding="utf-8")) except Exception: return {} return {} def _read_template(name: str) -> str: path = _TEMPLATES_DIR / name if not path.exists(): raise FileNotFoundError( f"Template manquant : {path}. Créez data/email_templates/{name}." ) return path.read_text(encoding="utf-8") def _read_optional_template(name: str) -> str | None: path = _TEMPLATES_DIR / name if not path.exists(): return None return path.read_text(encoding="utf-8") def _format_expiry(dt: datetime) -> str: return dt.strftime("%d.%m.%Y à %H:%M") def _format_ttl_human(dt: datetime) -> str: """Renvoie 'dans X h' ou 'dans X jours'.""" delta = dt - datetime.now() total_seconds = max(0, int(delta.total_seconds())) if total_seconds < 3600: mins = total_seconds // 60 return f"valable {mins} minute{'s' if mins > 1 else ''}" hours = total_seconds // 3600 if hours < 48: return f"valable {hours} heure{'s' if hours > 1 else ''}" days = hours // 24 return f"valable {days} jour{'s' if days > 1 else ''}" def send_password_email( *, kind: str, # "welcome" | "reset" username: str, name: str, email: str, token: str, expires_at: datetime, ) -> None: """Envoie un email de définition (kind='welcome') ou de reset (kind='reset'). Lève une exception en cas d'erreur (SMTP, template manquant, base_url manquante). """ if kind not in ("welcome", "reset"): raise ValueError(f"kind must be 'welcome' or 'reset', got {kind!r}") if not email or "@" not in email: raise ValueError(f"Email invalide pour {username!r}") settings = _load_settings() base_url = (settings.get("app_base_url") or "").rstrip("/") if not base_url: raise ValueError( "URL de base manquante. Configurez `app_base_url` dans Paramètres." ) smtp_host = settings.get("smtp_host") smtp_port = int(settings.get("smtp_port") or 587) smtp_login = settings.get("smtp_login") smtp_password = settings.get("smtp_password") smtp_sender = settings.get("smtp_sender") if not (smtp_host and smtp_login and smtp_password and smtp_sender): raise ValueError( "Configuration SMTP incomplète. Vérifiez Paramètres → SMTP." ) link = f"{base_url}/password-set?token={quote(token)}" vars_ = { "name": name, "username": username, "link": link, "expiry": _format_expiry(expires_at), "ttl_human": _format_ttl_human(expires_at), } template_text_name = "welcome.txt" if kind == "welcome" else "reset.txt" template_html_name = "welcome.html" if kind == "welcome" else "reset.html" body_text = _read_template(template_text_name).format_map(vars_) html_raw = _read_optional_template(template_html_name) body_html = html_raw.format_map(vars_) if html_raw else None subject = ( "EPTM Dashboard — Définissez votre mot de passe" if kind == "welcome" else "EPTM Dashboard — Réinitialisation de votre mot de passe" ) send_email( smtp_host=smtp_host, smtp_port=smtp_port, smtp_login=smtp_login, smtp_password=smtp_password, smtp_sender=smtp_sender, to_email=email, subject=subject, body=body_text, body_html=body_html, attachments=None, )