from fastapi import APIRouter,Depends,File,Form,HTTPException,Query,UploadFile from fastapi.responses import JSONResponse from pydantic import BaseModel from s3.views import S3Storage from users.permissions import PermissionTag,require_permission from dotenv import load_dotenv load_dotenv() router=APIRouter() class DeleteObjectBody(BaseModel): key: str @router.get("/s3/health") async def s3_health(): """Bucket reachability — unauthenticated like GET /sheet/health.""" try: service=S3Storage() data=await service.health_check() return JSONResponse(content={"data":data,"total":1,"status_code":200}) except HTTPException: raise except Exception as e: raise HTTPException(status_code=500,detail=str(e)) @router.post("/s3/upload") async def upload_s3_file( file: UploadFile=File(...), source: str=Form(...), record_id: str=Form(...), owner_id: str=Form(...), current_user: dict=Depends(require_permission(PermissionTag.CANDIDATES_CREATE,PermissionTag.SETTINGS_EDIT,require_all=False)), ): """PDF only. Private PutObject under {source}/{record_id}/{owner_id}/{file}.pdf.""" try: service=S3Storage() data=await service.upload_for_record(file,source=source,record_id=record_id,owner_id=owner_id) return JSONResponse(content={"data":data,"total":1,"status_code":200}) except HTTPException: raise except Exception as e: raise HTTPException(status_code=500,detail=str(e)) @router.get("/s3/url") async def fetch_s3_url( key: str=Query(...), current_user: dict=Depends(require_permission(PermissionTag.CANDIDATES_VIEW,PermissionTag.SETTINGS_VIEW,require_all=False)), ): """Stable private object address stored in file_path (not anonymously openable).""" try: service=S3Storage() data=await service.object_url(key) return JSONResponse(content={"data":data,"total":1,"status_code":200}) except HTTPException: raise except Exception as e: raise HTTPException(status_code=500,detail=str(e)) @router.get("/s3/open") async def open_s3_file( key: str=Query(...,description="S3 key or stored file_path URL"), expires_in: int | None=Query(None,ge=60,le=604800), current_user: dict=Depends(require_permission(PermissionTag.CANDIDATES_VIEW,PermissionTag.SETTINGS_VIEW,PermissionTag.INBOX_VIEW,require_all=False)), ): """Short-lived presigned GET for a private CV — open this URL in the browser.""" try: service=S3Storage() data=await service.open_url(key,expires_in=expires_in) return JSONResponse(content={"data":data,"total":1,"status_code":200}) except HTTPException: raise except Exception as e: raise HTTPException(status_code=500,detail=str(e)) @router.get("/s3/download") async def download_s3_file( key: str=Query(...,description="S3 key or stored file_path URL"), current_user: dict=Depends(require_permission(PermissionTag.CANDIDATES_VIEW,PermissionTag.SETTINGS_VIEW,require_all=False)), ): """Stream a private PDF through the API (IAM GetObject — no public bucket).""" try: service=S3Storage() return await service.download_file(key) except HTTPException: raise except Exception as e: raise HTTPException(status_code=500,detail=str(e)) @router.post("/s3/delete") async def delete_s3_file( payload: DeleteObjectBody, current_user: dict=Depends(require_permission(PermissionTag.CANDIDATES_DELETE,PermissionTag.SETTINGS_DELETE,require_all=False)), ): try: service=S3Storage() data=await service.delete_file(payload.key) return JSONResponse(content={"data":data,"total":1,"status_code":200}) except HTTPException: raise except Exception as e: raise HTTPException(status_code=500,detail=str(e))