Files
webref/backend/app/api/export.py
Danilo Reyes a8315d03fd
All checks were successful
CI/CD Pipeline / VM Test - backend-integration (push) Successful in 12s
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 4s
CI/CD Pipeline / Frontend Linting (push) Successful in 30s
CI/CD Pipeline / Nix Flake Check (push) Successful in 43s
CI/CD Pipeline / VM Test - backend-integration (pull_request) Successful in 4s
CI/CD Pipeline / VM Test - full-stack (pull_request) Successful in 2s
CI/CD Pipeline / VM Test - performance (pull_request) Successful in 2s
CI/CD Pipeline / VM Test - security (pull_request) Successful in 2s
CI/CD Pipeline / Backend Linting (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Linting (pull_request) Successful in 17s
CI/CD Pipeline / Nix Flake Check (pull_request) Successful in 38s
CI/CD Pipeline / CI Summary (push) Successful in 1s
CI/CD Pipeline / CI Summary (pull_request) Successful in 1s
fix until the canvas sort of works
2025-11-02 19:13:08 -06:00

129 lines
4.1 KiB
Python

"""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_sync
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_sync),
) -> 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_sync),
) -> 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_sync),
) -> 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_sync),
) -> 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
}