groupe-meditation/backend/app/routers/reunions.py
2026-05-25 17:39:38 -04:00

127 lines
4.2 KiB
Python

"""Routes S4 — Rapport de réunion."""
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, desc, extract
from app.core.database import get_db
from app.core.reunions import jour_reunion_attendu
from app.core.security import get_current_membre, require_executif
from app.models.reunion import Reunion
from app.models.groupe import Groupe
from app.models.membre import Membre
from app.schemas.phase1 import ReunionCreate, ReunionOut
router = APIRouter(prefix="/reunions", tags=["S4 — Rapport de réunion"])
@router.post("/", response_model=ReunionOut)
async def creer_rapport_reunion(
req: ReunionCreate,
membre=Depends(require_executif),
db: AsyncSession = Depends(get_db),
):
"""S4 — L'animateur note le thème et les annonces."""
groupe = await db.get(Groupe, membre.groupe_id)
# ── Validation : réunion régulière ──
if req.type == "reguliere" and groupe.jour_reunion:
jour_attendu = jour_reunion_attendu(groupe)
jour_soumis = req.date_reunion.weekday()
if jour_attendu is not None and jour_soumis != jour_attendu:
raise HTTPException(
status_code=400,
detail=f"La réunion régulière doit avoir lieu le {groupe.jour_reunion}",
)
# Une seule régulière par semaine ISO
iso_year, iso_week, _ = req.date_reunion.isocalendar()
result = await db.execute(
select(Reunion).where(
Reunion.groupe_id == membre.groupe_id,
Reunion.type == "reguliere",
extract("isoyear", Reunion.date_reunion) == iso_year,
extract("week", Reunion.date_reunion) == iso_week,
)
)
if result.scalars().first():
raise HTTPException(
status_code=400,
detail=f"Il y a déjà une réunion régulière pour la semaine {iso_week}",
)
reunion = Reunion(
groupe_id=membre.groupe_id,
type=req.type,
date_reunion=req.date_reunion,
animateur_id=membre.id,
theme=req.theme,
annonces=req.annonces,
note=req.note,
)
db.add(reunion)
await db.flush()
return ReunionOut(
id=reunion.id,
type=reunion.type,
date_reunion=reunion.date_reunion,
animateur_prenom=membre.prenom,
theme=reunion.theme,
annonces=reunion.annonces,
note=reunion.note,
cree_le=reunion.cree_le,
)
@router.get("/", response_model=list[ReunionOut])
async def liste_reunions(
limite: int = 20,
membre=Depends(get_current_membre),
db: AsyncSession = Depends(get_db),
):
"""Lister les réunions récentes du groupe."""
result = await db.execute(
select(Reunion)
.where(Reunion.groupe_id == membre.groupe_id)
.order_by(desc(Reunion.date_reunion))
.limit(limite)
)
reunions = result.scalars().all()
out = []
for r in reunions:
anim = await db.get(Membre, r.animateur_id) if r.animateur_id else None
out.append(ReunionOut(
id=r.id,
type=r.type,
date_reunion=r.date_reunion,
animateur_prenom=anim.prenom if anim else None,
theme=r.theme,
annonces=r.annonces,
note=r.note,
cree_le=r.cree_le,
))
return out
@router.get("/{reunion_id}", response_model=ReunionOut)
async def detail_reunion(
reunion_id: str,
membre=Depends(get_current_membre),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(
select(Reunion).where(Reunion.id == reunion_id, Reunion.groupe_id == membre.groupe_id)
)
reunion = result.scalar_one_or_none()
if not reunion:
raise HTTPException(status_code=404, detail="Réunion introuvable")
anim = await db.get(Membre, reunion.animateur_id) if reunion.animateur_id else None
return ReunionOut(
id=reunion.id,
type=reunion.type,
date_reunion=reunion.date_reunion,
animateur_prenom=anim.prenom if anim else None,
theme=reunion.theme,
annonces=reunion.annonces,
note=reunion.note,
cree_le=reunion.cree_le,
)