"""Export API endpoints for downloading and exporting images.""" from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query, status from fastapi.responses import StreamingResponse from sqlalchemy.orm import Session from app.core.deps import get_current_user, get_db from app.database.models.board import Board from app.database.models.board_image import BoardImage from app.database.models.image import Image from app.database.models.user import User from app.images.download import download_single_image from app.images.export_composite import create_composite_export from app.images.export_zip import create_zip_export router = APIRouter(tags=["export"]) @router.get("/images/{image_id}/download") async def download_image( image_id: UUID, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> StreamingResponse: """ Download a single image. Only the image owner can download it. """ # Verify image exists and user owns it image = db.query(Image).filter(Image.id == image_id, Image.user_id == current_user.id).first() if image is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Image not found or access denied", ) return await download_single_image(image.storage_path, image.filename) @router.get("/boards/{board_id}/export/zip") def export_board_zip( board_id: UUID, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> StreamingResponse: """ Export all images from a board as a ZIP file. Only the board owner can export it. """ # Verify board exists and user owns it board = db.query(Board).filter(Board.id == board_id, Board.user_id == current_user.id).first() if board is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Board not found or access denied", ) return create_zip_export(str(board_id), db) @router.get("/boards/{board_id}/export/composite") def export_board_composite( board_id: UUID, scale: float = Query(1.0, ge=0.5, le=4.0, description="Resolution scale (0.5x to 4x)"), format: str = Query("PNG", regex="^(PNG|JPEG)$", description="Output format (PNG or JPEG)"), current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> StreamingResponse: """ Export board as a single composite image showing the layout. Only the board owner can export it. Args: scale: Resolution multiplier (0.5x, 1x, 2x, 4x) format: Output format (PNG or JPEG) """ # Verify board exists and user owns it board = db.query(Board).filter(Board.id == board_id, Board.user_id == current_user.id).first() if board is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Board not found or access denied", ) return create_composite_export(str(board_id), db, scale=scale, format=format) @router.get("/boards/{board_id}/export/info") def get_export_info( board_id: UUID, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> dict: """ Get information about board export (image count, estimated size). Useful for showing progress estimates. """ # Verify board exists and user owns it board = db.query(Board).filter(Board.id == board_id, Board.user_id == current_user.id).first() if board is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Board not found or access denied", ) # Count images and calculate estimated size images = ( db.query(Image).join(BoardImage, BoardImage.image_id == Image.id).filter(BoardImage.board_id == board_id).all() ) total_size = sum(img.file_size for img in images) return { "board_id": str(board_id), "image_count": len(images), "total_size_bytes": total_size, "estimated_zip_size_bytes": int(total_size * 0.95), # ZIP usually has small overhead }