133 lines
4.1 KiB
Python
133 lines
4.1 KiB
Python
"""Routes — Événements (anniversaires + ad hoc)."""
|
|
from datetime import date, timedelta
|
|
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
|
|
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
|
|
|
|
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 et ad hoc."""
|
|
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,
|
|
})
|
|
|
|
# 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é"}
|