robot-u-site/settings.py

99 lines
3.6 KiB
Python
Raw Permalink Normal View History

2026-04-08 06:03:48 -04:00
from __future__ import annotations
import os
from dataclasses import dataclass
from functools import lru_cache
@dataclass(frozen=True)
class Settings:
app_base_url: str | None
2026-04-12 22:02:47 -04:00
auth_secret_key: str | None
auth_cookie_secure: bool
2026-04-14 20:17:29 -04:00
cors_allow_origins: tuple[str, ...]
2026-04-08 06:03:48 -04:00
forgejo_base_url: str
forgejo_token: str | None
forgejo_oauth_client_id: str | None
forgejo_oauth_client_secret: str | None
forgejo_oauth_scopes: tuple[str, ...]
2026-04-13 18:19:50 -04:00
forgejo_general_discussion_repo: str | None
forgejo_webhook_secret: str | None
2026-04-08 06:03:48 -04:00
forgejo_repo_scan_limit: int
forgejo_recent_issue_limit: int
2026-04-13 18:19:50 -04:00
forgejo_cache_ttl_seconds: float
2026-04-08 06:03:48 -04:00
forgejo_request_timeout_seconds: float
calendar_feed_urls: tuple[str, ...]
calendar_event_limit: int
def _normalize_base_url(raw_value: str | None) -> str:
value = (raw_value or "").strip()
if not value:
return "https://aksal.cloud"
if value.startswith(("http://", "https://")):
return value.rstrip("/")
return f"https://{value.rstrip('/')}"
def _parse_calendar_feed_urls(raw_value: str | None) -> tuple[str, ...]:
2026-04-14 20:17:29 -04:00
return _parse_csv_values(raw_value)
def _parse_csv_values(raw_value: str | None) -> tuple[str, ...]:
2026-04-08 06:03:48 -04:00
value = (raw_value or "").strip()
if not value:
return ()
return tuple(entry.strip() for entry in value.replace("\n", ",").split(",") if entry.strip())
def _parse_scopes(raw_value: str | None) -> tuple[str, ...]:
value = (raw_value or "").strip()
if not value:
return ("openid", "profile")
return tuple(scope for scope in value.replace(",", " ").split() if scope)
2026-04-12 22:02:47 -04:00
def _parse_bool(raw_value: str | None, *, default: bool = False) -> bool:
value = (raw_value or "").strip().lower()
if not value:
return default
return value in {"1", "true", "yes", "on"}
2026-04-14 20:17:29 -04:00
def _cors_allow_origins(app_base_url: str | None, raw_value: str | None) -> tuple[str, ...]:
configured_origins = _parse_csv_values(raw_value)
if configured_origins:
return configured_origins
if app_base_url:
return (app_base_url,)
return ("*",)
2026-04-08 06:03:48 -04:00
@lru_cache(maxsize=1)
def get_settings() -> Settings:
2026-04-14 20:17:29 -04:00
app_base_url = (
_normalize_base_url(os.getenv("APP_BASE_URL")) if os.getenv("APP_BASE_URL") else None
)
2026-04-08 06:03:48 -04:00
return Settings(
2026-04-14 20:17:29 -04:00
app_base_url=app_base_url,
2026-04-12 22:02:47 -04:00
auth_secret_key=os.getenv("AUTH_SECRET_KEY") or None,
auth_cookie_secure=_parse_bool(os.getenv("AUTH_COOKIE_SECURE")),
2026-04-14 20:17:29 -04:00
cors_allow_origins=_cors_allow_origins(app_base_url, os.getenv("CORS_ALLOW_ORIGINS")),
2026-04-08 06:03:48 -04:00
forgejo_base_url=_normalize_base_url(os.getenv("FORGEJO_BASE_URL")),
forgejo_token=os.getenv("FORGEJO_TOKEN") or None,
forgejo_oauth_client_id=os.getenv("FORGEJO_OAUTH_CLIENT_ID") or None,
forgejo_oauth_client_secret=os.getenv("FORGEJO_OAUTH_CLIENT_SECRET") or None,
forgejo_oauth_scopes=_parse_scopes(os.getenv("FORGEJO_OAUTH_SCOPES")),
2026-04-13 18:19:50 -04:00
forgejo_general_discussion_repo=os.getenv("FORGEJO_GENERAL_DISCUSSION_REPO") or None,
forgejo_webhook_secret=os.getenv("FORGEJO_WEBHOOK_SECRET") or None,
2026-04-08 06:03:48 -04:00
forgejo_repo_scan_limit=int(os.getenv("FORGEJO_REPO_SCAN_LIMIT", "30")),
2026-04-13 18:19:50 -04:00
forgejo_recent_issue_limit=int(os.getenv("FORGEJO_RECENT_ISSUE_LIMIT", "50")),
forgejo_cache_ttl_seconds=float(os.getenv("FORGEJO_CACHE_TTL_SECONDS", "60.0")),
2026-04-08 06:03:48 -04:00
forgejo_request_timeout_seconds=float(
os.getenv("FORGEJO_REQUEST_TIMEOUT_SECONDS", "10.0"),
),
calendar_feed_urls=_parse_calendar_feed_urls(os.getenv("CALENDAR_FEED_URLS")),
calendar_event_limit=int(os.getenv("CALENDAR_EVENT_LIMIT", "3")),
2026-04-08 06:03:48 -04:00
)