feat(proj): init

This commit is contained in:
vl.arkhangelskii
2026-09-21 04:06:43 +03:00
commit c956b94983
1076 changed files with 50876 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
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()