788 lines
23 KiB
Python
788 lines
23 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from govoplan_core.api.v1.schemas import DeltaDeletedItem
|
|
from govoplan_files.backend.storage.common import FileConflictResolution
|
|
|
|
|
|
class FileSpaceResponse(BaseModel):
|
|
id: str
|
|
label: str
|
|
owner_type: Literal["user", "group"]
|
|
owner_id: str
|
|
description: str | None = None
|
|
space_type: Literal["managed", "connector"] = "managed"
|
|
connector_space_id: str | None = None
|
|
connector_profile_id: str | None = None
|
|
provider: str | None = None
|
|
library_id: str | None = None
|
|
remote_path: str | None = None
|
|
sync_mode: str | None = None
|
|
read_only: bool = False
|
|
|
|
|
|
class FileSpacesResponse(BaseModel):
|
|
spaces: list[FileSpaceResponse]
|
|
|
|
|
|
class FileConnectorSpaceCreateRequest(BaseModel):
|
|
owner_type: Literal["user", "group"] = "user"
|
|
owner_id: str | None = None
|
|
label: str
|
|
connector_profile_id: str
|
|
library_id: str | None = None
|
|
remote_path: str = ""
|
|
sync_mode: Literal["manual"] = "manual"
|
|
read_only: bool = True
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorSpaceUpdateRequest(BaseModel):
|
|
label: str | None = None
|
|
library_id: str | None = None
|
|
remote_path: str | None = None
|
|
sync_mode: Literal["manual"] | None = None
|
|
read_only: bool | None = None
|
|
is_active: bool | None = None
|
|
metadata: dict[str, Any] | None = None
|
|
|
|
|
|
class FileConnectorSpaceResponse(BaseModel):
|
|
id: str
|
|
tenant_id: str
|
|
owner_type: Literal["user", "group"]
|
|
owner_id: str
|
|
label: str
|
|
connector_profile_id: str
|
|
provider: str
|
|
library_id: str | None = None
|
|
remote_path: str = ""
|
|
sync_mode: str
|
|
read_only: bool
|
|
is_active: bool
|
|
created_at: str
|
|
updated_at: str
|
|
deleted_at: str | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorSpacesResponse(BaseModel):
|
|
spaces: list[FileConnectorSpaceResponse] = Field(default_factory=list)
|
|
|
|
|
|
class FileShareResponse(BaseModel):
|
|
id: str
|
|
file_asset_id: str
|
|
target_type: str
|
|
target_id: str
|
|
permission: str
|
|
created_by_user_id: str | None = None
|
|
created_at: str
|
|
expires_at: str | None = None
|
|
revoked_at: str | None = None
|
|
revoked_by_user_id: str | None = None
|
|
active: bool
|
|
|
|
|
|
class FileSharesResponse(BaseModel):
|
|
shares: list[FileShareResponse] = Field(default_factory=list)
|
|
|
|
|
|
class FileIntegrityScanCreateRequest(BaseModel):
|
|
verify_checksums: bool = True
|
|
batch_size: int = Field(default=100, ge=1, le=1000)
|
|
|
|
|
|
class FileIntegrityScanResponse(BaseModel):
|
|
id: str
|
|
tenant_id: str
|
|
storage_backend: str
|
|
storage_prefix: str
|
|
status: str
|
|
revision: int
|
|
phase: str
|
|
verify_checksums: bool
|
|
batch_size: int
|
|
scanned_blob_count: int
|
|
verified_blob_count: int
|
|
quarantined_blob_count: int
|
|
scanned_object_count: int
|
|
orphan_object_count: int
|
|
created_by_user_id: str | None = None
|
|
started_at: str | None = None
|
|
completed_at: str | None = None
|
|
last_error: str | None = None
|
|
created_at: str
|
|
updated_at: str
|
|
|
|
|
|
class FileIntegrityScansResponse(BaseModel):
|
|
scans: list[FileIntegrityScanResponse] = Field(default_factory=list)
|
|
|
|
|
|
class FileIntegrityFindingResponse(BaseModel):
|
|
id: str
|
|
scan_id: str
|
|
tenant_id: str
|
|
kind: str
|
|
state: str
|
|
revision: int
|
|
blob_id: str | None = None
|
|
storage_key: str
|
|
expected_size_bytes: int | None = None
|
|
observed_size_bytes: int | None = None
|
|
expected_checksum_sha256: str | None = None
|
|
observed_checksum_sha256: str | None = None
|
|
resolved_at: str | None = None
|
|
resolved_by_user_id: str | None = None
|
|
created_at: str
|
|
updated_at: str
|
|
|
|
|
|
class FileIntegrityFindingsResponse(BaseModel):
|
|
findings: list[FileIntegrityFindingResponse] = Field(default_factory=list)
|
|
|
|
|
|
class FileIntegrityActionRequest(BaseModel):
|
|
dry_run: bool = True
|
|
expected_revision: int = Field(ge=1)
|
|
|
|
|
|
class FileIntegrityScanRunRequest(BaseModel):
|
|
expected_revision: int = Field(ge=1)
|
|
|
|
|
|
class FileIntegrityActionResponse(BaseModel):
|
|
action: str
|
|
changed: bool
|
|
dry_run: bool
|
|
finding: FileIntegrityFindingResponse
|
|
inspection_kind: str | None = None
|
|
inspection_valid: bool | None = None
|
|
|
|
|
|
class FileSourceProvenance(BaseModel):
|
|
source_type: str | None = None
|
|
connector_id: str | None = None
|
|
provider: str | None = None
|
|
external_id: str | None = None
|
|
external_path: str | None = None
|
|
external_url: str | None = None
|
|
revision: str | None = None
|
|
revision_label: str | None = None
|
|
observed_at: str | None = None
|
|
imported_at: str | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileAssetResponse(BaseModel):
|
|
id: str
|
|
tenant_id: str
|
|
owner_type: str
|
|
owner_id: str
|
|
display_path: str
|
|
filename: str
|
|
description: str | None = None
|
|
size_bytes: int
|
|
content_type: str | None = None
|
|
checksum_sha256: str
|
|
version_id: str
|
|
created_at: str
|
|
updated_at: str
|
|
deleted_at: str | None = None
|
|
retained_until: str | None = None
|
|
legal_hold: bool = False
|
|
lifecycle_revision: int = 1
|
|
lifecycle_reason: str | None = None
|
|
audit_relevant: bool = False
|
|
metadata: dict[str, Any] | None = None
|
|
source_provenance: FileSourceProvenance | None = None
|
|
source_revision: str | None = None
|
|
shares: list[FileShareResponse] = Field(default_factory=list)
|
|
|
|
|
|
class FileFolderResponse(BaseModel):
|
|
id: str
|
|
tenant_id: str
|
|
owner_type: str
|
|
owner_id: str
|
|
path: str
|
|
created_at: str
|
|
updated_at: str
|
|
deleted_at: str | None = None
|
|
|
|
|
|
class FileFoldersResponse(BaseModel):
|
|
folders: list[FileFolderResponse]
|
|
cursor: str | None = None
|
|
next_cursor: str | None = None
|
|
watermark: str | None = None
|
|
|
|
|
|
class FileFolderCreateRequest(BaseModel):
|
|
owner_type: Literal["user", "group"]
|
|
owner_id: str
|
|
path: str
|
|
|
|
|
|
class FileFolderDeleteRequest(BaseModel):
|
|
owner_type: Literal["user", "group"]
|
|
owner_id: str
|
|
path: str
|
|
recursive: bool = True
|
|
|
|
|
|
class FileFolderDeleteResponse(BaseModel):
|
|
deleted_folders: int
|
|
deleted_files: int
|
|
|
|
|
|
class FileListResponse(BaseModel):
|
|
files: list[FileAssetResponse]
|
|
total: int
|
|
cursor: str | None = None
|
|
next_cursor: str | None = None
|
|
watermark: str | None = None
|
|
|
|
|
|
class FileDeltaResponse(BaseModel):
|
|
files: list[FileAssetResponse] = Field(default_factory=list)
|
|
folders: list[FileFolderResponse] = Field(default_factory=list)
|
|
deleted: list[DeltaDeletedItem] = Field(default_factory=list)
|
|
watermark: str | None = None
|
|
has_more: bool = False
|
|
full: bool = False
|
|
|
|
|
|
class FileUploadResponse(BaseModel):
|
|
files: list[FileAssetResponse]
|
|
|
|
|
|
class ArchiveEntryResponse(BaseModel):
|
|
path: str
|
|
kind: Literal["file", "directory"]
|
|
size_bytes: int
|
|
compressed_size_bytes: int | None = None
|
|
encrypted: bool = False
|
|
|
|
|
|
class ArchivePreviewResponse(BaseModel):
|
|
preview_token: str
|
|
archive_format: str
|
|
entries: list[ArchiveEntryResponse] = Field(default_factory=list)
|
|
file_count: int
|
|
directory_count: int
|
|
expanded_size_bytes: int
|
|
compressed_size_bytes: int
|
|
requires_password: bool
|
|
password_verified: bool
|
|
expires_at: str
|
|
|
|
|
|
class FileConnectorPolicySource(BaseModel):
|
|
scope_type: Literal["system", "tenant", "user", "group", "campaign"] = "system"
|
|
scope_id: str | None = None
|
|
label: str | None = None
|
|
policy: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorPolicyEvaluateRequest(BaseModel):
|
|
source_provenance: FileSourceProvenance
|
|
operation: str = "access"
|
|
policy_sources: list[FileConnectorPolicySource] = Field(default_factory=list)
|
|
|
|
|
|
class FileConnectorPolicyEvaluateResponse(BaseModel):
|
|
decision: dict[str, Any]
|
|
|
|
|
|
class FileConnectorPolicyUpdateRequest(BaseModel):
|
|
policy: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorPolicyStepResponse(BaseModel):
|
|
scope_type: str
|
|
scope_id: str | None = None
|
|
path: str
|
|
label: str
|
|
applied_fields: list[str] = Field(default_factory=list)
|
|
policy: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorPolicyResponse(BaseModel):
|
|
scope_type: Literal["system", "tenant", "user", "group", "campaign"]
|
|
scope_id: str | None = None
|
|
policy: dict[str, Any] = Field(default_factory=dict)
|
|
effective_policy: dict[str, Any] | None = None
|
|
parent_policy: dict[str, Any] | None = None
|
|
effective_policy_sources: list[FileConnectorPolicyStepResponse] = Field(default_factory=list)
|
|
parent_policy_sources: list[FileConnectorPolicyStepResponse] = Field(default_factory=list)
|
|
|
|
|
|
class FileConnectorProfileResponse(BaseModel):
|
|
id: str
|
|
label: str
|
|
provider: str
|
|
endpoint_url: str | None = None
|
|
base_path: str | None = None
|
|
enabled: bool = True
|
|
scope_type: Literal["system", "tenant", "user", "group", "campaign"] = "system"
|
|
scope_id: str | None = None
|
|
source_path: str
|
|
credential_profile_id: str | None = None
|
|
credential_profile_label: str | None = None
|
|
credential_mode: str = "none"
|
|
credential_source: str | None = None
|
|
credentials_configured: bool = False
|
|
username: str | None = None
|
|
capabilities: list[str] = Field(default_factory=list)
|
|
policy_sources: list[FileConnectorPolicySource] = Field(default_factory=list)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
source_kind: str = "settings"
|
|
|
|
|
|
class FileConnectorProfilesResponse(BaseModel):
|
|
profiles: list[FileConnectorProfileResponse]
|
|
|
|
|
|
class FileConnectorCredentialResponse(BaseModel):
|
|
id: str
|
|
label: str
|
|
provider: str | None = None
|
|
enabled: bool = True
|
|
scope_type: Literal["system", "tenant", "user", "group", "campaign"] = "system"
|
|
scope_id: str | None = None
|
|
source_path: str
|
|
credential_mode: str = "none"
|
|
credential_secret_source: str | None = None
|
|
credentials_configured: bool = False
|
|
username: str | None = None
|
|
policy_sources: list[FileConnectorPolicySource] = Field(default_factory=list)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
source_kind: str = "database"
|
|
|
|
|
|
class FileConnectorCredentialsResponse(BaseModel):
|
|
credentials: list[FileConnectorCredentialResponse]
|
|
|
|
|
|
class FileConnectorSettingsDeltaResponse(BaseModel):
|
|
profiles: list[FileConnectorProfileResponse] = Field(default_factory=list)
|
|
credentials: list[FileConnectorCredentialResponse] = Field(default_factory=list)
|
|
spaces: list[FileConnectorSpaceResponse] = Field(default_factory=list)
|
|
policy: FileConnectorPolicyResponse | None = None
|
|
changed_sections: list[str] = Field(default_factory=list)
|
|
deleted: list[DeltaDeletedItem] = Field(default_factory=list)
|
|
watermark: str | None = None
|
|
has_more: bool = False
|
|
full: bool = False
|
|
|
|
|
|
class FileConnectorProfileCredentialsRequest(BaseModel):
|
|
username: str | None = None
|
|
password: str | None = None
|
|
token: str | None = None
|
|
password_env: str | None = None
|
|
token_env: str | None = None
|
|
secret_ref: str | None = None
|
|
|
|
|
|
class FileConnectorDiscoveryCandidate(BaseModel):
|
|
endpoint_url: str
|
|
status: Literal["failed", "usable", "found", "credentials_rejected"]
|
|
message: str
|
|
|
|
|
|
class FileConnectorDiscoveryRequest(BaseModel):
|
|
provider: Literal["seafile", "nextcloud", "webdav", "smb", "s3", "sharepoint", "onedrive", "nfs", "dms", "generic"]
|
|
endpoint_url: str
|
|
base_path: str | None = None
|
|
credential_mode: Literal["none", "anonymous", "basic", "token", "secret_ref"] = "none"
|
|
credentials: FileConnectorProfileCredentialsRequest = Field(default_factory=FileConnectorProfileCredentialsRequest)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
require_valid_credentials: bool = False
|
|
|
|
|
|
class FileConnectorDiscoveryResponse(BaseModel):
|
|
provider: str
|
|
endpoint_url: str | None = None
|
|
base_path: str | None = None
|
|
status: Literal["usable", "found", "credentials_rejected", "not_found", "unsupported"]
|
|
message: str
|
|
candidates: list[FileConnectorDiscoveryCandidate] = Field(default_factory=list)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorProfileCreateRequest(BaseModel):
|
|
id: str
|
|
label: str
|
|
provider: Literal["seafile", "nextcloud", "webdav", "smb", "s3", "sharepoint", "onedrive", "nfs", "dms", "generic"]
|
|
endpoint_url: str | None = None
|
|
base_path: str | None = None
|
|
enabled: bool = True
|
|
scope_type: Literal["system", "tenant", "user", "group", "campaign"] = "tenant"
|
|
scope_id: str | None = None
|
|
credential_profile_id: str | None = None
|
|
credential_mode: Literal["none", "anonymous", "basic", "token", "secret_ref"] = "none"
|
|
credentials: FileConnectorProfileCredentialsRequest = Field(default_factory=FileConnectorProfileCredentialsRequest)
|
|
capabilities: list[str] = Field(default_factory=lambda: ["browse", "import", "sync"])
|
|
policy: dict[str, Any] = Field(default_factory=dict)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorProfileUpdateRequest(BaseModel):
|
|
label: str | None = None
|
|
provider: Literal["seafile", "nextcloud", "webdav", "smb", "s3", "sharepoint", "onedrive", "nfs", "dms", "generic"] | None = None
|
|
endpoint_url: str | None = None
|
|
base_path: str | None = None
|
|
enabled: bool | None = None
|
|
credential_profile_id: str | None = None
|
|
credential_mode: Literal["none", "anonymous", "basic", "token", "secret_ref"] | None = None
|
|
credentials: FileConnectorProfileCredentialsRequest | None = None
|
|
clear_password: bool = False
|
|
clear_token: bool = False
|
|
capabilities: list[str] | None = None
|
|
policy: dict[str, Any] | None = None
|
|
metadata: dict[str, Any] | None = None
|
|
|
|
|
|
class FileConnectorCredentialCreateRequest(BaseModel):
|
|
id: str
|
|
label: str
|
|
provider: Literal["seafile", "nextcloud", "webdav", "smb", "s3", "sharepoint", "onedrive", "nfs", "dms", "generic"] | None = None
|
|
enabled: bool = True
|
|
scope_type: Literal["system", "tenant", "user", "group", "campaign"] = "tenant"
|
|
scope_id: str | None = None
|
|
credential_mode: Literal["none", "anonymous", "basic", "token", "secret_ref"] = "none"
|
|
credentials: FileConnectorProfileCredentialsRequest = Field(default_factory=FileConnectorProfileCredentialsRequest)
|
|
policy: dict[str, Any] = Field(default_factory=dict)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorCredentialUpdateRequest(BaseModel):
|
|
label: str | None = None
|
|
provider: Literal["seafile", "nextcloud", "webdav", "smb", "s3", "sharepoint", "onedrive", "nfs", "dms", "generic"] | None = None
|
|
enabled: bool | None = None
|
|
credential_mode: Literal["none", "anonymous", "basic", "token", "secret_ref"] | None = None
|
|
credentials: FileConnectorProfileCredentialsRequest | None = None
|
|
clear_password: bool = False
|
|
clear_token: bool = False
|
|
policy: dict[str, Any] | None = None
|
|
metadata: dict[str, Any] | None = None
|
|
|
|
|
|
class FileConnectorProviderResponse(BaseModel):
|
|
provider: str
|
|
label: str
|
|
protocol: str
|
|
implemented: bool
|
|
installed: bool
|
|
browse_supported: bool
|
|
import_supported: bool
|
|
write_supported: bool = False
|
|
optional_dependency: str | None = None
|
|
permission_model: str
|
|
sync_strategy: str
|
|
conflict_strategy: str
|
|
preview_strategy: str
|
|
audit_events: list[str] = Field(default_factory=list)
|
|
notes: str | None = None
|
|
|
|
|
|
class FileConnectorProvidersResponse(BaseModel):
|
|
providers: list[FileConnectorProviderResponse]
|
|
|
|
|
|
class FileConnectorBrowseItem(BaseModel):
|
|
kind: Literal["library", "folder", "file"]
|
|
name: str
|
|
path: str
|
|
external_id: str | None = None
|
|
external_url: str | None = None
|
|
size_bytes: int | None = None
|
|
content_type: str | None = None
|
|
modified_at: str | None = None
|
|
etag: str | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorBrowseResponse(BaseModel):
|
|
profile_id: str
|
|
provider: str
|
|
path: str = ""
|
|
library_id: str | None = None
|
|
read_only: bool = True
|
|
next_continuation_token: str | None = None
|
|
has_more: bool = False
|
|
decision: dict[str, Any]
|
|
items: list[FileConnectorBrowseItem]
|
|
|
|
|
|
class FileConnectorImportRequest(BaseModel):
|
|
library_id: str
|
|
path: str
|
|
owner_type: Literal["user", "group"] = "user"
|
|
owner_id: str | None = None
|
|
target_folder: str | None = None
|
|
target_path: str | None = None
|
|
campaign_id: str | None = None
|
|
conflict_strategy: Literal["reject", "overwrite", "rename", "skip"] = "reject"
|
|
source_revision: str | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorSyncResponse(BaseModel):
|
|
file: FileAssetResponse
|
|
action: Literal["created", "updated", "unchanged"]
|
|
previous_version_id: str | None = None
|
|
current_version_id: str
|
|
|
|
|
|
class FileConnectorFolderSyncRequest(BaseModel):
|
|
path: str = ""
|
|
target_folder: str | None = None
|
|
recursive: bool = True
|
|
conflict_strategy: Literal["reject", "overwrite", "rename", "skip"] = "skip"
|
|
max_files: int = Field(default=100, ge=1, le=500)
|
|
max_depth: int = Field(default=12, ge=0, le=50)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class FileConnectorFolderSyncItemResponse(BaseModel):
|
|
source_path: str
|
|
target_path: str | None = None
|
|
action: Literal[
|
|
"created",
|
|
"updated",
|
|
"unchanged",
|
|
"skipped",
|
|
"conflict",
|
|
"policy_denied",
|
|
"failed",
|
|
]
|
|
file: FileAssetResponse | None = None
|
|
previous_version_id: str | None = None
|
|
current_version_id: str | None = None
|
|
source_revision: str | None = None
|
|
detail: str | None = None
|
|
policy_decision: dict[str, Any] | None = None
|
|
|
|
|
|
class FileConnectorFolderSyncSummary(BaseModel):
|
|
discovered: int = 0
|
|
created: int = 0
|
|
updated: int = 0
|
|
unchanged: int = 0
|
|
skipped: int = 0
|
|
conflicts: int = 0
|
|
policy_denied: int = 0
|
|
failed: int = 0
|
|
|
|
|
|
class FileConnectorFolderSyncResponse(BaseModel):
|
|
connector_space_id: str
|
|
connector_profile_id: str
|
|
provider: str
|
|
remote_path: str
|
|
target_folder: str
|
|
recursive: bool
|
|
truncated: bool = False
|
|
summary: FileConnectorFolderSyncSummary
|
|
items: list[FileConnectorFolderSyncItemResponse] = Field(default_factory=list)
|
|
|
|
|
|
class FileConnectorWriteRequest(BaseModel):
|
|
file_id: str
|
|
remote_path: str
|
|
idempotency_key: str = Field(min_length=8, max_length=160)
|
|
expected_revision: str | None = Field(default=None, max_length=500)
|
|
|
|
|
|
class FileConnectorWriteResponse(BaseModel):
|
|
recovery_operation_id: str
|
|
status: str
|
|
replayed: bool = False
|
|
provider: str
|
|
remote_path: str
|
|
revision: str | None = None
|
|
checksum_sha256: str
|
|
size_bytes: int
|
|
|
|
|
|
class BulkDeleteRequest(BaseModel):
|
|
file_ids: list[str]
|
|
|
|
|
|
class BulkDeleteResponse(BaseModel):
|
|
deleted_count: int
|
|
|
|
|
|
class FileLifecycleUpdateRequest(BaseModel):
|
|
retained_until: datetime | None = None
|
|
legal_hold: bool = False
|
|
reason: str = Field(min_length=1, max_length=500)
|
|
expected_revision: int = Field(ge=1)
|
|
|
|
|
|
class FileRestoreResponse(BaseModel):
|
|
restored_count: int
|
|
|
|
|
|
class FileFolderRestoreResponse(BaseModel):
|
|
restored_folders: int
|
|
restored_files: int
|
|
|
|
|
|
class FilePurgePreviewRequest(BaseModel):
|
|
file_ids: list[str] = Field(min_length=1, max_length=100)
|
|
|
|
|
|
class FilePurgePreviewItem(BaseModel):
|
|
file_id: str
|
|
filename: str
|
|
lifecycle_revision: int
|
|
deleted_at: str | None = None
|
|
retained_until: str | None = None
|
|
legal_hold: bool = False
|
|
blockers: list[str] = Field(default_factory=list)
|
|
blob_ids: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class FilePurgePreviewResponse(BaseModel):
|
|
preview_sha256: str
|
|
eligible: bool
|
|
items: list[FilePurgePreviewItem]
|
|
|
|
|
|
class FilePurgeExecuteRequest(FilePurgePreviewRequest):
|
|
preview_sha256: str = Field(min_length=64, max_length=64)
|
|
idempotency_key: str = Field(min_length=8, max_length=160)
|
|
approval_reference: str = Field(min_length=3, max_length=1000)
|
|
confirmation: Literal["PURGE"]
|
|
|
|
|
|
class FilePurgeResponse(BaseModel):
|
|
recovery_operation_id: str
|
|
status: str
|
|
replayed: bool = False
|
|
purged_files: int = 0
|
|
released_blobs: int = 0
|
|
|
|
|
|
class FileBlobGcRequest(BaseModel):
|
|
limit: int = Field(default=25, ge=1, le=100)
|
|
approval_reference: str = Field(min_length=3, max_length=1000)
|
|
|
|
|
|
class FileBlobGcResponse(BaseModel):
|
|
inspected_blobs: int
|
|
deleted_blobs: int
|
|
unresolved_operation_ids: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class ConflictResolutionRequest(BaseModel):
|
|
target_path: str
|
|
action: Literal["overwrite", "rename", "skip"]
|
|
new_path: str | None = None
|
|
|
|
|
|
def _conflict_resolutions(items: list[ConflictResolutionRequest] | None) -> list[FileConflictResolution]:
|
|
return [FileConflictResolution(target_path=item.target_path, action=item.action, new_path=item.new_path) for item in items or []]
|
|
|
|
|
|
class FileShareRequest(BaseModel):
|
|
target_type: Literal["user", "group", "campaign", "tenant"]
|
|
target_id: str
|
|
permission: Literal["read", "write", "manage"] = "read"
|
|
expires_at: datetime | None = None
|
|
|
|
|
|
class BulkFileShareRequest(BaseModel):
|
|
file_ids: list[str] = Field(default_factory=list, max_length=1000)
|
|
target_type: Literal["user", "group", "campaign", "tenant"]
|
|
target_id: str
|
|
permission: Literal["read", "write", "manage"] = "read"
|
|
expires_at: datetime | None = None
|
|
|
|
|
|
class BulkFileShareResponse(BaseModel):
|
|
shares: list[FileShareResponse]
|
|
shared_count: int
|
|
|
|
|
|
class RenameRequest(BaseModel):
|
|
file_ids: list[str] = Field(default_factory=list)
|
|
folder_paths: list[str] = Field(default_factory=list)
|
|
owner_type: Literal["user", "group"]
|
|
owner_id: str
|
|
mode: Literal["direct", "prefix", "suffix", "replace"]
|
|
new_name: str | None = None
|
|
find: str | None = None
|
|
replacement: str = ""
|
|
prefix: str = ""
|
|
suffix: str = ""
|
|
recursive: bool = False
|
|
dry_run: bool = True
|
|
|
|
|
|
class RenamePreviewItem(BaseModel):
|
|
kind: Literal["file", "folder"]
|
|
id: str
|
|
file_id: str | None = None
|
|
folder_path: str | None = None
|
|
old_path: str
|
|
new_path: str
|
|
|
|
|
|
class RenameResponse(BaseModel):
|
|
dry_run: bool
|
|
items: list[RenamePreviewItem]
|
|
|
|
|
|
class TransferRequest(BaseModel):
|
|
operation: Literal["move", "copy"]
|
|
file_ids: list[str] = Field(default_factory=list)
|
|
folder_paths: list[str] = Field(default_factory=list)
|
|
source_owner_type: Literal["user", "group"]
|
|
source_owner_id: str
|
|
target_owner_type: Literal["user", "group"]
|
|
target_owner_id: str
|
|
target_folder: str = ""
|
|
conflict_strategy: Literal["reject", "overwrite", "rename"] = "reject"
|
|
conflict_resolutions: list[ConflictResolutionRequest] = Field(default_factory=list)
|
|
|
|
|
|
class TransferResponse(BaseModel):
|
|
operation: str
|
|
files: int
|
|
folders: int
|
|
|
|
|
|
class ArchiveRequest(BaseModel):
|
|
file_ids: list[str]
|
|
filename: str = "files.zip"
|
|
|
|
|
|
class PatternResolveRequest(BaseModel):
|
|
patterns: list[str]
|
|
owner_type: Literal["user", "group"] | None = None
|
|
owner_id: str | None = None
|
|
campaign_id: str | None = None
|
|
path_prefix: str | None = None
|
|
include_unmatched: bool = True
|
|
case_sensitive: bool = False
|
|
|
|
|
|
class PatternMatchResponse(BaseModel):
|
|
pattern: str
|
|
matches: list[FileAssetResponse]
|
|
|
|
|
|
class PatternResolveResponse(BaseModel):
|
|
patterns: list[PatternMatchResponse]
|
|
unmatched: list[FileAssetResponse] = Field(default_factory=list)
|