""" REST routes — upload, download, session info, delete. """ from __future__ import annotations import os from fastapi import APIRouter, UploadFile, File, HTTPException from fastapi.responses import FileResponse from models.schemas import UploadResponse, SessionInfo, ErrorResponse from services import file_manager, session_manager, audit_service router = APIRouter(tags=["file operations"]) # ── Upload ───────────────────────────────────────────────────────── @router.post( "/upload", response_model=UploadResponse, responses={400: {"model": ErrorResponse}, 413: {"model": ErrorResponse}}, summary="Upload CSV / Excel / Parquet file", ) async def upload_file(file: UploadFile = File(...)): content = await file.read() try: result = file_manager.handle_upload(content, file.filename or "unknown.csv") except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: raise HTTPException(status_code=500, detail=f"Upload failed: {e}") return UploadResponse(**result) # ── Download ─────────────────────────────────────────────────────── @router.get( "/download/{session_id}", responses={404: {"model": ErrorResponse}}, summary="Download file as CSV", ) async def download_file(session_id: str): csv_path = file_manager.export_to_csv(session_id) if csv_path is None: raise HTTPException(status_code=404, detail="Session not found") return FileResponse( path=csv_path, media_type="text/csv", filename=f"{session_id}.csv", ) # ── Session info ─────────────────────────────────────────────────── @router.get( "/session/{session_id}", response_model=SessionInfo, responses={404: {"model": ErrorResponse}}, summary="Get session metadata", ) async def get_session(session_id: str): meta = session_manager.get(session_id) if meta is None: raise HTTPException(status_code=404, detail="Session not found") return SessionInfo( session_id=meta.session_id, file_name=meta.file_name, file_size_bytes=meta.file_size_bytes, columns=meta.columns, row_count=meta.row_count, status=meta.status, ) # ── Delete session ───────────────────────────────────────────────── @router.delete( "/session/{session_id}", summary="Delete session and its data", ) async def delete_session(session_id: str): ok = file_manager.delete_session(session_id) if not ok: raise HTTPException(status_code=404, detail="Session not found") return {"detail": "Session deleted"} # ── Audit history ────────────────────────────────────────────────── @router.get( "/history/{session_id}", summary="Get command history for a session", ) async def get_history(session_id: str, limit: int = 50): history = await audit_service.get_history(session_id, limit) return {"history": history}