c228f7be55
Le lien de vérification pointait vers la page Dash /verification-email (qui se contente de rediriger vers /connexion) au lieu de la route backend /auth/verify-email qui consomme réellement le token et marque l'email comme vérifié. Conséquence : l'email n'était jamais validé et le login renvoyait email_not_verified en boucle. Ajoute aussi MAIL_SUPPRESS_SEND=true au bloc env de pytest : sans cela, le load_dotenv() de src.app injectait MAIL_SUPPRESS_SEND=false depuis le .env local, désactivant la suppression d'envoi et faisant échouer les tests d'auth qui envoient un email (selon l'ordre d'import). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
88 lines
2.6 KiB
Python
88 lines
2.6 KiB
Python
import os
|
|
from pathlib import Path
|
|
|
|
from flask import Flask, render_template
|
|
from flask_mail import Mail, Message
|
|
|
|
from src.utils import logger
|
|
|
|
TEMPLATES_DIR = Path(__file__).parent / "templates"
|
|
|
|
_mail: Mail | None = None
|
|
|
|
|
|
def init_mailer(app: Flask) -> None:
|
|
global _mail
|
|
app.config["MAIL_SERVER"] = os.getenv("SMTP_HOST", "")
|
|
app.config["MAIL_PORT"] = int(os.getenv("SMTP_PORT", "587"))
|
|
app.config["MAIL_USERNAME"] = os.getenv("SMTP_USERNAME") or None
|
|
app.config["MAIL_PASSWORD"] = os.getenv("SMTP_PASSWORD") or None
|
|
app.config["MAIL_USE_TLS"] = os.getenv("SMTP_USE_TLS", "True").lower() == "true"
|
|
app.config["MAIL_DEFAULT_SENDER"] = os.getenv("MAIL_FROM", "noreply@decp.info")
|
|
app.config["MAIL_SUPPRESS_SEND"] = (
|
|
os.getenv("MAIL_SUPPRESS_SEND", os.getenv("DEVELOPMENT", "False")).lower()
|
|
== "true"
|
|
)
|
|
# Inclure les templates du package auth dans la recherche Jinja
|
|
if hasattr(app.jinja_loader, "searchpath"):
|
|
app.jinja_loader.searchpath.append(str(TEMPLATES_DIR))
|
|
else:
|
|
import jinja2
|
|
|
|
app.jinja_loader = jinja2.ChoiceLoader(
|
|
[app.jinja_loader, jinja2.FileSystemLoader(str(TEMPLATES_DIR))]
|
|
)
|
|
_mail = Mail(app)
|
|
|
|
|
|
def _base_url() -> str:
|
|
return os.getenv("APP_BASE_URL", "http://localhost:8050").rstrip("/")
|
|
|
|
|
|
def _send(
|
|
subject: str,
|
|
recipient: str,
|
|
txt_template: str,
|
|
html_template: str,
|
|
**ctx,
|
|
) -> None:
|
|
assert _mail is not None, "Mailer non initialisé (init_mailer(app) non appelé)"
|
|
if _mail.suppress:
|
|
suppress_cause = (
|
|
"MAIL_SUPPRESS_SEND=true"
|
|
if os.getenv("MAIL_SUPPRESS_SEND") is not None
|
|
else "DEVELOPMENT=true"
|
|
)
|
|
logger.warning(
|
|
"Email supprimé (%s) — non envoyé à %s : %s",
|
|
suppress_cause,
|
|
recipient,
|
|
subject,
|
|
)
|
|
msg = Message(subject=subject, recipients=[recipient])
|
|
msg.body = render_template(txt_template, **ctx)
|
|
msg.html = render_template(html_template, **ctx)
|
|
_mail.send(msg)
|
|
|
|
|
|
def send_verification_email(email: str, token: str) -> None:
|
|
link = f"{_base_url()}/auth/verify-email?token={token}"
|
|
_send(
|
|
"Vérification de votre adresse email — decp.info",
|
|
email,
|
|
"emails/verify_email.txt",
|
|
"emails/verify_email.html",
|
|
link=link,
|
|
)
|
|
|
|
|
|
def send_reset_email(email: str, token: str) -> None:
|
|
link = f"{_base_url()}/reinitialiser-mot-de-passe?token={token}"
|
|
_send(
|
|
"Réinitialisation de votre mot de passe — decp.info",
|
|
email,
|
|
"emails/reset_password.txt",
|
|
"emails/reset_password.html",
|
|
link=link,
|
|
)
|