itcloud/backend/src/app/api/schemas.py

235 lines
4.9 KiB
Python

"""Pydantic schemas for API requests and responses."""
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, EmailStr, Field
from app.domain.models import AssetStatus, AssetType
# Auth schemas
class UserRegister(BaseModel):
"""User registration request."""
email: EmailStr
password: str = Field(min_length=8, max_length=100)
class UserLogin(BaseModel):
"""User login request."""
email: EmailStr
password: str
class Token(BaseModel):
"""JWT token response."""
access_token: str
refresh_token: str
token_type: str = "bearer"
class UserResponse(BaseModel):
"""User information response."""
id: str
email: str
is_active: bool
created_at: datetime
model_config = {"from_attributes": True}
# Asset schemas
class AssetResponse(BaseModel):
"""Asset information response."""
id: str
user_id: str
folder_id: Optional[str] = None
type: AssetType
status: AssetStatus
original_filename: str
content_type: str
size_bytes: int
sha256: Optional[str] = None
captured_at: Optional[datetime] = None
width: Optional[int] = None
height: Optional[int] = None
duration_sec: Optional[float] = None
storage_key_original: str
storage_key_thumb: Optional[str] = None
created_at: datetime
model_config = {"from_attributes": True}
class AssetListResponse(BaseModel):
"""Paginated list of assets."""
items: list[AssetResponse]
next_cursor: Optional[str] = None
has_more: bool
class CreateUploadRequest(BaseModel):
"""Request to create an upload."""
original_filename: str = Field(max_length=512)
content_type: str = Field(max_length=100)
size_bytes: int = Field(gt=0, le=21474836480) # Max 20GB
class CreateUploadResponse(BaseModel):
"""Response with upload credentials."""
asset_id: str
upload_url: str
upload_method: str = "presigned_post"
fields: Optional[dict] = None
class FinalizeUploadRequest(BaseModel):
"""Request to finalize an upload."""
etag: Optional[str] = None
sha256: Optional[str] = Field(None, max_length=64)
# Download URLs
class DownloadUrlResponse(BaseModel):
"""Pre-signed download URL."""
url: str
expires_in: int
# Share schemas
class CreateShareRequest(BaseModel):
"""Request to create a share link."""
asset_id: Optional[str] = None
album_id: Optional[str] = None
expires_in_seconds: Optional[int] = Field(None, gt=0)
password: Optional[str] = Field(None, min_length=6, max_length=100)
class ShareResponse(BaseModel):
"""Share link information."""
id: str
owner_user_id: str
asset_id: Optional[str] = None
album_id: Optional[str] = None
token: str
expires_at: Optional[datetime] = None
created_at: datetime
revoked_at: Optional[datetime] = None
model_config = {"from_attributes": True}
class ShareAccessRequest(BaseModel):
"""Request to access a shared resource."""
password: Optional[str] = None
class ShareWithAssetResponse(BaseModel):
"""Share with asset information."""
share: ShareResponse
asset: Optional[AssetResponse] = None
# Folder schemas
class FolderResponse(BaseModel):
"""Folder information response."""
id: str
user_id: str
name: str
parent_folder_id: Optional[str] = None
created_at: datetime
model_config = {"from_attributes": True}
class FolderListResponse(BaseModel):
"""List of folders."""
items: list[FolderResponse]
class FolderCreateRequest(BaseModel):
"""Request to create a folder."""
name: str = Field(min_length=1, max_length=255)
parent_folder_id: Optional[str] = None
class FolderUpdateRequest(BaseModel):
"""Request to update a folder."""
name: str = Field(min_length=1, max_length=255)
class BreadcrumbItem(BaseModel):
"""Breadcrumb item for folder navigation."""
id: str
name: str
parent_folder_id: Optional[str] = None
model_config = {"from_attributes": True}
class BreadcrumbsResponse(BaseModel):
"""Breadcrumbs path."""
items: list[BreadcrumbItem]
# Batch operation schemas
class BatchDeleteRequest(BaseModel):
"""Request to delete multiple assets."""
asset_ids: list[str] = Field(min_length=1, max_length=100)
class BatchDeleteResponse(BaseModel):
"""Response for batch delete operation."""
deleted: int
failed: int
total: int
class BatchMoveRequest(BaseModel):
"""Request to move multiple assets."""
asset_ids: list[str] = Field(min_length=1, max_length=100)
folder_id: Optional[str] = None # None = move to root
class BatchMoveResponse(BaseModel):
"""Response for batch move operation."""
moved: int
requested: int
class BatchDownloadRequest(BaseModel):
"""Request to download multiple assets."""
asset_ids: list[str] = Field(min_length=1, max_length=100)
# Error response
class ErrorResponse(BaseModel):
"""Standard error response."""
error: dict[str, str | dict]