api-admim/app/s3/router_s3_sem_repository.py

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")