from datetime import datetime, timezone from enum import Enum from typing import Annotated from uuid import UUID from pydantic import AnyHttpUrl, BaseModel, ConfigDict, Field, StringConstraints, field_validator Name = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=100)] def utcnow() -> datetime: return datetime.now(timezone.utc) class MonitorStatus(str, Enum): unknown = "unknown" up = "up" down = "down" error = "error" class MonitorCreate(BaseModel): name: Name url: AnyHttpUrl @field_validator("url") @classmethod def no_credentials(cls, value: AnyHttpUrl) -> AnyHttpUrl: if value.username or value.password: raise ValueError("URL credentials are not allowed") return value class MonitorUpdate(MonitorCreate): pass class Monitor(BaseModel): model_config = ConfigDict(frozen=True) id: UUID name: str url: AnyHttpUrl status: MonitorStatus = MonitorStatus.unknown created_at: datetime updated_at: datetime checked_at: datetime | None = None latency_ms: float | None = Field(default=None, ge=0) http_status: int | None = Field(default=None, ge=100, le=599) error: str | None = None class CheckResult(BaseModel): status: MonitorStatus checked_at: datetime latency_ms: float = Field(ge=0) http_status: int | None = None error: str | None = None class StatusResponse(CheckResult): id: UUID class ProbeResponse(BaseModel): status: str