rcnn/backend/apps/utils/storage.py
Marius Unsel d93412cd0d Initial commit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 01:12:40 +02:00

78 lines
2.1 KiB
Python

import boto3
from botocore.exceptions import ClientError
from django.conf import settings
def _is_s3_storage():
return "S3Boto3Storage" in settings.DEFAULT_FILE_STORAGE
def _get_client():
return boto3.client(
"s3",
endpoint_url=settings.AWS_S3_ENDPOINT_URL,
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
region_name=settings.AWS_S3_REGION_NAME,
)
def generate_presigned_put_url(key, content_type="video/mp4", expires_in=3600):
"""
Return a presigned PUT URL the client can use to upload directly to Wasabi.
In development (local filesystem storage) returns None — callers should handle this.
"""
if not _is_s3_storage():
return None
client = _get_client()
return client.generate_presigned_url(
"put_object",
Params={
"Bucket": settings.AWS_STORAGE_BUCKET_NAME,
"Key": key,
"ContentType": content_type,
},
ExpiresIn=expires_in,
)
def generate_presigned_get_url(key, expires_in=3600):
"""Return a presigned GET URL for downloading a private Wasabi object."""
if not _is_s3_storage():
return None
client = _get_client()
return client.generate_presigned_url(
"get_object",
Params={
"Bucket": settings.AWS_STORAGE_BUCKET_NAME,
"Key": key,
},
ExpiresIn=expires_in,
)
def object_exists(key):
"""Return True if the object exists in the Wasabi bucket."""
if not _is_s3_storage():
# In dev, assume upload happened (no real Wasabi)
return True
client = _get_client()
try:
client.head_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=key)
return True
except ClientError:
return False
def preview_url(key):
"""
Return the public URL for a preview image.
Uses Cloudflare CDN in production; falls back to a presigned URL.
"""
if not key:
return None
cdn = settings.CDN_BASE_URL
if cdn:
return f"{cdn.rstrip('/')}/{key}"
return generate_presigned_get_url(key, expires_in=86400)