import json import os from dataclasses import dataclass from pathlib import Path DEFAULT_TIMEZONE = "UTC" DEFAULT_POLL_SECONDS = 60 class ConfigFileError(RuntimeError): def __init__(self, path: Path, message: str): super().__init__(f"{path}: {message}") self.path = path self.message = message @dataclass(frozen=True) class WebAppConfig: data_dir: Path posts_dir: Path config_dir: Path users_file: Path timezone: str session_secret: str scheduler_poll_seconds: int def load_webapp_config() -> WebAppConfig: data_dir = Path(os.environ.get("LINKKI_DATA_DIR", "data")).resolve() config_dir = data_dir / "config" posts_dir = data_dir / "posts" config_dir.mkdir(parents=True, exist_ok=True) posts_dir.mkdir(parents=True, exist_ok=True) config_path = config_dir / "app_config.json" config_data: dict[str, object] = {} if config_path.exists(): try: config_data = json.loads(config_path.read_text(encoding="utf-8")) except json.JSONDecodeError as error: raise ConfigFileError(config_path, f"Invalid JSON: {error.msg}") from error timezone = str(config_data.get("timezone", DEFAULT_TIMEZONE)) session_secret = str(config_data.get("session_secret", "change-me")) poll_seconds = int(config_data.get("scheduler_poll_seconds", DEFAULT_POLL_SECONDS)) users_filename = str(config_data.get("users_file", "users.json")) return WebAppConfig( data_dir=data_dir, posts_dir=posts_dir, config_dir=config_dir, users_file=config_dir / users_filename, timezone=timezone, session_secret=session_secret, scheduler_poll_seconds=poll_seconds, )