aigenrec/luminabackend
0
1import shutil2import os3import uuid4import tempfile5from typing import List6from fastapi import APIRouter, UploadFile, File, HTTPException, BackgroundTasks, Depends, Form, status7from services.document_service import document_service8from models.schemas import DocumentUploadResponse, DocumentList9from config.settings import settings10from api.deps import get_current_user11 12router = APIRouter()13 14@router.post("/upload", response_model=DocumentUploadResponse)15async def upload_document(16 background_tasks: BackgroundTasks,17 file: UploadFile = File(...),18 project_id: str = Form(...),19 current_user: dict = Depends(get_current_user)20):21 """22 Upload a document and start processing it.23 Securely handles file uploads.24 """25 temp_file = None26 try:27 # 1. Validate Project Access (Check ownership)28 # Ideally we check if project exists and belongs to user first.29 # For now, relying on RLS at database level or simple check.30 31 # 2. Validate File Type (MIME & Extension)32 allowed_mimes = [33 "application/pdf",34 "application/vnd.openxmlformats-officedocument.wordprocessingml.document",35 "text/plain"36 ]37 if file.content_type not in allowed_mimes:38 raise HTTPException(status.HTTP_400_BAD_REQUEST, "Invalid file type. Only PDF, DOCX, and TXT are supported.")39 40 file_ext = os.path.splitext(file.filename)[1].lower().replace('.', '')41 if file_ext not in settings.ALLOWED_EXTENSIONS:42 raise HTTPException(status.HTTP_400_BAD_REQUEST, f"Invalid file extension. Allowed: {settings.ALLOWED_EXTENSIONS}")43 44 # 3. Secure Temp File Creation45 # Use tempfile module for safer handling46 temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=f".{file_ext}", dir="temp")47 48 # 4. Stream content to check size49 file_size = 050 chunk_size = 1024 * 1024 # 1MB chunks51 52 while True:53 chunk = await file.read(chunk_size)54 if not chunk:55 break56 file_size += len(chunk)57 if file_size > settings.MAX_FILE_SIZE:58 temp_file.close()59 os.unlink(temp_file.name)60 raise HTTPException(status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, f"File size exceeds limit of {settings.MAX_FILE_SIZE} bytes")61 temp_file.write(chunk)62 63 temp_file.close()64 temp_path = temp_file.name65 66 # 5. Create document record in Supabase67 doc_data = {68 "project_id": project_id,69 "filename": file.filename,70 "file_type": file.content_type,71 "file_size": file_size,72 "upload_status": "pending"73 }74 75 response = document_service.client.table("documents").insert(doc_data).execute()76 77 if not response.data:78 raise HTTPException(500, "Failed to create document record")79 80 document = response.data[0]81 document_id = document["id"]82 83 # 6. Start background processing84 background_tasks.add_task(85 document_service.process_document,86 document_id=document_id,87 project_id=project_id,88 file_path=temp_path,89 filename=file.filename90 )91 92 return document93 94 except HTTPException as he:95 if temp_file and os.path.exists(temp_file.name):96 try:97 os.unlink(temp_file.name)98 except: pass99 raise he100 except Exception as e:101 if temp_file and os.path.exists(temp_file.name):102 try:103 os.unlink(temp_file.name)104 except: pass105 raise HTTPException(500, str(e))106 107@router.get("/{project_id}", response_model=DocumentList)108async def list_documents(109 project_id: str,110 current_user: dict = Depends(get_current_user)111):112 """113 List all documents for a project114 """115 try:116 # Verify project access first ideally, but RLS should handle filtering if configured.117 # Adding manual check for extra safety.118 119 # Basic query120 response = document_service.client.table("documents").select("*").eq("project_id", project_id).execute()121 return {"documents": response.data}122 except Exception as e:123 raise HTTPException(500, str(e))124 125@router.delete("/{document_id}")126async def delete_document(127 document_id: str,128 project_id: str,129 current_user: dict = Depends(get_current_user)130):131 """132 Delete a document133 """134 try:135 await document_service.delete_document(project_id, document_id)136 return {"message": "Document deleted successfully"}137 except Exception as e:138 raise HTTPException(500, str(e))