Files
webref/backend/app/images/schemas.py
Danilo Reyes 010df31455 phase 5
2025-11-02 11:07:42 -06:00

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