"""Réglages d'accès de l'instance — inscription locale (fusion #146). Patron des réglages existants (``llm_config``, ``sso_config``) : une table à ligne unique (``id = 1``) créée paresseusement, qui prime sur les valeurs de ``app.config.settings`` (variables d'environnement / ``.env``), elles-mêmes aux défauts du code. Réglage « inscription locale ouverte » : - **fermée par défaut** (décision de Bruno, programme « compte partout ») : les comptes naissent dans le Hub Dracodev et entrent dans Flowdeck par la voie ObsiGate (SSO) / le provisionnement JIT ; le parcours public d'inscription locale est refusé proprement. - réversible à tout moment par un administrateur de l'instance (``GET``/``PUT /api/admin/reglages-acces``) ou en posant ``INSCRIPTION_LOCALE_OUVERTE=true`` avant tout enregistrement en base. Ce réglage ne touche **jamais** la connexion des comptes existants, locaux comme draco : il ne garde que la création de comptes locaux. """ from __future__ import annotations import logging from app.config import settings logger = logging.getLogger(__name__) __all__ = [ "get_reglages_acces", "set_reglages_acces", "inscription_locale_ouverte", "message_inscription_fermee", ] def _assurer_table(conn) -> None: """Crée la table des réglages d'accès si elle n'existe pas encore.""" conn.execute(""" CREATE TABLE IF NOT EXISTS reglages_acces ( id INTEGER PRIMARY KEY CHECK (id = 1), inscription_locale_ouverte INTEGER, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """) def get_reglages_acces() -> dict: """Réglages d'accès effectifs — la ligne en base prime sur la config.""" reglages = { # Défaut du code et de la config : inscription fermée. "inscription_locale_ouverte": bool( getattr(settings, "inscription_locale_ouverte", False)), } try: from app.db import get_conn with get_conn() as conn: _assurer_table(conn) row = conn.execute( "SELECT inscription_locale_ouverte FROM reglages_acces" " WHERE id=1" ).fetchone() except Exception: # noqa: BLE001 — base pas encore prête → config seule return reglages if row is not None and row["inscription_locale_ouverte"] is not None: reglages["inscription_locale_ouverte"] = bool( row["inscription_locale_ouverte"]) return reglages def set_reglages_acces(*, inscription_locale_ouverte: bool | None = None) -> dict: """Enregistre les réglages d'accès (ligne unique) et les renvoie.""" from app.db import get_conn actuels = get_reglages_acces() if inscription_locale_ouverte is not None: actuels["inscription_locale_ouverte"] = bool(inscription_locale_ouverte) with get_conn() as conn: _assurer_table(conn) conn.execute( "INSERT INTO reglages_acces (id, inscription_locale_ouverte," " updated_at) VALUES (1, ?, CURRENT_TIMESTAMP)" " ON CONFLICT(id) DO UPDATE SET" " inscription_locale_ouverte=excluded.inscription_locale_ouverte," " updated_at=CURRENT_TIMESTAMP", (1 if actuels["inscription_locale_ouverte"] else 0,), ) conn.commit() return actuels def inscription_locale_ouverte() -> bool: """Vrai si l'inscription publique locale est ouverte sur l'instance.""" return bool(get_reglages_acces()["inscription_locale_ouverte"]) def message_inscription_fermee() -> str: """Message affiché quand l'inscription locale est fermée (#146). Nomme le Hub Dracodev — là où les comptes se créent — avec son URL dérivée de l'hôte comme les autres liens de la suite (``draco_urls.hub_url()``, jamais un nom figé). """ from app.services import draco_urls return ( "L'inscription locale est fermée sur cette instance : " "les comptes se créent dans le Hub Dracodev " f"({draco_urls.hub_url()}), puis se connectent ici avec le " "bouton « Login with ObsiGate (SSO) »." )