from __future__ import annotations from pathlib import Path from pydantic import field_validator from pydantic_settings import BaseSettings, SettingsConfigDict BASE_DIR = Path(__file__).resolve().parent.parent class ApiSettings(BaseSettings): model_config = SettingsConfigDict( env_file=BASE_DIR / ".env", env_file_encoding="utf-8", extra="ignore", ) database_path: Path = BASE_DIR / "data" / "budget.db" bot_token: str # Shared secret for bot (/api/auth/internal) and admin /api/budgets/* api_token: str | None = None jwt_secret: str | None = None jwt_ttl_seconds: int = 60 * 60 * 24 * 14 telegram_auth_max_age_seconds: int = 60 * 60 * 24 cors_origins: str = "*" host: str = "0.0.0.0" port: int = 8000 @field_validator("bot_token", mode="before") @classmethod def require_bot_token(cls, value: object) -> object: if value is None or (isinstance(value, str) and not value.strip()): raise ValueError("BOT_TOKEN is required for Telegram login") return value @field_validator("api_token", "jwt_secret", mode="before") @classmethod def empty_as_none(cls, value: object) -> object: if isinstance(value, str) and not value.strip(): return None return value @property def session_secret(self) -> str: return self.jwt_secret or f"ppm-jwt::{self.bot_token}" @property def cors_origin_list(self) -> list[str]: return [item.strip() for item in self.cors_origins.split(",") if item.strip()] settings = ApiSettings()