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

152 lines
3.3 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
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
deleted_at: Optional[datetime] = None
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
# Error response
class ErrorResponse(BaseModel):
"""Standard error response."""
error: dict[str, str | dict]