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

128 lines
4.2 KiB
Python
Raw Normal View History

2026-03-04 14:01:00 -05:00
"""Routes S4 — Rapport de réunion."""
2026-04-17 04:04:04 -04:00
from datetime import datetime, timezone
2026-03-04 14:01:00 -05:00
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
2026-04-17 04:04:04 -04:00
from sqlalchemy import select, desc, extract
2026-03-04 14:01:00 -05:00
from app.core.database import get_db
2026-05-25 17:39:38 -04:00
from app.core.reunions import jour_reunion_attendu
from app.core.security import get_current_membre, require_executif
2026-03-04 14:01:00 -05:00
from app.models.reunion import Reunion
2026-04-17 04:04:04 -04:00
from app.models.groupe import Groupe
2026-03-04 14:01:00 -05:00
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,
2026-05-25 17:39:38 -04:00
membre=Depends(require_executif),
2026-03-04 14:01:00 -05:00
db: AsyncSession = Depends(get_db),
):
"""S4 — L'animateur note le thème et les annonces."""
2026-04-17 04:04:04 -04:00
groupe = await db.get(Groupe, membre.groupe_id)
# ── Validation : réunion régulière ──
if req.type == "reguliere" and groupe.jour_reunion:
2026-05-25 17:39:38 -04:00
jour_attendu = jour_reunion_attendu(groupe)
2026-04-17 04:04:04 -04:00
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}",
)
2026-03-04 14:01:00 -05:00
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,
)