# app.config from pydantic import BaseModel, HttpUrl, field_validator from pydantic_settings import BaseSettings, SettingsConfigDict class SiteConfig(BaseModel): """Schema for a single monitored site.""" name: str url: HttpUrl timeout_seconds: int = 10 expected_status: int = 200 expected_keywords: list[str] = [] max_retries: int = 1 @field_validator("timeout_seconds") @classmethod def timeout_must_be_positive(cls, v: int) -> int: if v <= 0: raise ValueError("timeout_seconds must be a positive integer") return v def to_dict(self) -> dict: """Return a plain dict compatible with check_site() in utils.py.""" return { "name": self.name, "url": str(self.url), "timeout_seconds": self.timeout_seconds, "expected_status": self.expected_status, "expected_keywords": self.expected_keywords, "max_retries": self.max_retries, } class Settings(BaseSettings): model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", ) # Discord discord_secret_key: str discord_client_id: str = "" discord_client_secret: str = "" # Database database_path: str = "uptime.db" # Polling — how often to check all sites (minimum 1 minute) poll_interval_minutes: int = 15 # Alerts — set alert_channel_id to 0 to disable alert_channel_id: int = 0 alert_cooldown_minutes: int = 30 # Sites — stored as a JSON array string in .env: monitored_sites: list[SiteConfig] = [] @field_validator("poll_interval_minutes") @classmethod def poll_interval_must_be_positive(cls, v: int) -> int: if v < 1: raise ValueError("poll_interval_minutes must be at least 1") return v settings = Settings()