"""Process-level configuration: where the database is, who may call us, and the seed values for the integrations. Two layers of configuration exist in this app and they do different jobs: * **This module** — environment variables. Infrastructure plus *secrets* (API tokens), so they can live in a `.env` file or a Docker secret and never touch the database or the browser. * **`app.settings_schema.AppSettings`** — the user-editable settings stored in the database and edited in the UI (pomodoro lengths, blocked sites, report times...). On first boot the secrets below are copied into it as defaults. So: `JIRA_API_TOKEN` in the environment gets you a working Jira source without ever opening the settings page, and anything you later change in the UI wins. """ from __future__ import annotations import os from functools import lru_cache from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict # Tests set this so a developer's real `.env` — with live Jira and Telegram # credentials in it — can never leak into a test run. _DOTENV_FILES = () if os.environ.get("KADENCE_NO_DOTENV") else (".env", "../.env") class EnvSettings(BaseSettings): model_config = SettingsConfigDict( env_file=_DOTENV_FILES, env_file_encoding="utf-8", extra="ignore", ) # ---- infrastructure ---------------------------------------------------- database_url: str = Field( default="sqlite:///./kadence.db", description="SQLAlchemy URL. Docker compose points this at Postgres.", ) cors_origins: str = Field( default="*", description="Comma-separated list of allowed browser origins, or '*'.", ) timezone: str = Field( default="Europe/Moscow", description="Fallback timezone for 'today' and for scheduled jobs.", ) scheduler_enabled: bool = Field( default=True, description="Run the background jobs (daily report, nudges, refresh).", ) telegram_bot_enabled: bool = Field( default=True, description="Run the Telegram command bot when a token is configured.", ) api_token: str = Field( default="", description=( "Optional shared secret. When set, every /api call must send it as " "`X-API-Token` (the desktop app and the web UI both do)." ), ) # ---- seeds for the editable settings ----------------------------------- jira_base_url: str = "" jira_email: str = "" jira_api_token: str = "" jira_extra_jql: str = "" jira_start_date_field: str = "customfield_10015" google_client_id: str = "" google_client_secret: str = "" google_refresh_token: str = "" google_tasks_lists: str = "" todoist_api_token: str = "" todoist_projects: str = "" laundry_session: str = "" laundry_base_url: str = "https://4ka.inbicst.ru" telegram_bot_token: str = "" telegram_chat_id: str = "" slack_webhook_url: str = "" @property def cors_origin_list(self) -> list[str]: if self.cors_origins.strip() == "*": return ["*"] return [item.strip() for item in self.cors_origins.split(",") if item.strip()] @lru_cache def env_settings() -> EnvSettings: return EnvSettings()