intermittent commit
This commit is contained in:
510
src/govoplan_addresses/backend/schemas.py
Normal file
510
src/govoplan_addresses/backend/schemas.py
Normal file
@@ -0,0 +1,510 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, SecretStr
|
||||
|
||||
|
||||
AddressBookScope = Literal["user", "group", "tenant", "system"]
|
||||
AddressSyncDirection = Literal["read_only", "import", "export", "two_way"]
|
||||
AddressSyncStatus = Literal["idle", "running", "succeeded", "failed", "conflict", "disabled"]
|
||||
AddressSyncDiagnosticSeverity = Literal["debug", "info", "warning", "error"]
|
||||
AddressSyncConflictStatus = Literal["open", "resolved", "ignored"]
|
||||
AddressSyncConflictResolution = Literal["keep_local", "use_remote", "merge", "manual", "ignored"]
|
||||
AddressCardDavAuthType = Literal["none", "basic", "bearer"]
|
||||
AddressSyncPlanAction = Literal["create", "update", "delete", "remote_create", "remote_update", "remote_delete", "conflict", "unchanged", "error"]
|
||||
|
||||
|
||||
class ContactEmailPayload(BaseModel):
|
||||
label: str | None = Field(default=None, max_length=80)
|
||||
email: str = Field(max_length=320)
|
||||
is_primary: bool = False
|
||||
|
||||
|
||||
class ContactPhonePayload(BaseModel):
|
||||
label: str | None = Field(default=None, max_length=80)
|
||||
phone: str = Field(max_length=100)
|
||||
is_primary: bool = False
|
||||
|
||||
|
||||
class ContactPostalAddressPayload(BaseModel):
|
||||
label: str | None = Field(default=None, max_length=80)
|
||||
street: str | None = Field(default=None, max_length=500)
|
||||
postal_code: str | None = Field(default=None, max_length=40)
|
||||
locality: str | None = Field(default=None, max_length=255)
|
||||
region: str | None = Field(default=None, max_length=255)
|
||||
country: str | None = Field(default=None, max_length=255)
|
||||
is_primary: bool = False
|
||||
|
||||
|
||||
class AddressBookCreateRequest(BaseModel):
|
||||
scope_type: AddressBookScope = "user"
|
||||
group_id: str | None = Field(default=None, max_length=36)
|
||||
name: str = Field(min_length=1, max_length=255)
|
||||
description: str | None = None
|
||||
|
||||
|
||||
class AddressBookUpdateRequest(BaseModel):
|
||||
name: str | None = Field(default=None, min_length=1, max_length=255)
|
||||
description: str | None = None
|
||||
|
||||
|
||||
class AddressBookResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
tenant_id: str | None = None
|
||||
scope_type: AddressBookScope
|
||||
scope_id: str | None = None
|
||||
name: str
|
||||
description: str | None = None
|
||||
source_kind: str
|
||||
source_ref: str | None = None
|
||||
read_only: bool
|
||||
sync_status: str | None = None
|
||||
sync_error: str | None = None
|
||||
contact_count: int = 0
|
||||
deleted_at: datetime | None = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class AddressBookListResponse(BaseModel):
|
||||
address_books: list[AddressBookResponse]
|
||||
|
||||
|
||||
class AddressListCreateRequest(BaseModel):
|
||||
name: str = Field(min_length=1, max_length=255)
|
||||
description: str | None = None
|
||||
|
||||
|
||||
class AddressListUpdateRequest(BaseModel):
|
||||
name: str | None = Field(default=None, min_length=1, max_length=255)
|
||||
description: str | None = None
|
||||
|
||||
|
||||
class AddressListEntryCreateRequest(BaseModel):
|
||||
contact_id: str = Field(max_length=36)
|
||||
contact_email_id: str | None = Field(default=None, max_length=36)
|
||||
contact_postal_address_id: str | None = Field(default=None, max_length=36)
|
||||
label: str | None = Field(default=None, max_length=255)
|
||||
|
||||
|
||||
class AddressListResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
tenant_id: str | None = None
|
||||
address_book_id: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
source_kind: str
|
||||
source_ref: str | None = None
|
||||
read_only: bool
|
||||
entry_count: int = 0
|
||||
deleted_at: datetime | None = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class AddressListListResponse(BaseModel):
|
||||
address_lists: list[AddressListResponse]
|
||||
|
||||
|
||||
class AddressListEntryResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
address_list_id: str
|
||||
contact_id: str
|
||||
contact_email_id: str | None = None
|
||||
contact_postal_address_id: str | None = None
|
||||
target_kind: str
|
||||
label: str | None = None
|
||||
order_index: int
|
||||
contact_display_name: str
|
||||
email: str | None = None
|
||||
postal_address: str | None = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class AddressListEntryListResponse(BaseModel):
|
||||
entries: list[AddressListEntryResponse]
|
||||
|
||||
|
||||
class ContactCreateRequest(BaseModel):
|
||||
display_name: str | None = Field(default=None, max_length=255)
|
||||
given_name: str | None = Field(default=None, max_length=255)
|
||||
family_name: str | None = Field(default=None, max_length=255)
|
||||
organization: str | None = Field(default=None, max_length=255)
|
||||
role_title: str | None = Field(default=None, max_length=255)
|
||||
note: str | None = None
|
||||
tags: list[str] = Field(default_factory=list)
|
||||
emails: list[ContactEmailPayload] = Field(default_factory=list)
|
||||
phones: list[ContactPhonePayload] = Field(default_factory=list)
|
||||
postal_addresses: list[ContactPostalAddressPayload] = Field(default_factory=list)
|
||||
provenance: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class ContactUpdateRequest(BaseModel):
|
||||
display_name: str | None = Field(default=None, max_length=255)
|
||||
given_name: str | None = Field(default=None, max_length=255)
|
||||
family_name: str | None = Field(default=None, max_length=255)
|
||||
organization: str | None = Field(default=None, max_length=255)
|
||||
role_title: str | None = Field(default=None, max_length=255)
|
||||
note: str | None = None
|
||||
tags: list[str] | None = None
|
||||
emails: list[ContactEmailPayload] | None = None
|
||||
phones: list[ContactPhonePayload] | None = None
|
||||
postal_addresses: list[ContactPostalAddressPayload] | None = None
|
||||
provenance: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class ContactEmailResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
label: str | None = None
|
||||
email: str
|
||||
is_primary: bool
|
||||
|
||||
|
||||
class ContactPhoneResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
label: str | None = None
|
||||
phone: str
|
||||
is_primary: bool
|
||||
|
||||
|
||||
class ContactPostalAddressResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
label: str | None = None
|
||||
street: str | None = None
|
||||
postal_code: str | None = None
|
||||
locality: str | None = None
|
||||
region: str | None = None
|
||||
country: str | None = None
|
||||
is_primary: bool
|
||||
|
||||
|
||||
class ContactResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
tenant_id: str | None = None
|
||||
address_book_id: str
|
||||
display_name: str
|
||||
given_name: str | None = None
|
||||
family_name: str | None = None
|
||||
organization: str | None = None
|
||||
role_title: str | None = None
|
||||
note: str | None = None
|
||||
tags: list[str]
|
||||
source_kind: str
|
||||
source_ref: str | None = None
|
||||
source_payload_kind: str | None = None
|
||||
source_revision: str | None = None
|
||||
provenance: dict[str, Any]
|
||||
emails: list[ContactEmailResponse]
|
||||
phones: list[ContactPhoneResponse]
|
||||
postal_addresses: list[ContactPostalAddressResponse]
|
||||
deleted_at: datetime | None = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class ContactListResponse(BaseModel):
|
||||
contacts: list[ContactResponse]
|
||||
|
||||
|
||||
class AddressLookupResponse(BaseModel):
|
||||
contacts: list[ContactResponse]
|
||||
|
||||
|
||||
class AddressBookWriteDecisionResponse(BaseModel):
|
||||
address_book_id: str
|
||||
address_book_label: str | None = None
|
||||
operation: str
|
||||
allowed: bool
|
||||
reason: str
|
||||
message: str
|
||||
scope_type: AddressBookScope | None = None
|
||||
scope_id: str | None = None
|
||||
tenant_id: str | None = None
|
||||
source_kind: str | None = None
|
||||
read_only: bool = False
|
||||
required_scopes: list[str] = Field(default_factory=list)
|
||||
provenance: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class AddressBookWriteTargetsResponse(BaseModel):
|
||||
targets: list[AddressBookWriteDecisionResponse] = Field(default_factory=list)
|
||||
|
||||
|
||||
class AddressSyncSourceCreateRequest(BaseModel):
|
||||
connector_type: str = Field(min_length=1, max_length=60)
|
||||
display_name: str = Field(min_length=1, max_length=255)
|
||||
external_account_ref: str | None = Field(default=None, max_length=1000)
|
||||
external_address_book_ref: str | None = Field(default=None, max_length=1000)
|
||||
sync_direction: AddressSyncDirection = "read_only"
|
||||
read_only: bool | None = None
|
||||
enabled: bool = True
|
||||
sync_token: str | None = None
|
||||
etag: str | None = Field(default=None, max_length=1000)
|
||||
remote_revision: str | None = Field(default=None, max_length=1000)
|
||||
metadata: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class AddressSyncSourceUpdateRequest(BaseModel):
|
||||
display_name: str | None = Field(default=None, min_length=1, max_length=255)
|
||||
external_account_ref: str | None = Field(default=None, max_length=1000)
|
||||
external_address_book_ref: str | None = Field(default=None, max_length=1000)
|
||||
sync_direction: AddressSyncDirection | None = None
|
||||
read_only: bool | None = None
|
||||
enabled: bool | None = None
|
||||
sync_token: str | None = None
|
||||
etag: str | None = Field(default=None, max_length=1000)
|
||||
remote_revision: str | None = Field(default=None, max_length=1000)
|
||||
metadata: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class AddressSyncAttemptFinishRequest(BaseModel):
|
||||
status: Literal["succeeded", "failed", "conflict"]
|
||||
sync_token: str | None = None
|
||||
etag: str | None = Field(default=None, max_length=1000)
|
||||
remote_revision: str | None = Field(default=None, max_length=1000)
|
||||
error: str | None = None
|
||||
diagnostic: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class AddressSyncSourceResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
tenant_id: str | None = None
|
||||
address_book_id: str
|
||||
connector_type: str
|
||||
display_name: str
|
||||
external_account_ref: str | None = None
|
||||
external_address_book_ref: str | None = None
|
||||
sync_direction: str
|
||||
read_only: bool
|
||||
enabled: bool
|
||||
status: str
|
||||
sync_token: str | None = None
|
||||
etag: str | None = None
|
||||
remote_revision: str | None = None
|
||||
last_attempted_at: datetime | None = None
|
||||
last_success_at: datetime | None = None
|
||||
last_error: str | None = None
|
||||
last_diagnostic: dict[str, Any] | None = None
|
||||
metadata: dict[str, Any] = Field(default_factory=dict)
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class AddressSyncSourceListResponse(BaseModel):
|
||||
sync_sources: list[AddressSyncSourceResponse]
|
||||
|
||||
|
||||
class AddressSyncDiagnosticCreateRequest(BaseModel):
|
||||
severity: AddressSyncDiagnosticSeverity = "info"
|
||||
code: str = Field(min_length=1, max_length=120)
|
||||
message: str = Field(min_length=1)
|
||||
details: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class AddressSyncDiagnosticResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
tenant_id: str | None = None
|
||||
sync_source_id: str
|
||||
severity: str
|
||||
code: str
|
||||
message: str
|
||||
details: dict[str, Any] = Field(default_factory=dict)
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class AddressSyncDiagnosticListResponse(BaseModel):
|
||||
diagnostics: list[AddressSyncDiagnosticResponse]
|
||||
|
||||
|
||||
class AddressSyncTombstoneCreateRequest(BaseModel):
|
||||
contact_id: str | None = Field(default=None, max_length=36)
|
||||
remote_uid: str | None = Field(default=None, max_length=1000)
|
||||
resource_href: str | None = Field(default=None, max_length=1000)
|
||||
local_deleted_at: datetime | None = None
|
||||
remote_deleted_at: datetime | None = None
|
||||
synced_at: datetime | None = None
|
||||
metadata: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class AddressSyncTombstoneResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
tenant_id: str | None = None
|
||||
sync_source_id: str
|
||||
address_book_id: str
|
||||
contact_id: str | None = None
|
||||
remote_uid: str | None = None
|
||||
resource_href: str | None = None
|
||||
local_deleted_at: datetime | None = None
|
||||
remote_deleted_at: datetime | None = None
|
||||
synced_at: datetime | None = None
|
||||
metadata: dict[str, Any] = Field(default_factory=dict)
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class AddressSyncTombstoneListResponse(BaseModel):
|
||||
tombstones: list[AddressSyncTombstoneResponse]
|
||||
|
||||
|
||||
class AddressSyncConflictCreateRequest(BaseModel):
|
||||
contact_id: str | None = Field(default=None, max_length=36)
|
||||
remote_uid: str | None = Field(default=None, max_length=1000)
|
||||
resource_href: str | None = Field(default=None, max_length=1000)
|
||||
field_path: str = Field(min_length=1, max_length=500)
|
||||
local_value: dict[str, Any] | None = None
|
||||
remote_value: dict[str, Any] | None = None
|
||||
local_updated_at: datetime | None = None
|
||||
remote_updated_at: datetime | None = None
|
||||
metadata: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class AddressSyncConflictResolveRequest(BaseModel):
|
||||
resolution: AddressSyncConflictResolution
|
||||
status: Literal["resolved", "ignored"] = "resolved"
|
||||
merged_payload: ContactCreateRequest | None = None
|
||||
|
||||
|
||||
class AddressSyncConflictResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
tenant_id: str | None = None
|
||||
sync_source_id: str
|
||||
address_book_id: str
|
||||
contact_id: str | None = None
|
||||
remote_uid: str | None = None
|
||||
resource_href: str | None = None
|
||||
field_path: str
|
||||
local_value: dict[str, Any] | None = None
|
||||
remote_value: dict[str, Any] | None = None
|
||||
local_updated_at: datetime | None = None
|
||||
remote_updated_at: datetime | None = None
|
||||
status: str
|
||||
resolution: str | None = None
|
||||
resolved_at: datetime | None = None
|
||||
resolved_by_account_id: str | None = None
|
||||
metadata: dict[str, Any] = Field(default_factory=dict)
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class AddressSyncConflictListResponse(BaseModel):
|
||||
conflicts: list[AddressSyncConflictResponse]
|
||||
|
||||
|
||||
class AddressCardDavDiscoveryRequest(BaseModel):
|
||||
url: str = Field(min_length=1, max_length=2000)
|
||||
auth_type: AddressCardDavAuthType = "none"
|
||||
username: str | None = Field(default=None, max_length=320)
|
||||
password: SecretStr | None = None
|
||||
bearer_token: SecretStr | None = None
|
||||
credential_ref: str | None = Field(default=None, max_length=1000)
|
||||
source_id: str | None = Field(default=None, max_length=36)
|
||||
|
||||
|
||||
class AddressCardDavAddressBookResponse(BaseModel):
|
||||
collection_url: str
|
||||
href: str
|
||||
display_name: str | None = None
|
||||
description: str | None = None
|
||||
ctag: str | None = None
|
||||
sync_token: str | None = None
|
||||
|
||||
|
||||
class AddressCardDavDiscoveryResponse(BaseModel):
|
||||
address_books: list[AddressCardDavAddressBookResponse]
|
||||
|
||||
|
||||
class AddressCardDavSourceCreateRequest(BaseModel):
|
||||
collection_url: str = Field(min_length=1, max_length=2000)
|
||||
display_name: str | None = Field(default=None, max_length=255)
|
||||
auth_type: AddressCardDavAuthType = "none"
|
||||
username: str | None = Field(default=None, max_length=320)
|
||||
password: SecretStr | None = None
|
||||
bearer_token: SecretStr | None = None
|
||||
credential_ref: str | None = Field(default=None, max_length=1000)
|
||||
sync_direction: AddressSyncDirection = "read_only"
|
||||
read_only: bool | None = None
|
||||
sync_token: str | None = None
|
||||
etag: str | None = Field(default=None, max_length=1000)
|
||||
remote_revision: str | None = Field(default=None, max_length=1000)
|
||||
|
||||
|
||||
class AddressSyncRunRequest(BaseModel):
|
||||
force_full: bool = False
|
||||
password: SecretStr | None = None
|
||||
bearer_token: SecretStr | None = None
|
||||
|
||||
|
||||
class AddressSyncPlanStats(BaseModel):
|
||||
created: int = 0
|
||||
updated: int = 0
|
||||
deleted: int = 0
|
||||
conflicts: int = 0
|
||||
unchanged: int = 0
|
||||
errors: int = 0
|
||||
fetched: int = 0
|
||||
full_sync: bool = False
|
||||
used_sync_token: bool = False
|
||||
sync_token: str | None = None
|
||||
etag: str | None = None
|
||||
remote_revision: str | None = None
|
||||
|
||||
|
||||
class AddressSyncPlanItemResponse(BaseModel):
|
||||
action: AddressSyncPlanAction
|
||||
href: str | None = None
|
||||
remote_uid: str | None = None
|
||||
contact_id: str | None = None
|
||||
display_name: str | None = None
|
||||
etag: str | None = None
|
||||
message: str | None = None
|
||||
|
||||
|
||||
class AddressSyncPlanResponse(BaseModel):
|
||||
sync_source: AddressSyncSourceResponse
|
||||
stats: AddressSyncPlanStats
|
||||
items: list[AddressSyncPlanItemResponse]
|
||||
|
||||
|
||||
class VCardImportRequest(BaseModel):
|
||||
content: str = Field(min_length=1)
|
||||
|
||||
|
||||
class VCardImportIssue(BaseModel):
|
||||
index: int
|
||||
message: str
|
||||
severity: Literal["warning", "error"] = "error"
|
||||
field: str | None = None
|
||||
line: int | None = None
|
||||
|
||||
|
||||
class VCardImportResponse(BaseModel):
|
||||
imported: int
|
||||
skipped: int
|
||||
contacts: list[ContactResponse]
|
||||
issues: list[VCardImportIssue] = Field(default_factory=list)
|
||||
Reference in New Issue
Block a user