113 lines
2.8 KiB
Python
113 lines
2.8 KiB
Python
"""Image schemas for request/response validation."""
|
|
|
|
from datetime import datetime
|
|
from typing import Any
|
|
from uuid import UUID
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
|
|
class ImageMetadata(BaseModel):
|
|
"""Image metadata structure."""
|
|
|
|
format: str = Field(..., description="Image format (jpeg, png, etc)")
|
|
checksum: str = Field(..., description="SHA256 checksum of file")
|
|
exif: dict[str, Any] | None = Field(None, description="EXIF data if available")
|
|
thumbnails: dict[str, str] = Field(default_factory=dict, description="Thumbnail URLs by quality level")
|
|
|
|
|
|
class ImageUploadResponse(BaseModel):
|
|
"""Response after successful image upload."""
|
|
|
|
id: UUID
|
|
filename: str
|
|
storage_path: str
|
|
file_size: int
|
|
mime_type: str
|
|
width: int
|
|
height: int
|
|
metadata: dict[str, Any]
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
"""Pydantic config."""
|
|
|
|
from_attributes = True
|
|
|
|
|
|
class ImageResponse(BaseModel):
|
|
"""Full image response with all fields."""
|
|
|
|
id: UUID
|
|
user_id: UUID
|
|
filename: str
|
|
storage_path: str
|
|
file_size: int
|
|
mime_type: str
|
|
width: int
|
|
height: int
|
|
metadata: dict[str, Any]
|
|
created_at: datetime
|
|
reference_count: int
|
|
|
|
class Config:
|
|
"""Pydantic config."""
|
|
|
|
from_attributes = True
|
|
|
|
|
|
class BoardImageCreate(BaseModel):
|
|
"""Schema for adding image to board."""
|
|
|
|
image_id: UUID = Field(..., description="ID of uploaded image")
|
|
position: dict[str, float] = Field(default_factory=lambda: {"x": 0, "y": 0}, description="Canvas position")
|
|
transformations: dict[str, Any] = Field(
|
|
default_factory=lambda: {
|
|
"scale": 1.0,
|
|
"rotation": 0,
|
|
"opacity": 1.0,
|
|
"flipped_h": False,
|
|
"flipped_v": False,
|
|
"greyscale": False,
|
|
},
|
|
description="Image transformations",
|
|
)
|
|
z_order: int = Field(default=0, description="Layer order")
|
|
|
|
@field_validator("position")
|
|
@classmethod
|
|
def validate_position(cls, v: dict[str, float]) -> dict[str, float]:
|
|
"""Validate position has x and y."""
|
|
if "x" not in v or "y" not in v:
|
|
raise ValueError("Position must contain 'x' and 'y' coordinates")
|
|
return v
|
|
|
|
|
|
class BoardImageResponse(BaseModel):
|
|
"""Response for board image with all metadata."""
|
|
|
|
id: UUID
|
|
board_id: UUID
|
|
image_id: UUID
|
|
position: dict[str, float]
|
|
transformations: dict[str, Any]
|
|
z_order: int
|
|
group_id: UUID | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
image: ImageResponse
|
|
|
|
class Config:
|
|
"""Pydantic config."""
|
|
|
|
from_attributes = True
|
|
|
|
|
|
class ImageListResponse(BaseModel):
|
|
"""Paginated list of images."""
|
|
|
|
images: list[ImageResponse]
|
|
total: int
|
|
page: int
|
|
page_size: int
|