"""Blocklist domain models. Internal domain-focused models used by blocklist_service. These represent the business domain layer and are independent of HTTP response shapes. Response models are defined in `app.models.blocklist` and mappers convert domain models to response models at the router boundary. """ from __future__ import annotations from dataclasses import dataclass from enum import StrEnum @dataclass(frozen=True) class DomainBlocklistSource: """Blocklist source definition (domain model).""" id: int name: str url: str enabled: bool created_at: str updated_at: str @dataclass(frozen=True) class DomainImportLogEntry: """A single blocklist import run record (domain model).""" id: int source_id: int | None source_url: str timestamp: str ips_imported: int ips_skipped: int errors: str | None @dataclass(frozen=True) class DomainImportLogList: """Paginated list of import log entries (domain model).""" items: list[DomainImportLogEntry] total: int page: int page_size: int class DomainScheduleFrequency(StrEnum): """Available import schedule frequency presets (domain model).""" hourly = "hourly" daily = "daily" weekly = "weekly" @dataclass(frozen=True) class DomainScheduleConfig: """Import schedule configuration (domain model).""" frequency: DomainScheduleFrequency interval_hours: int = 24 hour: int = 3 minute: int = 0 day_of_week: int = 0 @dataclass(frozen=True) class DomainScheduleInfo: """Current schedule configuration with runtime metadata (domain model).""" config: DomainScheduleConfig next_run_at: str | None = None last_run_at: str | None = None last_run_errors: bool | None = None @dataclass(frozen=True) class DomainPreviewResult: """Result of previewing a blocklist URL (domain model).""" entries: list[str] total_lines: int valid_count: int skipped_count: int @dataclass(frozen=True) class DomainImportSourceResult: """Result of importing a single blocklist source (domain model).""" source_id: int | None source_url: str ips_imported: int ips_skipped: int error: str | None @dataclass(frozen=True) class DomainImportRunResult: """Aggregated result from a full import run (domain model).""" results: list[DomainImportSourceResult] total_imported: int total_skipped: int errors_count: int