2026-03-04 14:01:00 -05:00
|
|
|
"""
|
|
|
|
|
Groupe Méditation — API Backend
|
|
|
|
|
District 87-16, Région 87
|
|
|
|
|
100% logiciel libre · Hébergé au Québec
|
|
|
|
|
"""
|
|
|
|
|
from contextlib import asynccontextmanager
|
|
|
|
|
from fastapi import FastAPI
|
|
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
2026-05-25 17:39:38 -04:00
|
|
|
from sqlalchemy import text
|
2026-03-04 14:01:00 -05:00
|
|
|
|
|
|
|
|
from app.core.config import settings
|
2026-05-25 17:39:38 -04:00
|
|
|
from app.core.audit import AuditMiddleware
|
2026-03-04 14:01:00 -05:00
|
|
|
from app.core.database import engine, Base
|
2026-05-26 13:21:16 -04:00
|
|
|
from app.routers import admin, auth, membres, postes, accueil, invitations, collectes, reunions, depenses, calendrier, rapports, rotations, parametres, presences, pv, rapports_rsg, jetons, anniversaires, commandes_jetons, litterature, ventes_litterature, contributions, config_repartition, propositions, operations_bancaires, evenements, notifications, journal
|
2026-03-04 14:01:00 -05:00
|
|
|
|
2026-04-17 04:04:04 -04:00
|
|
|
# Import models pour que create_all crée toutes les tables
|
2026-03-13 01:28:06 -04:00
|
|
|
from app.models.sync_log import SyncLog # noqa: F401
|
2026-04-17 04:04:04 -04:00
|
|
|
from app.models.proposition import Proposition # noqa: F401
|
|
|
|
|
from app.models.operation_bancaire import OperationBancaire # noqa: F401
|
|
|
|
|
from app.models.evenement import Evenement # noqa: F401
|
|
|
|
|
from app.models.candidature import Candidature # noqa: F401
|
2026-05-15 16:41:17 -04:00
|
|
|
from app.models.poste_module import PosteModule # noqa: F401
|
|
|
|
|
from app.models.reserve import Reserve # noqa: F401
|
2026-05-25 17:39:38 -04:00
|
|
|
from app.models.transaction_comptable import TransactionComptable # noqa: F401
|
|
|
|
|
from app.models.mouvement_reserve import MouvementReserve # noqa: F401
|
|
|
|
|
from app.models.journal_action import JournalAction # noqa: F401
|
|
|
|
|
from app.models.push_subscription import PushSubscription # noqa: F401
|
2026-05-26 08:15:28 -04:00
|
|
|
from app.models.destinataire_contribution import DestinataireContribution # noqa: F401
|
2026-05-26 13:21:16 -04:00
|
|
|
from app.models.rapport_adopte import RapportAdopte # noqa: F401
|
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
|
|
|
from app.models.vente_jeton import VenteJeton # noqa: F401
|
2026-05-31 10:59:41 -04:00
|
|
|
from app.models.historique_modification import HistoriqueModification # noqa: F401
|
2026-03-13 01:28:06 -04:00
|
|
|
|
2026-03-04 14:01:00 -05:00
|
|
|
|
|
|
|
|
@asynccontextmanager
|
|
|
|
|
async def lifespan(app: FastAPI):
|
|
|
|
|
async with engine.begin() as conn:
|
|
|
|
|
await conn.run_sync(Base.metadata.create_all)
|
2026-05-25 17:39:38 -04:00
|
|
|
await conn.execute(text(
|
|
|
|
|
"ALTER TABLE groupes "
|
|
|
|
|
"ADD COLUMN IF NOT EXISTS assemblee_affaires_ordre VARCHAR(20) DEFAULT 'premiere'"
|
|
|
|
|
))
|
2026-05-31 18:12:26 -04:00
|
|
|
await conn.execute(text("ALTER TABLE postes ADD COLUMN IF NOT EXISTS groupe_id UUID REFERENCES groupes(id)"))
|
|
|
|
|
await conn.execute(text(
|
|
|
|
|
"UPDATE postes SET groupe_id = (SELECT id FROM groupes ORDER BY cree_le LIMIT 1) "
|
|
|
|
|
"WHERE groupe_id IS NULL AND EXISTS (SELECT 1 FROM groupes)"
|
|
|
|
|
))
|
|
|
|
|
await conn.execute(text("ALTER TABLE postes ALTER COLUMN groupe_id SET NOT NULL"))
|
2026-05-25 17:39:38 -04:00
|
|
|
await conn.execute(text("ALTER TABLE propositions ADD COLUMN IF NOT EXISTS date_adoption DATE"))
|
|
|
|
|
await conn.execute(text("ALTER TABLE propositions ADD COLUMN IF NOT EXISTS etant_donne_que TEXT"))
|
|
|
|
|
await conn.execute(text("ALTER TABLE propositions ADD COLUMN IF NOT EXISTS groupe_a_decide_de TEXT"))
|
2026-05-26 09:05:58 -04:00
|
|
|
await conn.execute(text("ALTER TABLE propositions DROP COLUMN IF EXISTS type_proposition"))
|
2026-05-26 13:21:16 -04:00
|
|
|
await conn.execute(text("ALTER TABLE membres ADD COLUMN IF NOT EXISTS notification_preferences JSON"))
|
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
|
|
|
await conn.execute(text("ALTER TABLE jetons ADD COLUMN IF NOT EXISTS reunion_id UUID REFERENCES reunions(id)"))
|
|
|
|
|
await conn.execute(text("ALTER TABLE ventes_litterature ADD COLUMN IF NOT EXISTS reunion_id UUID REFERENCES reunions(id)"))
|
|
|
|
|
await conn.execute(text("ALTER TABLE invitations ADD COLUMN IF NOT EXISTS cible_type VARCHAR(40)"))
|
|
|
|
|
await conn.execute(text("ALTER TABLE invitations ADD COLUMN IF NOT EXISTS cible_id UUID"))
|
2026-05-31 10:59:41 -04:00
|
|
|
for table in (
|
|
|
|
|
"propositions",
|
|
|
|
|
"depenses",
|
|
|
|
|
"collectes",
|
|
|
|
|
"reunions",
|
|
|
|
|
"pv_reunions",
|
|
|
|
|
"reserves",
|
|
|
|
|
"litterature",
|
|
|
|
|
"destinataires_contributions",
|
|
|
|
|
"envois_contributions",
|
|
|
|
|
):
|
|
|
|
|
await conn.execute(text(
|
|
|
|
|
f"ALTER TABLE {table} "
|
|
|
|
|
"ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMPTZ DEFAULT now() NOT NULL"
|
|
|
|
|
))
|
2026-05-26 08:15:28 -04:00
|
|
|
await conn.execute(text(
|
|
|
|
|
"ALTER TABLE envois_contributions "
|
|
|
|
|
"ALTER COLUMN destination TYPE VARCHAR(120) USING destination::text"
|
|
|
|
|
))
|
2026-05-25 17:39:38 -04:00
|
|
|
await conn.execute(text("DROP TABLE IF EXISTS votes"))
|
|
|
|
|
await conn.execute(text("DROP TABLE IF EXISTS options_sondage"))
|
|
|
|
|
await conn.execute(text("DROP TABLE IF EXISTS sondages"))
|
|
|
|
|
await conn.execute(text("DROP TABLE IF EXISTS decisions"))
|
2026-05-26 08:15:28 -04:00
|
|
|
await conn.execute(text(
|
|
|
|
|
"INSERT INTO destinataires_contributions (id, groupe_id, nom, protege, actif, cree_le) "
|
|
|
|
|
"SELECT CAST(md5(random()::text || clock_timestamp()::text) AS uuid), g.id, 'District 87-16', true, true, now() "
|
|
|
|
|
"FROM groupes g "
|
|
|
|
|
"WHERE NOT EXISTS ("
|
|
|
|
|
" SELECT 1 FROM destinataires_contributions d "
|
|
|
|
|
" WHERE d.groupe_id = g.id AND d.nom = 'District 87-16'"
|
|
|
|
|
")"
|
|
|
|
|
))
|
2026-03-04 14:01:00 -05:00
|
|
|
yield
|
|
|
|
|
await engine.dispose()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app = FastAPI(
|
|
|
|
|
title="Groupe Méditation API",
|
|
|
|
|
description="API du Groupe Méditation — District 87-16, Région 87",
|
|
|
|
|
version="0.1.0",
|
|
|
|
|
lifespan=lifespan,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
app.add_middleware(
|
|
|
|
|
CORSMiddleware,
|
|
|
|
|
allow_origins=settings.CORS_ORIGINS,
|
|
|
|
|
allow_credentials=True,
|
|
|
|
|
allow_methods=["*"],
|
|
|
|
|
allow_headers=["*"],
|
|
|
|
|
)
|
2026-05-25 17:39:38 -04:00
|
|
|
app.add_middleware(AuditMiddleware)
|
2026-03-04 14:01:00 -05:00
|
|
|
|
|
|
|
|
# Montage des routes
|
|
|
|
|
app.include_router(auth.router, prefix="/api")
|
2026-05-26 13:21:16 -04:00
|
|
|
app.include_router(admin.router, prefix="/api")
|
2026-03-04 14:01:00 -05:00
|
|
|
app.include_router(membres.router, prefix="/api")
|
|
|
|
|
app.include_router(postes.router, prefix="/api")
|
|
|
|
|
app.include_router(accueil.router, prefix="/api")
|
|
|
|
|
app.include_router(invitations.router, prefix="/api")
|
|
|
|
|
app.include_router(collectes.router, prefix="/api")
|
|
|
|
|
app.include_router(reunions.router, prefix="/api")
|
|
|
|
|
app.include_router(depenses.router, prefix="/api")
|
|
|
|
|
app.include_router(calendrier.router, prefix="/api")
|
|
|
|
|
app.include_router(rapports.router, prefix="/api")
|
|
|
|
|
app.include_router(rotations.router, prefix="/api")
|
|
|
|
|
app.include_router(parametres.router, prefix="/api")
|
|
|
|
|
app.include_router(presences.router, prefix="/api")
|
|
|
|
|
app.include_router(pv.router, prefix="/api")
|
|
|
|
|
app.include_router(rapports_rsg.router, prefix="/api")
|
|
|
|
|
app.include_router(jetons.router, prefix="/api")
|
|
|
|
|
app.include_router(anniversaires.router, prefix="/api")
|
|
|
|
|
app.include_router(commandes_jetons.router, prefix="/api")
|
|
|
|
|
app.include_router(litterature.router, prefix="/api")
|
|
|
|
|
app.include_router(ventes_litterature.router, prefix="/api")
|
|
|
|
|
app.include_router(contributions.router, prefix="/api")
|
|
|
|
|
app.include_router(config_repartition.router, prefix="/api")
|
2026-04-17 04:04:04 -04:00
|
|
|
app.include_router(propositions.router, prefix="/api")
|
|
|
|
|
app.include_router(operations_bancaires.router, prefix="/api")
|
|
|
|
|
app.include_router(evenements.router, prefix="/api")
|
2026-05-25 17:39:38 -04:00
|
|
|
app.include_router(notifications.router, prefix="/api")
|
|
|
|
|
app.include_router(journal.router, prefix="/api")
|
2026-03-04 14:01:00 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/api/health")
|
|
|
|
|
async def root_health():
|
|
|
|
|
return {"status": "ok", "app": "Groupe Méditation", "version": "0.1.0"}
|