from __future__ import annotations import configparser from functools import lru_cache from pathlib import Path from pydantic import field_validator from pydantic_settings import BaseSettings, SettingsConfigDict ROOT_DIR = Path(__file__).resolve().parent.parent def read_app_version() -> str: parser = configparser.ConfigParser() version_file = ROOT_DIR / "version.ini" if version_file.exists(): parser.read(version_file, encoding="utf-8") return parser.get("version", "version", fallback="0.1").strip() return "0.1" class Settings(BaseSettings): model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", extra="ignore", ) app_name: str = "TryMe Gaming App" database_url: str = f"sqlite:///{(ROOT_DIR / 'tryme.db').as_posix()}" # Auth0 Federated OIDC / JWT settings auth0_domain: str = "" auth0_client_id: str = "" auth0_client_secret: str = "" auth0_audience: str = "" auth0_callback_url: str = "http://localhost:8000/api/v1/auth/callback" frontend_base_url: str = "http://localhost:8000" # Local dev auth fallback & session signing dev_auth_enabled: bool = True session_secret: str = "tryme-dev-secret-change-in-production" session_ttl_hours: int = 168 # Initial moderator setup or container variable (matches sub, email, or nickname) admin_user: str = "" # Optional starter quizzes for local demo / compose seed_starter_quizzes: bool = False @field_validator("database_url", mode="before") @classmethod def normalize_database_url(cls, value: str) -> str: if isinstance(value, str): val = value.strip() if val.startswith("postgres://"): return "postgresql+psycopg://" + val[len("postgres://") :] if val.startswith("postgresql://"): return "postgresql+psycopg://" + val[len("postgresql://") :] return val return value @property def auth0_configured(self) -> bool: return bool(self.auth0_domain and self.auth0_client_id) @lru_cache def get_settings() -> Settings: return Settings()