# app/api/v1/admin/images.py """ Admin image management endpoints. Provides: - Image upload with automatic processing - Image deletion - Storage statistics """ import logging from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile from app.api.deps import get_current_admin_api from app.services.image_service import image_service from models.database.user import User from models.schema.image import ( ImageDeleteResponse, ImageStorageStats, ImageUploadResponse, ) router = APIRouter(prefix="/images") logger = logging.getLogger(__name__) # Maximum upload size (10MB) MAX_UPLOAD_SIZE = 10 * 1024 * 1024 @router.post("/upload", response_model=ImageUploadResponse) async def upload_image( file: UploadFile = File(...), vendor_id: int = Form(...), product_id: int | None = Form(None), current_admin: User = Depends(get_current_admin_api), ): """Upload and process an image. The image will be: - Converted to WebP format - Resized to multiple variants (original, 800px, 200px) - Stored in a sharded directory structure Args: file: Image file to upload vendor_id: Vendor ID for the image product_id: Optional product ID Returns: Image URLs and metadata """ # Validate file size content = await file.read() if len(content) > MAX_UPLOAD_SIZE: raise HTTPException( status_code=413, detail=f"File too large. Maximum size: {MAX_UPLOAD_SIZE // (1024*1024)}MB", ) # Validate content type if not file.content_type or not file.content_type.startswith("image/"): raise HTTPException( status_code=400, detail="Invalid file type. Only images are allowed.", ) try: result = image_service.upload_product_image( file_content=content, filename=file.filename or "image.jpg", vendor_id=vendor_id, product_id=product_id, ) logger.info(f"Image uploaded: {result['id']} for vendor {vendor_id}") return ImageUploadResponse(success=True, image=result) except ValueError as e: logger.warning(f"Image upload failed: {e}") return ImageUploadResponse(success=False, error=str(e)) except Exception as e: logger.error(f"Image upload error: {e}") raise HTTPException(status_code=500, detail="Failed to process image") @router.delete("/{image_hash}", response_model=ImageDeleteResponse) async def delete_image( image_hash: str, current_admin: User = Depends(get_current_admin_api), ): """Delete an image and all its variants. Args: image_hash: The image ID/hash Returns: Deletion status """ deleted = image_service.delete_product_image(image_hash) if deleted: logger.info(f"Image deleted: {image_hash}") return ImageDeleteResponse(success=True, message="Image deleted successfully") else: return ImageDeleteResponse(success=False, message="Image not found") @router.get("/stats", response_model=ImageStorageStats) async def get_storage_stats( current_admin: User = Depends(get_current_admin_api), ): """Get image storage statistics. Returns: Storage metrics including file counts, sizes, and directory info """ stats = image_service.get_storage_stats() return ImageStorageStats(**stats)