907 lines
29 KiB
Python
907 lines
29 KiB
Python
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"]
|
|
AddressDistributionChannel = Literal["email", "postal", "internal_mail", "portal"]
|
|
AddressContactPointChannel = Literal[
|
|
"email",
|
|
"phone",
|
|
"postal",
|
|
"internal_mail",
|
|
"portal",
|
|
]
|
|
AddressChannelDecision = Literal[
|
|
"allowed",
|
|
"opted_in",
|
|
"preferred",
|
|
"opted_out",
|
|
"suppressed",
|
|
"invalid",
|
|
"returned",
|
|
"temporarily_unavailable",
|
|
]
|
|
AddressDistributionOutcome = Literal[
|
|
"usable",
|
|
"unresolved",
|
|
"invalid",
|
|
"suppressed",
|
|
"ambiguous",
|
|
"duplicate",
|
|
"policy_blocked",
|
|
"provider_unavailable",
|
|
"stale",
|
|
]
|
|
AddressContactPointFallbackRule = Literal["none", "primary", "any"]
|
|
AddressPostalFormat = Literal["domestic", "international"]
|
|
ContactPointQualityState = Literal[
|
|
"valid",
|
|
"invalid",
|
|
"returned",
|
|
"stale",
|
|
"undeliverable",
|
|
]
|
|
|
|
|
|
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 ContactFieldProvenanceResponse(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: str
|
|
contact_id: str
|
|
field_path: str
|
|
value: Any = None
|
|
source_kind: str
|
|
source_ref: str | None = None
|
|
source_revision: str | None = None
|
|
precedence: int
|
|
selected: bool
|
|
reason_code: str
|
|
explanation: str | None = None
|
|
visibility: str
|
|
merge_record_id: str | None = None
|
|
created_by_account_id: str | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict, validation_alias="metadata_")
|
|
created_at: datetime
|
|
|
|
|
|
class ContactPointQualityDecisionCreateRequest(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
channel: AddressContactPointChannel
|
|
contact_point_id: str | None = Field(default=None, max_length=36)
|
|
state: ContactPointQualityState
|
|
reason_code: str | None = Field(default=None, max_length=120)
|
|
reason: str | None = None
|
|
evidence_ref: str | None = Field(default=None, max_length=1000)
|
|
effective_from: datetime | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ContactPointQualityDecisionResponse(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: str
|
|
tenant_id: str | None = None
|
|
contact_id: str
|
|
channel: AddressContactPointChannel
|
|
contact_point_id: str | None = None
|
|
state: ContactPointQualityState
|
|
reason_code: str
|
|
reason: str | None = None
|
|
evidence_ref: str | None = None
|
|
effective_from: datetime
|
|
effective_until: datetime | None = None
|
|
created_by_account_id: str | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict, validation_alias="metadata_")
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class ContactPointQualityDecisionListResponse(BaseModel):
|
|
decisions: list[ContactPointQualityDecisionResponse] = Field(default_factory=list)
|
|
|
|
|
|
class ContactEmailResponse(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: str
|
|
label: str | None = None
|
|
email: str
|
|
original_email: str = ""
|
|
normalized_email: str = ""
|
|
provenance: dict[str, Any] = Field(default_factory=dict)
|
|
quality_state: ContactPointQualityState = "valid"
|
|
quality_reason_code: str | None = None
|
|
is_primary: bool
|
|
|
|
|
|
class ContactPhoneResponse(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: str
|
|
label: str | None = None
|
|
phone: str
|
|
original_phone: str = ""
|
|
normalized_phone: str = ""
|
|
provenance: dict[str, Any] = Field(default_factory=dict)
|
|
quality_state: ContactPointQualityState = "valid"
|
|
quality_reason_code: str | None = None
|
|
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
|
|
original_value: dict[str, Any] = Field(default_factory=dict)
|
|
normalized_value: dict[str, Any] = Field(default_factory=dict)
|
|
provenance: dict[str, Any] = Field(default_factory=dict)
|
|
quality_state: ContactPointQualityState = "valid"
|
|
quality_reason_code: 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]
|
|
field_provenance: list[ContactFieldProvenanceResponse] = Field(default_factory=list)
|
|
deleted_at: datetime | None = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class ContactListResponse(BaseModel):
|
|
contacts: list[ContactResponse]
|
|
total: int
|
|
offset: int
|
|
limit: int
|
|
has_more: bool
|
|
|
|
|
|
class ContactDuplicateFeatureResponse(BaseModel):
|
|
code: str
|
|
label: str
|
|
weight: int
|
|
value: str
|
|
|
|
|
|
class ContactDuplicateSuggestionResponse(BaseModel):
|
|
left: ContactResponse
|
|
right: ContactResponse
|
|
score: int
|
|
confidence: Literal["possible", "likely", "strong"]
|
|
features: list[ContactDuplicateFeatureResponse]
|
|
|
|
|
|
class ContactDuplicateSuggestionListResponse(BaseModel):
|
|
suggestions: list[ContactDuplicateSuggestionResponse] = Field(default_factory=list)
|
|
scanned_contacts: int
|
|
candidate_pairs: int
|
|
truncated: bool
|
|
|
|
|
|
class ContactMergeRequest(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
winner_contact_id: str = Field(max_length=36)
|
|
duplicate_contact_ids: list[str] = Field(min_length=1, max_length=20)
|
|
reason: str = Field(min_length=3)
|
|
field_sources: dict[str, str] = Field(default_factory=dict)
|
|
contact_point_strategy: Literal["union", "winner_only"] = "union"
|
|
source_precedence: list[str] = Field(default_factory=list, max_length=20)
|
|
|
|
|
|
class ContactMergeRecoveryRequest(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
reason: str = Field(min_length=3)
|
|
expected_after_hash: str = Field(min_length=64, max_length=64)
|
|
|
|
|
|
class ContactMergeRecordResponse(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: str
|
|
tenant_id: str | None = None
|
|
address_book_id: str
|
|
winner_contact_id: str
|
|
loser_contact_ids: list[str]
|
|
status: str
|
|
reason: str
|
|
survivorship: dict[str, Any]
|
|
decisions: list[dict[str, Any]]
|
|
before_hash: str
|
|
after_hash: str
|
|
created_by_account_id: str | None = None
|
|
recovered_at: datetime | None = None
|
|
recovered_by_account_id: str | None = None
|
|
recovery_action: str | None = None
|
|
recovery_reason: str | None = None
|
|
provenance: dict[str, Any]
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class ContactMergeRecordListResponse(BaseModel):
|
|
merges: list[ContactMergeRecordResponse] = Field(default_factory=list)
|
|
|
|
|
|
class ContactRedirectResponse(BaseModel):
|
|
requested_contact_id: str
|
|
resolved_contact_id: str
|
|
redirected: bool
|
|
redirect_chain: list[str] = Field(default_factory=list)
|
|
merge_record_ids: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class AddressQualityCorrectionResponse(BaseModel):
|
|
contact_id: str
|
|
display_name: str
|
|
channel: AddressContactPointChannel
|
|
contact_point_id: str | None = None
|
|
state: ContactPointQualityState
|
|
reason_code: str
|
|
reason: str | None = None
|
|
effective_from: datetime
|
|
|
|
|
|
class AddressQualitySummaryResponse(BaseModel):
|
|
contact_count: int
|
|
contact_point_count: int
|
|
quality_counts: dict[str, int] = Field(default_factory=dict)
|
|
duplicate_suggestion_count: int
|
|
correction_count: int
|
|
corrections: list[AddressQualityCorrectionResponse] = Field(default_factory=list)
|
|
truncated: bool = False
|
|
|
|
|
|
class ContactChannelRuleCreateRequest(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
channel: AddressDistributionChannel
|
|
purpose: str | None = Field(default=None, max_length=120)
|
|
contact_point_id: str | None = Field(default=None, max_length=36)
|
|
decision: AddressChannelDecision
|
|
legal_basis: str | None = Field(default=None, max_length=255)
|
|
evidence_ref: str | None = Field(default=None, max_length=1000)
|
|
reason: str | None = None
|
|
preference_rank: int | None = Field(default=None, ge=0, le=10000)
|
|
locale: str | None = Field(default=None, max_length=20)
|
|
effective_from: datetime | None = None
|
|
effective_until: datetime | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ContactChannelRuleResponse(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: str
|
|
tenant_id: str | None = None
|
|
contact_id: str
|
|
channel: AddressDistributionChannel
|
|
purpose: str | None = None
|
|
contact_point_id: str | None = None
|
|
decision: AddressChannelDecision
|
|
legal_basis: str | None = None
|
|
evidence_ref: str | None = None
|
|
reason: str | None = None
|
|
preference_rank: int | None = None
|
|
locale: str | None = None
|
|
effective_from: datetime | None = None
|
|
effective_until: datetime | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict, validation_alias="metadata_")
|
|
created_by_account_id: str | None = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class ContactChannelRuleListResponse(BaseModel):
|
|
rules: list[ContactChannelRuleResponse] = Field(default_factory=list)
|
|
|
|
|
|
class AddressSourceReferencePayload(BaseModel):
|
|
provider: str = Field(min_length=1, max_length=120)
|
|
resource_type: str = Field(min_length=1, max_length=120)
|
|
resource_id: str = Field(min_length=1, max_length=1000)
|
|
revision: str | None = Field(default=None, max_length=1000)
|
|
fingerprint: str | None = Field(default=None, max_length=255)
|
|
label: str | None = Field(default=None, max_length=500)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ContactPointResolveRequest(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
subject: AddressSourceReferencePayload
|
|
effective_at: datetime
|
|
purpose: str | None = Field(default=None, max_length=120)
|
|
requested_channels: list[AddressDistributionChannel] = Field(default_factory=list)
|
|
address_purpose: str | None = Field(default=None, max_length=80)
|
|
fallback_rule: AddressContactPointFallbackRule = "primary"
|
|
locale: str | None = Field(default=None, max_length=20)
|
|
postal_format: AddressPostalFormat = "domestic"
|
|
context: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ContactPointSourceRequestPayload(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
source_id: str = Field(min_length=1, max_length=1000)
|
|
effective_at: datetime
|
|
purpose: str | None = Field(default=None, max_length=120)
|
|
requested_channels: list[AddressDistributionChannel] = Field(default_factory=list)
|
|
address_purpose: str | None = Field(default=None, max_length=80)
|
|
fallback_rule: AddressContactPointFallbackRule = "primary"
|
|
locale: str | None = Field(default=None, max_length=20)
|
|
postal_format: AddressPostalFormat = "domestic"
|
|
max_items: int = Field(default=5000, ge=1, le=20000)
|
|
context: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ContactPointSourceRequestResponse(ContactPointSourceRequestPayload):
|
|
tenant_id: str
|
|
|
|
|
|
class ContactPointCandidateResponse(BaseModel):
|
|
channel: AddressDistributionChannel
|
|
target: str
|
|
target_key: str
|
|
status: AddressDistributionOutcome
|
|
contact_point_id: str | None = None
|
|
address_purpose: str | None = None
|
|
locale: str | None = None
|
|
preferred: bool = False
|
|
preference_rank: int | None = None
|
|
reason_code: str | None = None
|
|
explanation: str | None = None
|
|
source: AddressSourceReferencePayload | None = None
|
|
source_revision: str | None = None
|
|
preference_revision: str | None = None
|
|
consent_revision: str | None = None
|
|
value: dict[str, Any] = Field(default_factory=dict)
|
|
provenance: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class DistributionExplanationResponse(BaseModel):
|
|
code: str
|
|
message: str
|
|
severity: Literal["info", "warning", "error"]
|
|
provider: str | None = None
|
|
source: AddressSourceReferencePayload | None = None
|
|
provenance: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ContactPointResolutionResponse(BaseModel):
|
|
contract_version: str
|
|
subject: AddressSourceReferencePayload
|
|
status: AddressDistributionOutcome
|
|
contact_id: str | None = None
|
|
display_name: str | None = None
|
|
candidates: list[ContactPointCandidateResponse] = Field(default_factory=list)
|
|
excluded: list[ContactPointCandidateResponse] = Field(default_factory=list)
|
|
explanations: list[DistributionExplanationResponse] = Field(default_factory=list)
|
|
source_revision: str | None = None
|
|
source_fingerprint: str | None = None
|
|
provenance: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ContactPointSourcePreviewResponse(BaseModel):
|
|
contract_version: str
|
|
source: AddressSourceReferencePayload
|
|
request: ContactPointSourceRequestResponse
|
|
resolutions: list[ContactPointResolutionResponse]
|
|
total_count: int
|
|
usable_count: int
|
|
excluded_count: int
|
|
offset: int
|
|
limit: int
|
|
has_more: bool
|
|
source_revision: str
|
|
source_fingerprint: str
|
|
generated_at: datetime
|
|
provenance: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ContactPointSnapshotResponse(BaseModel):
|
|
id: str
|
|
tenant_id: str
|
|
contract_version: str
|
|
source: AddressSourceReferencePayload
|
|
request: ContactPointSourceRequestResponse
|
|
resolutions: list[ContactPointResolutionResponse]
|
|
recipient_count: int
|
|
excluded_count: int
|
|
source_revision: str
|
|
source_fingerprint: str
|
|
snapshot_hash: str
|
|
generated_at: datetime
|
|
provenance: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
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 AddressCredentialEnvelopeResponse(BaseModel):
|
|
id: str
|
|
scope_type: str
|
|
scope_id: str | None = None
|
|
name: str
|
|
description: str | None = None
|
|
credential_kind: str
|
|
public_data: dict[str, Any] = Field(default_factory=dict)
|
|
secret_keys: list[str] = Field(default_factory=list)
|
|
secret_configured: bool = False
|
|
allowed_modules: list[str] = Field(default_factory=list)
|
|
inherit_to_lower_scopes: bool = False
|
|
is_active: bool = True
|
|
revision: str
|
|
|
|
|
|
class AddressCredentialEnvelopeListResponse(BaseModel):
|
|
credentials: list[AddressCredentialEnvelopeResponse] = Field(default_factory=list)
|
|
|
|
|
|
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)
|