"""Jail domain models. Internal domain-focused models used by jail_service. These represent the business domain layer and are independent of HTTP response shapes. Response models are defined in `app.models.jail` and mappers convert domain models to response models at the router boundary. """ from __future__ import annotations from dataclasses import dataclass @dataclass(frozen=True) class DomainJailStatus: """Runtime metrics for a single jail (domain model).""" currently_banned: int total_banned: int currently_failed: int total_failed: int @dataclass(frozen=True) class DomainBantimeEscalation: """Incremental ban-time escalation configuration (domain model).""" increment: bool = False factor: float | None = None formula: str | None = None multipliers: str | None = None max_time: int | None = None rnd_time: int | None = None overall_jails: bool = False @dataclass(frozen=True) class DomainJailSummary: """Lightweight jail entry for the overview list (domain model).""" name: str enabled: bool running: bool idle: bool backend: str find_time: int ban_time: int max_retry: int status: DomainJailStatus | None = None @dataclass(frozen=True) class DomainJailList: """List of active jails (domain model).""" items: list[DomainJailSummary] total: int @dataclass(frozen=True) class DomainJail: """Full jail configuration (domain model).""" name: str enabled: bool running: bool idle: bool backend: str log_paths: list[str] fail_regex: list[str] ignore_regex: list[str] ignore_ips: list[str] find_time: int ban_time: int max_retry: int actions: list[str] date_pattern: str | None = None log_encoding: str = "UTF-8" bantime_escalation: DomainBantimeEscalation | None = None status: DomainJailStatus | None = None @dataclass(frozen=True) class DomainActiveBan: """A currently active ban entry from a jail (domain model).""" ip: str jail: str banned_at: str | None = None expires_at: str | None = None ban_count: int = 1 country: str | None = None @dataclass(frozen=True) class DomainJailBannedIps: """Paginated list of currently banned IPs for a jail (domain model).""" items: list[DomainActiveBan] total: int page: int page_size: int @dataclass(frozen=True) class DomainJailDetail: """Full jail with supplemental metadata (domain model).""" jail: DomainJail ignore_list: list[str] ignore_self: bool