80 lines
2.8 KiB
Python
80 lines
2.8 KiB
Python
"""S3 storage service — upload / delete / health over the plugins S3 class."""
|
|
|
|
from fastapi import HTTPException,UploadFile
|
|
|
|
from s3.plugins import S3,S3ServiceError,assert_pdf
|
|
from s3.serializers import serialize_delete,serialize_health,serialize_upload
|
|
|
|
|
|
class S3Storage:
|
|
"""No DB session — pure object storage against the configured bucket."""
|
|
|
|
def __init__(self):
|
|
self.s3=S3()
|
|
|
|
def _map(self,exc:S3ServiceError):
|
|
raise HTTPException(status_code=exc.status_code,detail=exc.message)
|
|
|
|
async def health_check(self):
|
|
try:
|
|
return serialize_health(self.s3.head_bucket())
|
|
except S3ServiceError as e:
|
|
self._map(e)
|
|
|
|
async def upload_for_record(self,file:UploadFile,source,record_id,owner_id):
|
|
"""PDF gate → PutObject under {source}/{record_id}/{owner_id}/{name}.pdf."""
|
|
if file is None:
|
|
raise HTTPException(status_code=422,detail="file is required")
|
|
filename=(file.filename or "").strip() or "resume.pdf"
|
|
try:
|
|
assert_pdf(filename,file.content_type)
|
|
except S3ServiceError as e:
|
|
self._map(e)
|
|
body=await file.read()
|
|
if not body:
|
|
raise HTTPException(status_code=422,detail="file is empty")
|
|
try:
|
|
result=self.s3.upload_for_record(
|
|
body,
|
|
filename,
|
|
source=source,
|
|
record_id=record_id,
|
|
owner_id=owner_id,
|
|
content_type=file.content_type,
|
|
)
|
|
return serialize_upload(result)
|
|
except S3ServiceError as e:
|
|
self._map(e)
|
|
|
|
async def upload_bytes_for_record(self,body,filename,source,record_id,owner_id,content_type=None):
|
|
try:
|
|
assert_pdf(filename or "resume.pdf",content_type)
|
|
result=self.s3.upload_for_record(
|
|
body,
|
|
filename or "resume.pdf",
|
|
source=source,
|
|
record_id=record_id,
|
|
owner_id=owner_id,
|
|
content_type=content_type,
|
|
)
|
|
return serialize_upload(result)
|
|
except S3ServiceError as e:
|
|
self._map(e)
|
|
|
|
async def delete_file(self,key):
|
|
if not key or not str(key).strip():
|
|
raise HTTPException(status_code=422,detail="key is required")
|
|
try:
|
|
return serialize_delete(self.s3.delete_object(str(key).strip()))
|
|
except S3ServiceError as e:
|
|
self._map(e)
|
|
|
|
async def object_url(self,key):
|
|
if not key or not str(key).strip():
|
|
raise HTTPException(status_code=422,detail="key is required")
|
|
try:
|
|
url=self.s3.permanent_object_url(str(key).strip())
|
|
return {"key":str(key).strip(),"url":url}
|
|
except S3ServiceError as e:
|
|
self._map(e)
|