Refactoring of services.py; tests

This commit is contained in:
2026-06-13 04:07:46 +02:00
parent f3db5fc5cf
commit 36e9211ee6
15 changed files with 2113 additions and 920 deletions

View File

@@ -0,0 +1,186 @@
from __future__ import annotations
from typing import Any, Literal
from pydantic import BaseModel, Field
from app.storage.common import FileConflictResolution
class FileSpaceResponse(BaseModel):
id: str
label: str
owner_type: Literal["user", "group"]
owner_id: str
description: str | None = None
class FileSpacesResponse(BaseModel):
spaces: list[FileSpaceResponse]
class FileShareResponse(BaseModel):
id: str
target_type: str
target_id: str
permission: str
created_at: str
revoked_at: str | None = None
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
audit_relevant: bool = False
metadata: dict[str, Any] | 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]
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]
class FileUploadResponse(BaseModel):
files: list[FileAssetResponse]
class BulkDeleteRequest(BaseModel):
file_ids: list[str]
class BulkDeleteResponse(BaseModel):
deleted_count: int
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"
class RenameRequest(BaseModel):
file_ids: list[str] = Field(default_factory=list)
folder_paths: list[str] = Field(default_factory=list)
owner_type: Literal["user", "group"] | None = None
owner_id: str | None = None
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)