"""Geo and IP lookup Pydantic models. Response models for the ``GET /api/geo/lookup/{ip}`` endpoint. """ from pydantic import BaseModel, ConfigDict, Field class GeoDetail(BaseModel): """Enriched geolocation data for an IP address. Populated from the ip-api.com free API. """ model_config = ConfigDict(strict=True) country_code: str | None = Field( default=None, description="ISO 3166-1 alpha-2 country code.", ) country_name: str | None = Field( default=None, description="Human-readable country name.", ) asn: str | None = Field( default=None, description="Autonomous System Number (e.g. ``'AS3320'``).", ) org: str | None = Field( default=None, description="Organisation associated with the ASN.", ) class GeoCacheStatsResponse(BaseModel): """Response for ``GET /api/geo/stats``. Exposes diagnostic counters of the geo cache subsystem so operators can assess resolution health from the UI or CLI. """ model_config = ConfigDict(strict=True) cache_size: int = Field(..., description="Number of positive entries in the in-memory cache.") unresolved: int = Field(..., description="Number of geo_cache rows with country_code IS NULL.") neg_cache_size: int = Field(..., description="Number of entries in the in-memory negative cache.") dirty_size: int = Field(..., description="Number of newly resolved entries not yet flushed to disk.") class IpLookupResponse(BaseModel): """Response for ``GET /api/geo/lookup/{ip}``. Aggregates current ban status and geographical information for an IP. """ model_config = ConfigDict(strict=True) ip: str = Field(..., description="The queried IP address.") currently_banned_in: list[str] = Field( default_factory=list, description="Names of jails where this IP is currently banned.", ) geo: GeoDetail | None = Field( default=None, description="Enriched geographical and network information.", )