Email de test et ajout manuel sans champ obligatoire
ci-cd / build-backend (push) Successful in 1m25s
ci-cd / build-frontend (push) Successful in 21s
ci-cd / deploy (push) Successful in 13s

Étape 67 : adresse + bouton dans l'onglet « Messages » pour envoyer tout
de suite un email de test, résultat réel affiché (envoyé, désactivé,
connexion ou message refusé, réponse du serveur SMTP) —
POST .../notifications/test.

Étape 66 : prénom et nom facultatifs à l'ajout manuel d'un bénévole ;
un bénévole sans nom s'affiche « Sans nom » / « ? » partout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AdamThomas
2026-10-28 19:34:24 +01:00
co-authored by Claude Opus 5.5
parent 5c2cc0a6c3
commit 461742eb78
22 changed files with 346 additions and 28 deletions
+35 -1
View File
@@ -4,18 +4,22 @@ import logging
import uuid
from collections import defaultdict
from fastapi import APIRouter, BackgroundTasks, Depends
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
from sqlmodel import Session, select
from app.api.deps import get_edition
from app.api.schemas import (
PlanningNotificationRequest,
PlanningNotificationResult,
TestEmailRequest,
TestEmailResult,
)
from app.auth.deps import require_coordinator
from app.auth.magic_link import build_magic_link_url, issue_magic_link_token
from app.config import get_settings
from app.db import get_session
from app.email import edition_logo, render_planning, send_many
from app.email.sender import build_message, deliver_test
from app.i18n import t
from app.models import Account, Assignment, Edition, Position, Shift, Volunteer
@@ -41,6 +45,36 @@ def _login_link(session: Session, edition: Edition, volunteer: Volunteer) -> str
return build_magic_link_url(issue_magic_link_token(session, account))
@router.post("/test", response_model=TestEmailResult)
def send_test_email(
payload: TestEmailRequest,
edition: Edition = Depends(get_edition),
_guard: Account = Depends(require_coordinator),
session: Session = Depends(get_session),
) -> TestEmailResult:
"""Envoie tout de suite un email de test à l'adresse saisie (même mise
en forme et même logo que les vrais emails) et renvoie le résultat réel
du serveur SMTP — pour vérifier la configuration depuis l'écran
« Messages » sans accès au serveur (`python -m app.email.check`)."""
email = payload.email.strip()
if "@" not in email or email.startswith("@") or email.endswith("@") or " " in email:
raise HTTPException(status_code=422, detail={"code": "notifications.invalid_email"})
message = build_message(
email,
t("email.test.subject"),
t("email.test.body", edition=edition.name or str(edition.year)),
logo=edition_logo(session, edition.id),
)
status, detail = deliver_test(message)
settings = get_settings()
return TestEmailResult(
status=status,
detail=detail,
smtp_host=f"{settings.smtp_host}:{settings.smtp_port}",
smtp_from=settings.smtp_from,
)
@router.post("/planning", response_model=PlanningNotificationResult)
def send_planning_notification(
payload: PlanningNotificationRequest,