152 lines
3.3 KiB
Python
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]
|