53 lines
1.6 KiB
Python
53 lines
1.6 KiB
Python
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()
|