Files
govoplan-audit/src/govoplan_audit/backend/api/v1/schemas.py
T

145 lines
4.6 KiB
Python

from __future__ import annotations
from datetime import datetime
from typing import Any, Literal
from pydantic import BaseModel, ConfigDict, Field, model_validator
from govoplan_core.api.v1.schemas import DeltaDeletedItem
class AuditAdminItem(BaseModel):
id: str
scope: Literal["tenant", "system"] = "tenant"
tenant_id: str | None = None
actor_email: str | None = None
action: str
object_type: str | None = None
object_id: str | None = None
details: dict[str, Any] = Field(default_factory=dict)
created_at: datetime
class AuditAdminListResponse(BaseModel):
items: list[AuditAdminItem]
total: int
page: int = 1
page_size: int = 100
pages: int = 1
cursor: str | None = None
next_cursor: str | None = None
class AuditAdminDeltaResponse(AuditAdminListResponse):
deleted: list[DeltaDeletedItem] = Field(default_factory=list)
watermark: str | None = None
has_more: bool = False
full: bool = False
class AuditLogItemResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: str
tenant_id: str | None = None
user_id: str | None = None
api_key_id: str | None = None
action: str
object_type: str | None = None
object_id: str | None = None
details: dict[str, Any] | None = None
created_at: datetime
class AuditLogListResponse(BaseModel):
items: list[AuditLogItemResponse]
class EventDeliveryMetricsResponse(BaseModel):
events: dict[str, int] = Field(default_factory=dict)
deliveries: dict[str, int] = Field(default_factory=dict)
consumers: dict[str, dict[str, int]] = Field(default_factory=dict)
oldest_due_at: datetime | None = None
class EventDeliveryReplayRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
reason: str = Field(min_length=1, max_length=2000)
class EventDeliveryReplayResponse(BaseModel):
event_id: str
consumer_id: str
delivery_key: str
status: str
attempts: int
replay_count: int
last_replayed_at: datetime | None = None
last_replayed_by: str | None = None
last_replay_reason: str | None = None
last_error: str | None = None
class EvidenceBundleReferenceRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
reference_id: str = Field(min_length=1, max_length=200)
kind: str = Field(min_length=1, max_length=80)
owner_module: str = Field(min_length=1, max_length=100)
locator: str = Field(min_length=1, max_length=2048)
content_sha256: str | None = Field(default=None, pattern=r"^[0-9A-Fa-f]{64}$")
required: bool = True
class EvidenceBundleExportRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
scope: Literal["tenant", "system", "all"] = "tenant"
tenant_id: str | None = Field(default=None, max_length=36)
since: datetime | None = None
until: datetime | None = None
record_ids: list[str] = Field(default_factory=list, max_length=500)
action: str | None = Field(default=None, max_length=100)
object_type: str | None = Field(default=None, max_length=100)
object_id: str | None = Field(default=None, max_length=100)
max_records: int = Field(default=500, ge=1, le=500)
references: list[EvidenceBundleReferenceRequest] = Field(
default_factory=list,
max_length=200,
)
sign: bool = False
@model_validator(mode="after")
def validate_window_and_selection(self):
for label, value in (("since", self.since), ("until", self.until)):
if value is not None and (value.tzinfo is None or value.utcoffset() is None):
raise ValueError(f"Evidence bundle {label} must include a timezone.")
if self.since and self.until and self.until < self.since:
raise ValueError("Evidence bundle until must not precede since.")
if len(self.record_ids) != len(set(self.record_ids)):
raise ValueError("Evidence bundle record ids must be unique.")
reference_ids = [item.reference_id for item in self.references]
if len(reference_ids) != len(set(reference_ids)):
raise ValueError("Evidence bundle reference ids must be unique.")
return self
class EvidenceBundleResponse(BaseModel):
id: str
scope: Literal["tenant", "system", "all"]
tenant_id: str | None = None
status: Literal["pending", "ready", "failed"]
bundle_sha256: str | None = None
record_count: int
reference_count: int
generated_at: datetime | None = None
downloaded_at: datetime | None = None
error_code: str | None = None
created_at: datetime
download_url: str | None = None
class EvidenceBundleDownloadResponse(BaseModel):
bundle: dict[str, Any]