311 lines
12 KiB
Python
311 lines
12 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
|
|
|
|
class StrictModel(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class FilePlanNodeWriteRequest(StrictModel):
|
|
node_id: str = Field(min_length=1, max_length=255)
|
|
code: str = Field(min_length=1, max_length=120)
|
|
label: str = Field(min_length=1, max_length=500)
|
|
parent_node_id: str | None = Field(default=None, max_length=255)
|
|
description: str | None = Field(default=None, max_length=10_000)
|
|
active: bool = True
|
|
valid_from: datetime | None = None
|
|
valid_to: datetime | None = None
|
|
recorded_at: datetime
|
|
expected_revision: int | None = Field(default=None, ge=1)
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
institutional_context: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_interval(self):
|
|
if self.valid_from and self.valid_to and self.valid_to <= self.valid_from:
|
|
raise ValueError("valid_to must be after valid_from")
|
|
return self
|
|
|
|
|
|
class RecordClassWriteRequest(StrictModel):
|
|
class_id: str = Field(min_length=1, max_length=255)
|
|
file_plan_node_id: str = Field(min_length=1, max_length=255)
|
|
key: str = Field(min_length=1, max_length=120)
|
|
label: str = Field(min_length=1, max_length=500)
|
|
description: str | None = Field(default=None, max_length=10_000)
|
|
metadata_requirements: list[str] = Field(default_factory=list, max_length=100)
|
|
allowed_source_types: list[str] = Field(default_factory=list, max_length=100)
|
|
retention_period_days: int | None = Field(default=None, ge=0, le=365_000)
|
|
closure_trigger: str | None = Field(default=None, max_length=255)
|
|
access_mode: Literal["tenant", "restricted"] = "tenant"
|
|
active: bool = True
|
|
valid_from: datetime | None = None
|
|
valid_to: datetime | None = None
|
|
recorded_at: datetime
|
|
expected_revision: int | None = Field(default=None, ge=1)
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
institutional_context: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_interval(self):
|
|
if self.valid_from and self.valid_to and self.valid_to <= self.valid_from:
|
|
raise ValueError("valid_to must be after valid_from")
|
|
return self
|
|
|
|
|
|
class RecordCreateRequest(StrictModel):
|
|
record_id: str | None = Field(default=None, max_length=255)
|
|
record_number: str = Field(min_length=1, max_length=255)
|
|
class_id: str = Field(min_length=1, max_length=255)
|
|
file_plan_node_id: str = Field(min_length=1, max_length=255)
|
|
title: str = Field(min_length=1, max_length=500)
|
|
description: str | None = Field(default=None, max_length=20_000)
|
|
state: Literal["planned", "open"] = "open"
|
|
source_authority_mode: Literal[
|
|
"native_authoritative",
|
|
"external_authoritative",
|
|
"external_mirror",
|
|
"governed_sync",
|
|
"governance_overlay",
|
|
"linked_reference",
|
|
] = "native_authoritative"
|
|
access_mode: Literal["tenant", "restricted"] = "tenant"
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
classification: str | None = Field(default=None, max_length=120)
|
|
responsible_unit_id: str | None = Field(default=None, max_length=255)
|
|
responsible_function_id: str | None = Field(default=None, max_length=255)
|
|
external_reference: dict[str, Any] = Field(default_factory=dict)
|
|
institutional_context: dict[str, Any] = Field(default_factory=dict)
|
|
valid_from: datetime | None = None
|
|
valid_to: datetime | None = None
|
|
recorded_at: datetime
|
|
change_reason: str = Field(min_length=1, max_length=2_000)
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_interval(self):
|
|
if self.valid_from and self.valid_to and self.valid_to <= self.valid_from:
|
|
raise ValueError("valid_to must be after valid_from")
|
|
return self
|
|
|
|
|
|
class RecordUpdateRequest(StrictModel):
|
|
expected_revision: int = Field(ge=1)
|
|
title: str | None = Field(default=None, min_length=1, max_length=500)
|
|
description: str | None = Field(default=None, max_length=20_000)
|
|
class_id: str | None = Field(default=None, min_length=1, max_length=255)
|
|
file_plan_node_id: str | None = Field(default=None, min_length=1, max_length=255)
|
|
state: Literal["planned", "open"] | None = None
|
|
access_mode: Literal["tenant", "restricted"] | None = None
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
classification: str | None = Field(default=None, max_length=120)
|
|
responsible_unit_id: str | None = Field(default=None, max_length=255)
|
|
responsible_function_id: str | None = Field(default=None, max_length=255)
|
|
institutional_context: dict[str, Any] | None = None
|
|
valid_from: datetime | None = None
|
|
valid_to: datetime | None = None
|
|
recorded_at: datetime
|
|
change_reason: str = Field(min_length=1, max_length=2_000)
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_interval(self):
|
|
if self.valid_from and self.valid_to and self.valid_to <= self.valid_from:
|
|
raise ValueError("valid_to must be after valid_from")
|
|
return self
|
|
|
|
|
|
class RecordVolumeCreateRequest(StrictModel):
|
|
volume_id: str | None = Field(default=None, max_length=255)
|
|
label: str = Field(min_length=1, max_length=500)
|
|
valid_from: datetime | None = None
|
|
valid_to: datetime | None = None
|
|
recorded_at: datetime
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
|
|
class RecordSourceLocatorRequest(StrictModel):
|
|
source_module: str = Field(min_length=1, max_length=100)
|
|
resource_type: str = Field(min_length=1, max_length=120)
|
|
resource_id: str = Field(min_length=1, max_length=500)
|
|
source_revision: str = Field(min_length=1, max_length=255)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class RecordItemCreateRequest(StrictModel):
|
|
source: RecordSourceLocatorRequest
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
filing_reason: str = Field(min_length=1, max_length=2_000)
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
volume_id: str | None = Field(default=None, max_length=255)
|
|
relationship: str = Field(default="contains", min_length=1, max_length=120)
|
|
institutional_context: dict[str, Any] = Field(default_factory=dict)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class RecordLifecycleActionRequest(StrictModel):
|
|
expected_revision: int = Field(ge=1)
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
reason: str = Field(min_length=1, max_length=2_000)
|
|
recorded_at: datetime
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
|
|
class RecordCloseRequest(RecordLifecycleActionRequest):
|
|
retention_trigger_at: datetime | None = None
|
|
restart_retention: bool = False
|
|
|
|
|
|
class RecordAppraisalRequest(RecordLifecycleActionRequest):
|
|
outcome: Literal["retain", "transfer", "destroy", "reclassify"]
|
|
policy_refs: list[str] = Field(default_factory=list, max_length=100)
|
|
override_retention_not_due: bool = False
|
|
|
|
|
|
class RecordHoldCreateRequest(StrictModel):
|
|
hold_id: str | None = Field(default=None, max_length=255)
|
|
expected_record_revision: int = Field(ge=1)
|
|
reason: str = Field(min_length=1, max_length=10_000)
|
|
authority: str = Field(min_length=1, max_length=500)
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
scope: dict[str, Any] = Field(default_factory=dict)
|
|
effective_from: datetime | None = None
|
|
effective_to: datetime | None = None
|
|
policy_refs: list[str] = Field(default_factory=list, max_length=100)
|
|
institutional_context: dict[str, Any] = Field(default_factory=dict)
|
|
recorded_at: datetime
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_interval(self):
|
|
if (
|
|
self.effective_from
|
|
and self.effective_to
|
|
and self.effective_to <= self.effective_from
|
|
):
|
|
raise ValueError("effective_to must be after effective_from")
|
|
return self
|
|
|
|
|
|
class RecordHoldReleaseRequest(StrictModel):
|
|
expected_hold_revision: int = Field(ge=1)
|
|
reason: str = Field(min_length=1, max_length=2_000)
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
recorded_at: datetime
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
|
|
class RecordDispositionCreateRequest(StrictModel):
|
|
disposition_id: str | None = Field(default=None, max_length=255)
|
|
expected_record_revision: int = Field(ge=1)
|
|
action: Literal["retain", "transfer", "destroy", "reclassify"]
|
|
reason: str = Field(min_length=1, max_length=10_000)
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
policy_refs: list[str] = Field(default_factory=list, max_length=100)
|
|
institutional_context: dict[str, Any] = Field(default_factory=dict)
|
|
recorded_at: datetime
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
|
|
class RecordDispositionFinalizeRequest(StrictModel):
|
|
expected_disposition_revision: int = Field(ge=1)
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
recorded_at: datetime
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
|
|
class RecordDispositionWithdrawRequest(RecordDispositionFinalizeRequest):
|
|
reason: str = Field(min_length=1, max_length=2_000)
|
|
|
|
|
|
class RecordTransferPackageCreateRequest(StrictModel):
|
|
package_id: str | None = Field(default=None, max_length=255)
|
|
disposition_id: str = Field(min_length=1, max_length=255)
|
|
expected_record_revision: int = Field(ge=1)
|
|
provider_id: str = Field(min_length=1, max_length=100)
|
|
profile: str = Field(min_length=1, max_length=255)
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
recorded_at: datetime
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
|
|
class RecordTransferDispatchRequest(StrictModel):
|
|
expected_package_revision: int = Field(ge=1)
|
|
purpose: str = Field(min_length=1, max_length=255)
|
|
recorded_at: datetime
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
|
|
|
|
class RecordListResponse(StrictModel):
|
|
records: list[dict[str, Any]]
|
|
total: int
|
|
offset: int
|
|
limit: int
|
|
|
|
|
|
class RecordCatalogResponse(StrictModel):
|
|
file_plan: list[dict[str, Any]]
|
|
classes: list[dict[str, Any]]
|
|
|
|
|
|
class RecordDetailResponse(StrictModel):
|
|
record: dict[str, Any]
|
|
volumes: list[dict[str, Any]]
|
|
items: list[dict[str, Any]]
|
|
chronology: list[dict[str, Any]]
|
|
holds: list[dict[str, Any]]
|
|
dispositions: list[dict[str, Any]]
|
|
transfer_packages: list[dict[str, Any]]
|
|
access_explanation: dict[str, Any]
|
|
|
|
|
|
class RecordSourceProviderResponse(StrictModel):
|
|
providers: list[dict[str, Any]]
|
|
|
|
|
|
class RecordArchiveProviderResponse(StrictModel):
|
|
providers: list[dict[str, Any]]
|
|
|
|
|
|
class RecordRecoveryStatusResponse(StrictModel):
|
|
record_id: str
|
|
record_revision: int
|
|
evidence_sha256: str
|
|
healthy: bool
|
|
source_checks: list[dict[str, Any]]
|
|
package_checks: list[dict[str, Any]]
|
|
recovery_operations: list[dict[str, Any]]
|
|
failure_count: int
|
|
limitations: list[str]
|
|
|
|
|
|
__all__ = [
|
|
"FilePlanNodeWriteRequest",
|
|
"RecordAppraisalRequest",
|
|
"RecordArchiveProviderResponse",
|
|
"RecordCatalogResponse",
|
|
"RecordClassWriteRequest",
|
|
"RecordCloseRequest",
|
|
"RecordCreateRequest",
|
|
"RecordDetailResponse",
|
|
"RecordDispositionCreateRequest",
|
|
"RecordDispositionFinalizeRequest",
|
|
"RecordDispositionWithdrawRequest",
|
|
"RecordHoldCreateRequest",
|
|
"RecordHoldReleaseRequest",
|
|
"RecordItemCreateRequest",
|
|
"RecordLifecycleActionRequest",
|
|
"RecordListResponse",
|
|
"RecordRecoveryStatusResponse",
|
|
"RecordSourceProviderResponse",
|
|
"RecordTransferDispatchRequest",
|
|
"RecordTransferPackageCreateRequest",
|
|
"RecordUpdateRequest",
|
|
"RecordVolumeCreateRequest",
|
|
]
|