Étape 8 : connexion par mot de passe pour la coordination
Deux systèmes d'authentification, une même session JWT :
- COORDINATION : login e-mail + mot de passe (bcrypt), POST .../auth/login ;
POST .../auth/change-password pour le compte courant
- RÉFÉRENTS / BÉNÉVOLES : lien magique inchangé, mais refusé pour un compte
qui a un mot de passe
- Account.password_hash (nullable) + migration 0002 ; propriété auth_method
("password" / "magic_link") exposée dans AccountRead
- app/auth/passwords.py : hash/verify bcrypt, longueur mini 10
- Création de compte : password requis pour COORDINATOR, interdit sinon
- seed : la coordination de démo a un mot de passe, affiché dans le résumé
- 12 tests (login ok/ko, séparation des deux systèmes, change-password,
validation à la création) ; 129 tests au total ; alembic check vert
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
1f9f460540
commit
8a879ca5c3
@@ -13,6 +13,7 @@ from dataclasses import dataclass, field
|
||||
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.auth.passwords import hash_password
|
||||
from app.db import engine
|
||||
from app.importing.text import normalize
|
||||
from app.models import (
|
||||
@@ -47,6 +48,7 @@ from app.validation.loader import build_validation_input
|
||||
|
||||
SEED = 20260709
|
||||
DEMO_EDITION_NAME = "Festival des Lucioles"
|
||||
DEMO_COORDINATION_PASSWORD = "coordination-lucioles-2026"
|
||||
DEMO_YEAR = 2026
|
||||
START = dt.date(2026, 7, 9)
|
||||
END = dt.date(2026, 7, 12)
|
||||
@@ -229,6 +231,15 @@ class Summary:
|
||||
for code, count in sorted(self.warnings.items()):
|
||||
lines.append(f" {code} : {count}")
|
||||
lines.append(f" Violations bloquantes : {self.blocking}")
|
||||
lines.append("")
|
||||
lines.append(
|
||||
" Connexion coordination (mot de passe) : "
|
||||
"coordination@lucioles.test / " + DEMO_COORDINATION_PASSWORD
|
||||
)
|
||||
lines.append(
|
||||
" Référents et bénévoles : lien magique "
|
||||
"(referent0..2@lucioles.test, <prénom>.<nom><n>@example.test)"
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
@@ -292,6 +303,7 @@ def build(session: Session, *, rng: random.Random | None = None) -> Summary:
|
||||
edition_id=edition.id,
|
||||
email="coordination@lucioles.test",
|
||||
role=Role.COORDINATOR,
|
||||
password_hash=hash_password(DEMO_COORDINATION_PASSWORD),
|
||||
)
|
||||
leads = [
|
||||
Account(
|
||||
|
||||
Reference in New Issue
Block a user