306 lines
8.8 KiB
Python
306 lines
8.8 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, Field, model_validator
|
|
|
|
|
|
class FeedAcquireRequest(BaseModel):
|
|
url: str = Field(min_length=1, max_length=2000)
|
|
max_entries: int = Field(default=2_000, ge=1, le=10_000)
|
|
|
|
|
|
class FeedImportRequest(FeedAcquireRequest):
|
|
name: str = Field(min_length=1, max_length=300)
|
|
source_name: str = Field(
|
|
min_length=1,
|
|
max_length=120,
|
|
pattern=r"^[A-Za-z_][A-Za-z0-9_]*$",
|
|
)
|
|
description: str | None = Field(default=None, max_length=4000)
|
|
|
|
|
|
class FeedEntryPayload(BaseModel):
|
|
id: str = Field(min_length=1, max_length=2000)
|
|
title: str = Field(min_length=1, max_length=1000)
|
|
url: str | None = Field(default=None, max_length=2000)
|
|
summary: str | None = None
|
|
content: str | None = None
|
|
author: str | None = Field(default=None, max_length=500)
|
|
published_at: datetime | None = None
|
|
updated_at: datetime | None = None
|
|
categories: list[str] = Field(default_factory=list, max_length=100)
|
|
enclosures: list[dict[str, Any]] = Field(default_factory=list, max_length=100)
|
|
visibility: Literal["public", "tenant", "private"] = "public"
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FeedPublicationEntryPayload(FeedEntryPayload):
|
|
source_kind: Literal["event", "publication", "case", "report"]
|
|
source_module: str = Field(
|
|
min_length=1,
|
|
max_length=100,
|
|
pattern=r"^[a-z][a-z0-9_]*$",
|
|
)
|
|
source_ref: str = Field(min_length=1, max_length=500)
|
|
source_revision: str | None = Field(default=None, max_length=200)
|
|
|
|
|
|
class FeedDocumentResponse(BaseModel):
|
|
format: Literal["rss", "atom"]
|
|
title: str
|
|
source_url: str
|
|
description: str | None = None
|
|
home_url: str | None = None
|
|
language: str | None = None
|
|
updated_at: datetime | None = None
|
|
acquired_at: datetime | None = None
|
|
fresh_until: datetime | None = None
|
|
etag: str | None = None
|
|
last_modified: str | None = None
|
|
content_type: str | None = None
|
|
sha256: str
|
|
entries: list[FeedEntryPayload]
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FeedRenderPayload(BaseModel):
|
|
format: Literal["rss", "atom"]
|
|
title: str = Field(min_length=1, max_length=1000)
|
|
feed_url: str = Field(min_length=1, max_length=2000)
|
|
home_url: str = Field(min_length=1, max_length=2000)
|
|
description: str | None = None
|
|
language: str | None = Field(default=None, max_length=100)
|
|
entries: list[FeedPublicationEntryPayload] = Field(
|
|
default_factory=list,
|
|
max_length=10_000,
|
|
)
|
|
audience: Literal["public", "tenant", "private"] = "public"
|
|
|
|
|
|
class SnapshotCreateRequest(BaseModel):
|
|
name: str = Field(min_length=1, max_length=300)
|
|
source_name: str = Field(
|
|
min_length=1,
|
|
max_length=120,
|
|
pattern=r"^[A-Za-z_][A-Za-z0-9_]*$",
|
|
)
|
|
description: str | None = Field(default=None, max_length=4000)
|
|
format: Literal["json", "csv"] = "json"
|
|
rows: list[dict[str, Any]] | None = Field(default=None, max_length=10_000)
|
|
csv_text: str | None = Field(default=None, max_length=5_000_000)
|
|
delimiter: Literal[",", ";", "\t", "|"] = ","
|
|
|
|
@model_validator(mode="after")
|
|
def validate_payload(self) -> "SnapshotCreateRequest":
|
|
if self.format == "json" and self.rows is None:
|
|
raise ValueError("JSON snapshots require rows.")
|
|
if self.format == "json" and self.csv_text is not None:
|
|
raise ValueError("JSON snapshots cannot include CSV text.")
|
|
if self.format == "csv" and not self.csv_text:
|
|
raise ValueError("CSV snapshots require CSV text.")
|
|
if self.format == "csv" and self.rows is not None:
|
|
raise ValueError("CSV snapshots cannot include JSON rows.")
|
|
return self
|
|
|
|
|
|
class ManagedFileSourceCreateRequest(BaseModel):
|
|
name: str = Field(min_length=1, max_length=300)
|
|
source_name: str = Field(
|
|
min_length=1,
|
|
max_length=120,
|
|
pattern=r"^[A-Za-z_][A-Za-z0-9_]*$",
|
|
)
|
|
description: str | None = Field(default=None, max_length=4000)
|
|
file_asset_id: str = Field(min_length=1, max_length=36)
|
|
file_version_id: str | None = Field(default=None, min_length=1, max_length=36)
|
|
delimiter: Literal[",", ";", "\t", "|"] = ","
|
|
sheet_name: str | None = Field(default=None, min_length=1, max_length=255)
|
|
|
|
|
|
class SqlSourceCreateRequest(BaseModel):
|
|
name: str = Field(min_length=1, max_length=300)
|
|
source_name: str = Field(
|
|
min_length=1,
|
|
max_length=120,
|
|
pattern=r"^[A-Za-z_][A-Za-z0-9_]*$",
|
|
)
|
|
description: str | None = Field(default=None, max_length=4000)
|
|
configuration_id: str = Field(min_length=1, max_length=36)
|
|
schema_name: str | None = Field(
|
|
default=None,
|
|
pattern=r"^[A-Za-z_][A-Za-z0-9_$-]{0,127}$",
|
|
)
|
|
table_name: str = Field(
|
|
min_length=1,
|
|
max_length=128,
|
|
pattern=r"^[A-Za-z_][A-Za-z0-9_$-]{0,127}$",
|
|
)
|
|
|
|
|
|
class TabularColumnResponse(BaseModel):
|
|
name: str
|
|
data_type: str
|
|
nullable: bool
|
|
|
|
|
|
class TabularPushdownResponse(BaseModel):
|
|
projections: bool
|
|
pagination: bool
|
|
filters: list[str]
|
|
aggregations: list[str]
|
|
sorting: list[str]
|
|
|
|
|
|
class TabularHealthResponse(BaseModel):
|
|
status: Literal["healthy", "warning", "error", "unknown"]
|
|
code: str
|
|
summary: str
|
|
checked_at: str | None
|
|
details: dict[str, Any]
|
|
|
|
|
|
class TabularPreviewDiagnosticResponse(BaseModel):
|
|
severity: Literal["info", "warning", "error"]
|
|
code: str
|
|
message: str
|
|
details: dict[str, Any]
|
|
|
|
|
|
class TabularSourceResponse(BaseModel):
|
|
ref: str
|
|
provider: str
|
|
source_name: str
|
|
name: str
|
|
description: str | None
|
|
columns: list[TabularColumnResponse]
|
|
schema_version: str
|
|
fingerprint: str
|
|
row_count: int | None
|
|
byte_count: int | None
|
|
updated_at: str | None
|
|
capabilities: list[str]
|
|
metadata: dict[str, Any]
|
|
source_mode: Literal["live", "cached", "file_backed", "static"]
|
|
pushdown: TabularPushdownResponse
|
|
health: TabularHealthResponse
|
|
|
|
|
|
class TabularSourceListResponse(BaseModel):
|
|
sources: list[TabularSourceResponse]
|
|
|
|
|
|
class TabularSourcePreviewResponse(BaseModel):
|
|
source: TabularSourceResponse
|
|
rows: list[dict[str, Any]]
|
|
total_rows: int
|
|
truncated: bool
|
|
returned_bytes: int
|
|
elapsed_ms: int
|
|
effective_row_limit: int
|
|
effective_byte_limit: int
|
|
effective_timeout_ms: int
|
|
diagnostics: list[TabularPreviewDiagnosticResponse]
|
|
|
|
|
|
class TabularSourceDeleteResponse(BaseModel):
|
|
deleted: bool
|
|
source_ref: str
|
|
|
|
|
|
class SanctionsSourceResponse(BaseModel):
|
|
provider_id: str
|
|
publisher: str
|
|
jurisdiction: str
|
|
list_type: str
|
|
source_id: str
|
|
source_url: str | None
|
|
parser_version: str
|
|
licence_notes: str
|
|
trust_notes: str
|
|
|
|
|
|
class SanctionsSourceListResponse(BaseModel):
|
|
sources: list[SanctionsSourceResponse]
|
|
|
|
|
|
class SanctionsSnapshotResponse(BaseModel):
|
|
ref: str
|
|
provider_id: str
|
|
publisher: str
|
|
jurisdiction: str
|
|
list_type: str
|
|
source_id: str
|
|
source_version: str
|
|
publication_at: datetime | None
|
|
effective_at: datetime | None
|
|
acquired_at: datetime
|
|
content_type: str
|
|
byte_count: int
|
|
sha256: str
|
|
parser_version: str
|
|
raw_evidence_ref: str
|
|
connector_run_id: str
|
|
signature_evidence: dict[str, Any]
|
|
licence_notes: str | None
|
|
trust_notes: str | None
|
|
transport_evidence: dict[str, Any]
|
|
|
|
|
|
class SanctionsSnapshotListResponse(BaseModel):
|
|
snapshots: list[SanctionsSnapshotResponse]
|
|
|
|
|
|
class SanctionsAcquisitionRunResponse(BaseModel):
|
|
id: str
|
|
provider_id: str
|
|
source_id: str
|
|
status: str
|
|
attempt_count: int
|
|
request_evidence: dict[str, Any]
|
|
response_evidence: dict[str, Any]
|
|
started_at: datetime
|
|
finished_at: datetime | None
|
|
snapshot_id: str | None
|
|
error: str | None
|
|
|
|
|
|
class SanctionsAcquisitionRunListResponse(BaseModel):
|
|
runs: list[SanctionsAcquisitionRunResponse]
|
|
|
|
|
|
class SanctionsRefreshResponse(BaseModel):
|
|
run_id: str
|
|
provider_id: str
|
|
status: str
|
|
snapshot: SanctionsSnapshotResponse | None
|
|
error: str | None
|
|
|
|
|
|
__all__ = [
|
|
"FeedAcquireRequest",
|
|
"FeedDocumentResponse",
|
|
"FeedEntryPayload",
|
|
"FeedImportRequest",
|
|
"FeedRenderPayload",
|
|
"ManagedFileSourceCreateRequest",
|
|
"SnapshotCreateRequest",
|
|
"SqlSourceCreateRequest",
|
|
"SanctionsAcquisitionRunListResponse",
|
|
"SanctionsAcquisitionRunResponse",
|
|
"SanctionsRefreshResponse",
|
|
"SanctionsSnapshotListResponse",
|
|
"SanctionsSnapshotResponse",
|
|
"SanctionsSourceListResponse",
|
|
"SanctionsSourceResponse",
|
|
"TabularColumnResponse",
|
|
"TabularHealthResponse",
|
|
"TabularPreviewDiagnosticResponse",
|
|
"TabularPushdownResponse",
|
|
"TabularSourceDeleteResponse",
|
|
"TabularSourceListResponse",
|
|
"TabularSourcePreviewResponse",
|
|
"TabularSourceResponse",
|
|
]
|