Implements all 88 tasks for the Reaction Image Board (specs/001-reaction-image-board): - docker-compose.yml: postgres, minio, minio-init, api, ui services with healthchecks - api/: FastAPI app with SQLAlchemy 2.x async, Alembic migrations, S3/MinIO storage, full integration + unit test suite (pytest + pytest-asyncio) - ui/: Angular 19 standalone app (Library, Upload, Detail, NotFound components) - .env.example: all required environment variables - .gitignore: Python, Node, Docker, IDE, .env patterns Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
22 lines
604 B
Python
22 lines
604 B
Python
ACCEPTED_MIME_TYPES = frozenset(["image/jpeg", "image/png", "image/gif", "image/webp"])
|
|
|
|
|
|
class MimeTypeError(ValueError):
|
|
pass
|
|
|
|
|
|
class FileSizeError(ValueError):
|
|
pass
|
|
|
|
|
|
def validate_mime_type(mime_type: str) -> None:
|
|
if mime_type not in ACCEPTED_MIME_TYPES:
|
|
raise MimeTypeError(f"Unsupported MIME type: {mime_type}")
|
|
|
|
|
|
def validate_file_size(size_bytes: int, max_bytes: int) -> None:
|
|
if size_bytes <= 0:
|
|
raise FileSizeError("File must not be empty")
|
|
if size_bytes > max_bytes:
|
|
raise FileSizeError(f"File size {size_bytes} exceeds limit of {max_bytes} bytes")
|