# retoor import os import time import tomllib from pathlib import Path from dotenv import load_dotenv ROOT = Path(__file__).resolve().parents[1] PKG_ROOT = Path(__file__).resolve().parent load_dotenv(ROOT / ".env") with (ROOT / "pyproject.toml").open("rb") as handle: APP_VERSION = tomllib.load(handle)["project"]["version"] APP_TITLE = "Molodetz" APP_PORT = 8088 DEFAULT_TEST_PORT = 8099 def _env(name, default=""): return os.environ.get(f"MOLODETZ_{name}", default) def _env_int(name, default): try: return int(_env(name, str(default))) except ValueError: return default DATA_DIR = Path(_env("DATA_DIR", str(ROOT / "data"))).resolve() DATABASE_URL = _env("DATABASE_URL", f"sqlite:///{DATA_DIR / 'molodetz.db'}") DATA_ROOT = ROOT / "data" if DATA_DIR != DATA_ROOT and DATA_ROOT not in DATA_DIR.parents: raise RuntimeError(f"refusing MOLODETZ_DATA_DIR outside {DATA_ROOT}: {DATA_DIR}") if DATABASE_URL.startswith("sqlite:///"): DB_PATH = Path(DATABASE_URL.removeprefix("sqlite:///")) if not DB_PATH.is_absolute(): DB_PATH = Path.cwd() / DB_PATH if DATA_DIR not in DB_PATH.resolve().parents: raise RuntimeError(f"refusing sqlite database file outside {DATA_DIR}: {DB_PATH}") PORT = _env_int("PORT", APP_PORT) TEST_PORT = _env_int("TEST_PORT", DEFAULT_TEST_PORT) SECRET_KEY = os.environ.get("SECRET_KEY", "molodetz-development-secret-change-in-production") SITE_URL = _env("SITE_URL", "").rstrip("/") INTERNAL_BASE_URL = _env("INTERNAL_BASE_URL", f"http://localhost:{PORT}").rstrip("/") DISABLE_SERVICES = _env("DISABLE_SERVICES") == "1" DISABLE_RATE_LIMIT = _env("DISABLE_RATE_LIMIT") == "1" RATE_LIMIT = _env_int("RATE_LIMIT", 60) WEB_WORKERS = max(1, _env_int("WEB_WORKERS", os.cpu_count() or 1)) TEMPLATE_AUTO_RELOAD = _env("TEMPLATE_AUTO_RELOAD", "1") == "1" BOOT_ID = _env("STATIC_VERSION") or str(int(time.time())) STATIC_VERSION = f"{APP_VERSION}-{BOOT_ID}" LOG_LEVEL = _env("LOG_LEVEL", "INFO") PRESENCE_TIMEOUT_SECONDS = _env_int("PRESENCE_TIMEOUT_SECONDS", 60) PRESENCE_ONLINE_LIMIT = _env_int("PRESENCE_ONLINE_LIMIT", 30) PRESENCE_TRACK_LIMIT = _env_int("PRESENCE_TRACK_LIMIT", 500) PRESENCE_ONLINE_MARGIN_SECONDS = _env_int("PRESENCE_ONLINE_MARGIN_SECONDS", 20) OUTBOUND_PROXY_URL = _env("OUTBOUND_PROXY_URL", "") RCLONE_BIN = _env("RCLONE_BIN", "rclone") RCLONE_CONFIG = _env("RCLONE_CONFIG", str(Path.home() / ".config/rclone/rclone.conf")) BACKUP_OFFLOAD_REMOTE = _env("BACKUP_OFFLOAD_REMOTE", "") SITEMAP_TTL = _env_int("SITEMAP_TTL", 3600) LANDING_TTL = _env_int("LANDING_TTL", 30) UNREAD_TTL = _env_int("UNREAD_TTL", 10) PLAYWRIGHT_HEADLESS = os.environ.get("PLAYWRIGHT_HEADLESS", "1") == "1" PLAYWRIGHT_SLOW_MO = int(os.environ.get("PLAYWRIGHT_SLOW_MO", "0") or 0) ADMIN_USERNAME = _env("ADMIN_USERNAME", "retoor") ADMIN_EMAIL = _env("ADMIN_EMAIL", "retoor@molodetz.nl") ADMIN_PASSWORD = _env("ADMIN_PASSWORD", "") STATIC_DIR = PKG_ROOT / "static" TEMPLATES_DIR = PKG_ROOT / "templates" MEDIA_SOURCE_DIR = STATIC_DIR / "media" DATA_PATHS: dict[str, Path] = { "data": DATA_DIR, "uploads": DATA_DIR / "uploads", "attachments": DATA_DIR / "uploads" / "attachments", "backups": DATA_DIR / "backups", "backup_staging": DATA_DIR / "backups" / "staging", "seo_reports": DATA_DIR / "seo_reports", "keys": DATA_DIR / "keys", "locks": DATA_DIR / "locks", } INIT_LOCK_FILE = DATA_PATHS["locks"] / "init.lock" SERVICE_LOCK_FILE = DATA_PATHS["locks"] / "service.lock" WEB_LOCK_FILE = DATA_PATHS["locks"] / "web.lock" NOTIFICATION_KEY_FILE = DATA_PATHS["keys"] / "notification.key" def ensure_data_dirs(): for path in DATA_PATHS.values(): path.mkdir(parents=True, exist_ok=True)