11"""File management API endpoints backed by ABI ObjectStorageService."""
22
33from datetime import datetime
4- from pathlib import PurePosixPath
4+ from pathlib import Path , PurePosixPath
5+ import shutil
6+ import subprocess
7+ import tempfile
58
69from fastapi import APIRouter , Depends , File , Form , HTTPException , Query , Request , Response , UploadFile
710from naas_abi .apps .nexus .apps .api .app .api .endpoints .auth import get_current_user_required
@@ -244,6 +247,12 @@ async def list_files(request: Request, path: str = Query("", description="Direct
244247 ".yaml" : "text/yaml" ,
245248 ".yml" : "text/yaml" ,
246249 ".pdf" : "application/pdf" ,
250+ ".png" : "image/png" ,
251+ ".jpg" : "image/jpeg" ,
252+ ".jpeg" : "image/jpeg" ,
253+ ".gif" : "image/gif" ,
254+ ".webp" : "image/webp" ,
255+ ".svg" : "image/svg+xml" ,
247256 }
248257 content_type = content_types .get (ext , "application/octet-stream" )
249258 except Exceptions .ObjectNotFound :
@@ -400,6 +409,65 @@ async def upload_file(
400409# =============================================================================
401410
402411
412+ @router .get ("/preview/pdf/{path:path}" )
413+ async def preview_file_as_pdf (request : Request , path : str ):
414+ """Preview a presentation file as PDF (requires LibreOffice)."""
415+ storage = get_object_storage (request )
416+ normalized_path = normalize_relative_path (path )
417+ ext = PurePosixPath (normalized_path ).suffix .lower ()
418+ if ext not in {".ppt" , ".pptx" }:
419+ raise HTTPException (status_code = 400 , detail = "Only PPT/PPTX preview is supported" )
420+ if _is_directory (storage , normalized_path ):
421+ raise HTTPException (status_code = 400 , detail = "Cannot preview a directory" )
422+
423+ try :
424+ content_bytes = _read_bytes (storage , normalized_path )
425+ except Exceptions .ObjectNotFound as exc :
426+ raise HTTPException (status_code = 404 , detail = "File not found" ) from exc
427+
428+ soffice = shutil .which ("soffice" ) or shutil .which ("libreoffice" )
429+ if not soffice :
430+ raise HTTPException (
431+ status_code = 501 ,
432+ detail = "PPTX preview is unavailable: LibreOffice is not installed on the API service." ,
433+ )
434+
435+ with tempfile .TemporaryDirectory (prefix = "nexus-ppt-preview-" ) as tmp_dir :
436+ input_path = Path (tmp_dir ) / PurePosixPath (normalized_path ).name
437+ output_name = f"{ PurePosixPath (normalized_path ).stem } .pdf"
438+ output_path = Path (tmp_dir ) / output_name
439+ input_path .write_bytes (content_bytes )
440+
441+ result = subprocess .run (
442+ [
443+ soffice ,
444+ "--headless" ,
445+ "--convert-to" ,
446+ "pdf" ,
447+ "--outdir" ,
448+ str (Path (tmp_dir )),
449+ str (input_path ),
450+ ],
451+ capture_output = True ,
452+ text = True ,
453+ timeout = 60 ,
454+ check = False ,
455+ )
456+ if result .returncode != 0 or not output_path .exists ():
457+ raise HTTPException (
458+ status_code = 500 ,
459+ detail = "Failed to convert presentation to PDF preview." ,
460+ )
461+
462+ pdf_bytes = output_path .read_bytes ()
463+
464+ return Response (
465+ content = pdf_bytes ,
466+ media_type = "application/pdf" ,
467+ headers = {"Content-Disposition" : f'inline; filename="{ output_name } "' },
468+ )
469+
470+
403471@router .get ("/raw/{path:path}" )
404472async def read_file_raw (request : Request , path : str ):
405473 """Read raw file bytes (for binary previews/downloads)."""
@@ -425,6 +493,12 @@ async def read_file_raw(request: Request, path: str):
425493 ".yaml" : "text/yaml" ,
426494 ".yml" : "text/yaml" ,
427495 ".pdf" : "application/pdf" ,
496+ ".png" : "image/png" ,
497+ ".jpg" : "image/jpeg" ,
498+ ".jpeg" : "image/jpeg" ,
499+ ".gif" : "image/gif" ,
500+ ".webp" : "image/webp" ,
501+ ".svg" : "image/svg+xml" ,
428502 }
429503 content_type = content_types .get (ext , "application/octet-stream" )
430504 filename = PurePosixPath (normalized_path ).name
0 commit comments