groupe-meditation/backend/app/routers/evenements.py

152 lines
4.9 KiB
Python

"""Routes — Événements (anniversaires + ad hoc + résolutions)."""
from datetime import date, timedelta
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, desc
from app.core.database import get_db
from app.core.security import get_current_membre, require_executif
from app.models.groupe import Groupe
from app.models.membre import Membre
from app.models.affectation import Affectation
from app.models.poste import Poste
from app.models.evenement import Evenement
from app.models.proposition import Proposition
router = APIRouter(prefix="/evenements", tags=["Événements"])
def _anniversaire_sobriete(date_abstinence: date, annee: int) -> tuple[int, date]:
try:
anniv = date_abstinence.replace(year=annee)
except ValueError:
anniv = date(annee, 3, 1)
return max(0, anniv.year - date_abstinence.year), anniv
@router.get("/")
async def evenements_a_venir(
jours: int = 90,
jours_avant: int = 365,
membre=Depends(get_current_membre),
db: AsyncSession = Depends(get_db),
):
"""Tous les événements : anniversaires, ad hoc et résolutions."""
aujourdhui = date.today()
debut = aujourdhui - timedelta(days=jours_avant)
limite = aujourdhui + timedelta(days=jours)
groupe = await db.get(Groupe, membre.groupe_id)
district = groupe.district if groupe else "87-16"
evenements = []
# ── 1. Anniversaires de sobriété du district ──
result = await db.execute(
select(Membre, Groupe.nom)
.join(Groupe, Membre.groupe_id == Groupe.id)
.where(
Groupe.district == district,
Membre.actif == True,
Membre.date_abstinence.isnot(None),
)
)
for m, groupe_nom in result.all():
for annee in range(debut.year, limite.year + 1):
annees, anniv = _anniversaire_sobriete(m.date_abstinence, annee)
if anniv < debut or anniv > limite:
continue
evenements.append({
"type": "anniversaire",
"date": str(anniv),
"titre": f"🎂 {m.prenom} — {annees} an{'s' if annees > 1 else ''}",
"detail": f"Anniversaire de sobriété · {groupe_nom}",
"lieu": None,
"groupe_nom": groupe_nom,
})
# ── 2. Événements ad hoc ──
result = await db.execute(
select(Evenement, Groupe.nom)
.join(Groupe, Evenement.groupe_id == Groupe.id)
.where(
Groupe.district == district,
Evenement.date_evenement >= debut,
Evenement.date_evenement <= limite,
)
)
for ev, groupe_nom in result.all():
evenements.append({
"type": "adhoc",
"date": str(ev.date_evenement),
"titre": ev.titre,
"detail": ev.description,
"lieu": ev.lieu,
"groupe_nom": groupe_nom,
})
# ── 3. Résolutions adoptées du groupe ──
result = await db.execute(
select(Proposition).where(
Proposition.groupe_id == membre.groupe_id,
Proposition.statut == "adoptee",
).order_by(desc(Proposition.date_vote))
)
for p in result.scalars().all():
date_res = str(p.date_vote) if p.date_vote else str(p.cree_le.date())
evenements.append({
"type": "resolution",
"date": date_res,
"titre": f"📜 {p.numero_resolution or 'RES'} — {p.sujet}",
"detail": p.description or p.note,
"lieu": None,
"groupe_nom": groupe.nom if groupe else "?",
})
# Trier par date
evenements.sort(key=lambda e: e["date"])
return evenements
# ── CRUD événements ad hoc ──
@router.post("/")
async def creer_evenement(
titre: str,
date_evenement: date,
description: str = "",
lieu: str = "",
executif=Depends(require_executif),
db: AsyncSession = Depends(get_db),
):
"""Créer un événement ad hoc (exécutif)."""
ev = Evenement(
groupe_id=executif.groupe_id,
titre=titre.strip(),
description=description.strip() or None,
date_evenement=date_evenement,
lieu=lieu.strip() or None,
cree_par=executif.id,
)
db.add(ev)
await db.flush()
return {"message": "Événement créé", "id": str(ev.id)}
@router.delete("/{evenement_id}")
async def supprimer_evenement(
evenement_id: str,
executif=Depends(require_executif),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(Evenement).where(
Evenement.id == evenement_id,
Evenement.groupe_id == executif.groupe_id,
)
)
ev = result.scalar_one_or_none()
if not ev:
raise HTTPException(status_code=404, detail="Événement introuvable")
await db.delete(ev)
await db.flush()
return {"message": "Événement supprimé"}