132 lines
4.6 KiB
Python
132 lines
4.6 KiB
Python
"""Routes membres — profil et gestion."""
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select
|
|
|
|
from app.core.database import get_db
|
|
from app.core.security import get_current_membre, require_executif, hash_pin, verify_pin
|
|
from app.models.membre import Membre
|
|
from app.schemas.schemas import MembrePublic, MembreComplet, MembreUpdate, ChangerPinRequest
|
|
|
|
router = APIRouter(prefix="/membres", tags=["Membres"])
|
|
|
|
|
|
@router.get("/moi", response_model=MembreComplet)
|
|
async def mon_profil(membre=Depends(get_current_membre)):
|
|
"""C7 — Mon profil."""
|
|
return MembreComplet.model_validate(membre)
|
|
|
|
|
|
@router.patch("/moi", response_model=MembreComplet)
|
|
async def modifier_profil(
|
|
updates: MembreUpdate,
|
|
membre=Depends(get_current_membre),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""C7 — Modifier mon profil."""
|
|
if updates.prenom is not None:
|
|
membre.prenom = updates.prenom.strip().title()
|
|
if updates.nom is not None:
|
|
membre.nom = updates.nom.strip().title() if updates.nom.strip() else None
|
|
if updates.telephone is not None:
|
|
membre.telephone = updates.telephone.strip()
|
|
if updates.courriel is not None:
|
|
membre.courriel = updates.courriel.strip().lower()
|
|
if updates.date_abstinence is not None:
|
|
membre.date_abstinence = updates.date_abstinence
|
|
await db.flush()
|
|
return MembreComplet.model_validate(membre)
|
|
|
|
|
|
@router.post("/moi/pin")
|
|
async def changer_pin(
|
|
req: ChangerPinRequest,
|
|
membre=Depends(get_current_membre),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""C7 — Changer mon PIN."""
|
|
if not verify_pin(req.ancien_pin, membre.pin_hash):
|
|
raise HTTPException(status_code=400, detail="Ancien PIN incorrect")
|
|
if not req.nouveau_pin.isdigit() or len(req.nouveau_pin) != 4:
|
|
raise HTTPException(status_code=400, detail="Le PIN doit être composé de 4 chiffres")
|
|
membre.pin_hash = hash_pin(req.nouveau_pin)
|
|
await db.flush()
|
|
return {"message": "PIN modifié avec succès"}
|
|
|
|
|
|
@router.get("/actifs", response_model=list[MembrePublic])
|
|
async def liste_membres_actifs(
|
|
membre=Depends(get_current_membre),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Liste simplifiée des membres actifs (prénom + id) — pour les dropdowns."""
|
|
result = await db.execute(
|
|
select(Membre).where(
|
|
Membre.groupe_id == membre.groupe_id,
|
|
Membre.actif == True,
|
|
).order_by(Membre.prenom)
|
|
)
|
|
return [MembrePublic.model_validate(m) for m in result.scalars().all()]
|
|
|
|
|
|
@router.get("/", response_model=list[MembreComplet])
|
|
async def liste_membres(
|
|
executif=Depends(require_executif),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""G2 — Liste des membres (exécutif seulement)."""
|
|
result = await db.execute(
|
|
select(Membre).where(
|
|
Membre.groupe_id == executif.groupe_id,
|
|
Membre.actif == True,
|
|
).order_by(Membre.prenom)
|
|
)
|
|
return [MembreComplet.model_validate(m) for m in result.scalars().all()]
|
|
|
|
|
|
@router.patch("/{membre_id}/desactiver")
|
|
async def desactiver_membre(
|
|
membre_id: str,
|
|
executif=Depends(require_executif),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""G2 — Désactiver un membre."""
|
|
result = await db.execute(
|
|
select(Membre).where(Membre.id == membre_id, Membre.groupe_id == executif.groupe_id)
|
|
)
|
|
membre = result.scalar_one_or_none()
|
|
if not membre:
|
|
raise HTTPException(status_code=404, detail="Membre introuvable")
|
|
membre.actif = False
|
|
await db.flush()
|
|
return {"message": f"{membre.prenom} a été désactivé"}
|
|
|
|
|
|
@router.delete("/{membre_id}/oubli")
|
|
async def droit_oubli(
|
|
membre_id: str,
|
|
executif=Depends(require_executif),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""G2 — Droit à l'oubli : anonymise les données personnelles."""
|
|
result = await db.execute(
|
|
select(Membre).where(Membre.id == membre_id, Membre.groupe_id == executif.groupe_id)
|
|
)
|
|
membre = result.scalar_one_or_none()
|
|
if not membre:
|
|
raise HTTPException(status_code=404, detail="Membre introuvable")
|
|
if str(membre.id) == str(executif.id):
|
|
raise HTTPException(status_code=400, detail="Impossible de supprimer votre propre compte")
|
|
|
|
prenom_original = membre.prenom
|
|
# Anonymiser
|
|
membre.prenom = "Ancien membre"
|
|
membre.nom = None
|
|
membre.telephone = "000-000-0000"
|
|
membre.courriel = f"supprime_{membre.id}@anon.local"
|
|
membre.pin_hash = "SUPPRIME"
|
|
membre.actif = False
|
|
membre.push_sub = None
|
|
membre.date_abstinence = None
|
|
await db.flush()
|
|
return {"message": f"Données de {prenom_original} anonymisées (droit à l'oubli)"}
|