- Default CORS_ORIGINS to http://localhost:5173 instead of "*" (still overridable) - Reject ".." and leading "/" in document keys/paths across get/save/delete/upload, mapped to HTTP 400 via new InvalidPathError - Add a delete button to DocumentEditor wired to deleteDocument + onDeleted, giving the existing DELETE API an actual UI entry point - Share a single lru_cache'd Meilisearch (and Minio) SDK client instance instead of constructing duplicates in dependencies.py - Add a startup check that creates the MinIO bucket if missing, tolerating MinIO being unreachable at boot without crashing the app
68 lines
2.2 KiB
Python
68 lines
2.2 KiB
Python
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
|
|
from pydantic import BaseModel
|
|
|
|
from app.dependencies import get_document_service
|
|
from app.document_service import (
|
|
DocumentNotFoundError,
|
|
DocumentService,
|
|
FileTooLargeError,
|
|
InvalidPathError,
|
|
UnsupportedFileTypeError,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class SaveDocumentRequest(BaseModel):
|
|
content: str
|
|
contentType: str
|
|
|
|
|
|
@router.get("/api/documents")
|
|
def list_documents(path: str = "", service: DocumentService = Depends(get_document_service)):
|
|
return service.list_documents(path)
|
|
|
|
|
|
@router.get("/api/documents/{key:path}")
|
|
def get_document(key: str, service: DocumentService = Depends(get_document_service)):
|
|
try:
|
|
return service.get_document(key)
|
|
except DocumentNotFoundError:
|
|
raise HTTPException(status_code=404, detail="Document not found")
|
|
except InvalidPathError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc))
|
|
|
|
|
|
@router.put("/api/documents/{key:path}")
|
|
def save_document(
|
|
key: str, body: SaveDocumentRequest, service: DocumentService = Depends(get_document_service)
|
|
):
|
|
try:
|
|
return service.save_document(key, body.content.encode("utf-8"), body.contentType)
|
|
except InvalidPathError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc))
|
|
|
|
|
|
@router.delete("/api/documents/{key:path}", status_code=204)
|
|
def delete_document(key: str, service: DocumentService = Depends(get_document_service)):
|
|
try:
|
|
service.delete_document(key)
|
|
except InvalidPathError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc))
|
|
return None
|
|
|
|
|
|
@router.post("/api/upload", status_code=201)
|
|
async def upload_document(
|
|
file: UploadFile = File(...),
|
|
path: str = Form(...),
|
|
service: DocumentService = Depends(get_document_service),
|
|
):
|
|
data = await file.read()
|
|
key = f"{path.rstrip('/')}/{file.filename}" if path else file.filename
|
|
content_type = file.content_type or "application/octet-stream"
|
|
try:
|
|
return service.upload_document(key, data, content_type)
|
|
except (UnsupportedFileTypeError, FileTooLargeError, InvalidPathError) as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc))
|