123 lines
4.4 KiB
Python
123 lines
4.4 KiB
Python
import boto3
|
|
import app.config as config
|
|
import uuid
|
|
from fastapi import APIRouter, UploadFile, HTTPException
|
|
from starlette import status
|
|
from starlette.responses import StreamingResponse
|
|
from botocore.exceptions import ClientError
|
|
from app.s3 import schema_s3
|
|
|
|
s3_client = boto3.client(
|
|
"s3",
|
|
aws_access_key_id=config.S3_ACCESS_KEY_ID,
|
|
aws_secret_access_key=config.S3_SECRET_ACCESS_KEY,
|
|
endpoint_url=config.S3_ENDPOINT_URL,
|
|
region_name=config.S3_REGION_NAME,
|
|
)
|
|
|
|
router = APIRouter(
|
|
prefix="/api/s3",
|
|
tags=["S3 Manipulação Arquivos"],
|
|
responses={404: {"description": "Not found"}},
|
|
)
|
|
|
|
|
|
@router.post("/upload", status_code=status.HTTP_200_OK)
|
|
async def upload_to_s3(file: UploadFile):
|
|
"""
|
|
Faz upload de uma imagem para o bucket restrito.
|
|
"""
|
|
try:
|
|
unique_filename = f"{uuid.uuid4()}-{file.filename}"
|
|
s3_client.upload_fileobj(
|
|
file.file,
|
|
config.S3_BUCKET_NAME,
|
|
unique_filename,
|
|
ExtraArgs={
|
|
"ContentType": file.content_type,
|
|
"Metadata": {"original_filename": file.filename}
|
|
},
|
|
)
|
|
return {"message": "Arquivo salvo com sucesso", "nome do arquivo": unique_filename}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.post("/images/url/")
|
|
async def get_presigned_url(request: schema_s3.FileNameRequest):
|
|
"""
|
|
Gera uma URL pré-assinada para download do arquivo, com o nome original configurado.
|
|
"""
|
|
try:
|
|
file_name = request.file_name # Nome do arquivo com UUID
|
|
|
|
# Obter os metadados do arquivo para o nome original
|
|
response = s3_client.head_object(Bucket=config.S3_BUCKET_NAME, Key=file_name)
|
|
metadata = response.get("Metadata", {})
|
|
original_filename = metadata.get("original_filename", file_name)
|
|
|
|
# Gerar uma URL pré-assinada para download
|
|
presigned_url = s3_client.generate_presigned_url(
|
|
"get_object",
|
|
Params={
|
|
"Bucket": config.S3_BUCKET_NAME,
|
|
"Key": file_name,
|
|
"ResponseContentDisposition": f'attachment; filename="{original_filename}"'
|
|
},
|
|
ExpiresIn=3600, # URL válida por 1 hora
|
|
)
|
|
|
|
return {"url": presigned_url}
|
|
except ClientError as e:
|
|
if e.response["Error"]["Code"] == "NoSuchKey":
|
|
raise HTTPException(status_code=404, detail="Arquivo não encontrado")
|
|
raise HTTPException(status_code=500, detail="Erro ao gerar URL")
|
|
|
|
|
|
@router.post("/images/url/simple/")
|
|
async def generate_presigned_url(request: schema_s3.FileNameRequest):
|
|
"""
|
|
Gera uma URL pré-assinada para acessar o arquivo no MinIO (sem download automático).
|
|
"""
|
|
try:
|
|
file_name = request.file_name # Nome do arquivo com UUID
|
|
|
|
# Gerar uma URL pré-assinada sem configurar o download automático
|
|
presigned_url = s3_client.generate_presigned_url(
|
|
"get_object",
|
|
Params={
|
|
"Bucket": config.S3_BUCKET_NAME,
|
|
"Key": file_name
|
|
},
|
|
ExpiresIn=3600, # URL válida por 1 hora
|
|
)
|
|
|
|
return {"url": presigned_url}
|
|
except ClientError as e:
|
|
if e.response["Error"]["Code"] == "NoSuchKey":
|
|
raise HTTPException(status_code=404, detail="File not found")
|
|
raise HTTPException(status_code=500, detail="Error generating presigned URL")
|
|
|
|
|
|
@router.post("/images/")
|
|
async def get_image(request: schema_s3.FileNameRequest):
|
|
"""
|
|
Retorna uma imagem específica para download.
|
|
O usuário precisa estar autenticado para acessar.
|
|
"""
|
|
try:
|
|
file_name = request.file_name
|
|
# Baixar o objeto do MinIO como um fluxo
|
|
response = s3_client.get_object(Bucket=config.S3_BUCKET_NAME, Key=file_name)
|
|
metadata = response.get("Metadata", {})
|
|
original_filename = metadata.get("original_filename", file_name) # Nome original ou o atual
|
|
return StreamingResponse(
|
|
response["Body"],
|
|
media_type=response["ContentType"], # Tipo de arquivo, ex.: image/jpeg
|
|
headers={"Content-Disposition": f'attachment; filename="{original_filename}"'}
|
|
)
|
|
except ClientError as e:
|
|
if e.response["Error"]["Code"] == "NoSuchKey":
|
|
raise HTTPException(status_code=404, detail="File not found")
|
|
raise HTTPException(status_code=500, detail="Error accessing file")
|