All checks were successful
CI/CD Pipeline / VM Test - backend-integration (push) Successful in 11s
CI/CD Pipeline / VM Test - full-stack (push) Successful in 8s
CI/CD Pipeline / VM Test - performance (push) Successful in 8s
CI/CD Pipeline / VM Test - security (push) Successful in 8s
CI/CD Pipeline / Backend Linting (push) Successful in 3s
CI/CD Pipeline / Frontend Linting (push) Successful in 18s
CI/CD Pipeline / Nix Flake Check (push) Successful in 43s
CI/CD Pipeline / CI Summary (push) Successful in 0s
63 lines
1.8 KiB
Python
63 lines
1.8 KiB
Python
"""Image download functionality."""
|
|
|
|
import io
|
|
from pathlib import Path
|
|
|
|
from fastapi import HTTPException, status
|
|
from fastapi.responses import StreamingResponse
|
|
|
|
from app.core.storage import storage_client
|
|
|
|
|
|
async def download_single_image(storage_path: str, filename: str) -> StreamingResponse:
|
|
"""
|
|
Download a single image from storage.
|
|
|
|
Args:
|
|
storage_path: Path to image in MinIO
|
|
filename: Original filename for download
|
|
|
|
Returns:
|
|
StreamingResponse with image data
|
|
|
|
Raises:
|
|
HTTPException: If image not found or download fails
|
|
"""
|
|
try:
|
|
# Get image from storage
|
|
image_data = storage_client.get_object(storage_path)
|
|
|
|
if image_data is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Image not found in storage",
|
|
)
|
|
|
|
# Determine content type from file extension
|
|
extension = Path(filename).suffix.lower()
|
|
content_type_map = {
|
|
".jpg": "image/jpeg",
|
|
".jpeg": "image/jpeg",
|
|
".png": "image/png",
|
|
".gif": "image/gif",
|
|
".webp": "image/webp",
|
|
".svg": "image/svg+xml",
|
|
}
|
|
content_type = content_type_map.get(extension, "application/octet-stream")
|
|
|
|
# Return streaming response
|
|
return StreamingResponse(
|
|
io.BytesIO(image_data),
|
|
media_type=content_type,
|
|
headers={
|
|
"Content-Disposition": f'attachment; filename="{filename}"',
|
|
"Cache-Control": "no-cache",
|
|
},
|
|
)
|
|
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Failed to download image: {str(e)}",
|
|
) from e
|