Files
webref/backend/app/images/schemas.py
Danilo Reyes 3eb3d977f9
All checks were successful
CI/CD Pipeline / VM Test - backend-integration (push) Successful in 7s
CI/CD Pipeline / VM Test - full-stack (push) Successful in 7s
CI/CD Pipeline / VM Test - performance (push) Successful in 7s
CI/CD Pipeline / VM Test - security (push) Successful in 7s
CI/CD Pipeline / Backend Linting (push) Successful in 2s
CI/CD Pipeline / Frontend Linting (push) Successful in 15s
CI/CD Pipeline / Nix Flake Check (push) Successful in 41s
CI/CD Pipeline / CI Summary (push) Successful in 1s
phase 10
2025-11-02 14:26:15 -06:00

155 lines
4.6 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 BoardImageUpdate(BaseModel):
"""Schema for updating board image position/transformations."""
position: dict[str, float] | None = Field(None, description="Canvas position")
transformations: dict[str, Any] | None = Field(None, description="Image transformations")
z_order: int | None = Field(None, description="Layer order")
group_id: UUID | None = Field(None, description="Group membership")
@field_validator("position")
@classmethod
def validate_position(cls, v: dict[str, float] | None) -> dict[str, float] | None:
"""Validate position has x and y if provided."""
if v is not None and ("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 BulkImageUpdate(BaseModel):
"""Schema for bulk updating multiple images."""
image_ids: list[UUID] = Field(..., description="List of image IDs to update")
position_delta: dict[str, float] | None = Field(None, description="Position delta to apply")
transformations: dict[str, Any] | None = Field(None, description="Transformations to apply")
z_order_delta: int | None = Field(None, description="Z-order delta to apply")
@field_validator("position_delta")
@classmethod
def validate_position_delta(cls, v: dict[str, float] | None) -> dict[str, float] | None:
"""Validate position delta has dx and dy."""
if v is not None and ("dx" not in v or "dy" not in v):
raise ValueError("Position delta must contain 'dx' and 'dy'")
return v
class BulkUpdateResponse(BaseModel):
"""Response for bulk update operation."""
updated_count: int = Field(..., description="Number of images updated")
failed_count: int = Field(default=0, description="Number of images that failed to update")
image_ids: list[UUID] = Field(..., description="IDs of successfully updated images")
class ImageListResponse(BaseModel):
"""Paginated list of images."""
images: list[ImageResponse]
total: int
page: int
page_size: int