from __future__ import annotations import os import secrets from dataclasses import dataclass from pathlib import Path from urllib.parse import quote_plus ROOT_DIR = Path(__file__).resolve().parent.parent @dataclass(slots=True) class Settings: app_name: str = "Spring Check-In Activity Manager" timezone: str = os.getenv("APP_TIMEZONE", "Asia/Shanghai") session_secret: str = os.getenv("SESSION_SECRET", secrets.token_urlsafe(32)) admin_username: str = os.getenv("ADMIN", "superadmin") admin_password: str = os.getenv("PASSWORD", "change-me-now") mysql_user: str = os.getenv("SQL_USER", "avnadmin") mysql_password: str = os.getenv("SQL_PASSWORD", "") mysql_host: str = os.getenv("SQL_HOST", "mysql-2bace9cd-cacode.i.aivencloud.com") mysql_port: int = int(os.getenv("SQL_PORT", "21260")) mysql_db: str = os.getenv("SQL_DATABASE", "CAM") mysql_ca_file: Path = ROOT_DIR / os.getenv("MYSQL_CA_FILE", "ca.pem") db_pool_size: int = int(os.getenv("DB_POOL_SIZE", "12")) db_max_overflow: int = int(os.getenv("DB_MAX_OVERFLOW", "24")) db_pool_timeout: int = int(os.getenv("DB_POOL_TIMEOUT", "30")) db_pool_recycle: int = int(os.getenv("DB_POOL_RECYCLE", "1800")) docker_root: Path = ROOT_DIR / os.getenv("DOCKER_ROOT", "docker_data") @property def upload_root(self) -> Path: return self.docker_root / "submissions" @property def task_media_root(self) -> Path: return self.docker_root / "tasks" @property def database_url(self) -> str: if raw_url := os.getenv("DATABASE_URL"): return raw_url user = quote_plus(self.mysql_user) password = quote_plus(self.mysql_password) return f"mysql+pymysql://{user}:{password}@{self.mysql_host}:{self.mysql_port}/{self.mysql_db}" @property def database_connect_args(self) -> dict: if self.database_url.startswith("sqlite"): return {} if self.mysql_ca_file.exists(): return {"ssl": {"ca": str(self.mysql_ca_file)}} return {} @property def database_engine_kwargs(self) -> dict: kwargs = { "pool_pre_ping": True, "connect_args": self.database_connect_args, } if not self.database_url.startswith("sqlite"): kwargs.update( { "pool_size": self.db_pool_size, "max_overflow": self.db_max_overflow, "pool_timeout": self.db_pool_timeout, "pool_recycle": self.db_pool_recycle, "pool_use_lifo": True, } ) return kwargs settings = Settings()