"""Configuration applicative, entierement pilotee par variables d'environnement.""" from __future__ import annotations from functools import lru_cache from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): """Parametres du backend. Chaque champ est surchargeable via une variable d'environnement de meme nom (insensible a la casse) : APP_NAME, DATABASE_URL, MAX_NODES, ... """ model_config = SettingsConfigDict(env_file=".env", extra="ignore", case_sensitive=False) app_name: str = "OpenMind" app_port: int = 8080 app_env: str = "production" database_url: str = "sqlite:////app/data/openmind.db" static_dir: str = "/app/static" max_map_size_mb: float = Field(default=10.0, gt=0) max_nodes: int = Field(default=5000, gt=0) max_title_length: int = Field(default=200, gt=0) # --- Exploitation publique ------------------------------------------- # Instance entierement privee : le partage serveur peut etre coupe sans # rien changer au fonctionnement local des cartes. sharing_enabled: bool = True # Limites de debit, au format "/" : 10/hour, 120/minute, # 5/second. Une valeur vide ou "0" desactive la limite concernee. share_create_rate_limit: str = "10/hour" share_read_rate_limit: str = "120/minute" share_write_rate_limit: str = "60/hour" # Nombre total de partages heberges. 0 = illimite. max_shared_maps: int = Field(default=10000, ge=0) # Taille maximale d'un partage. 0 = on retombe sur max_map_size_mb. max_share_size_mb: float = Field(default=0.0, ge=0) # Duree de vie par defaut d'un nouveau partage, en jours. 0 = permanent. default_share_expiry_days: int = Field(default=30, ge=0) # Autorise l'option "Jamais" dans l'interface et via l'API. allow_permanent_shares: bool = True # A n'activer que derriere un reverse proxy de confiance : sinon un client # direct pourrait falsifier son adresse et contourner les limites de debit. trust_proxy_headers: bool = False # Liste d'origines autorisees, separees par des virgules. # Vide = aucune origine externe (l'app est servie par ce meme serveur). cors_origins: str = "" log_level: str = "INFO" @property def max_map_size_bytes(self) -> int: return int(self.max_map_size_mb * 1024 * 1024) @property def max_share_size_bytes(self) -> int: """Limite propre aux partages, bornee par la limite HTTP globale.""" if self.max_share_size_mb <= 0: return self.max_map_size_bytes return min(int(self.max_share_size_mb * 1024 * 1024), self.max_map_size_bytes) @property def max_share_size_mb_effective(self) -> float: return self.max_share_size_bytes / (1024 * 1024) @property def cors_origin_list(self) -> list[str]: return [origin.strip() for origin in self.cors_origins.split(",") if origin.strip()] @property def is_debug(self) -> bool: return self.app_env.lower() in {"dev", "development", "debug"} @lru_cache def get_settings() -> Settings: return Settings()