Frontend now uploads media directly to MinIO and sends only the resulting object_key; the backend never touches file bytes. Mattermost post bodies carry "<type>:<object_key>" instead of a permanent public URL, and download links are signed fresh on every read (send + list) so they can't outlive their expiry. Also wires up MINIO_SECURE, which settings.py previously never read from env. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
45 lines
1.7 KiB
Python
45 lines
1.7 KiB
Python
from datetime import timedelta
|
|
|
|
from django.conf import settings
|
|
from minio import Minio
|
|
|
|
|
|
class StorageService:
|
|
"""
|
|
Thin adapter around MinIO for the object-key-in-message-body flow: the
|
|
frontend uploads media directly to MinIO and only ever sends us the
|
|
resulting object key, so this service's job is limited to turning that
|
|
key back into a short-lived download URL on read.
|
|
"""
|
|
|
|
def __init__(self):
|
|
endpoint = getattr(settings, "MINIO_ENDPOINT", None)
|
|
if not endpoint:
|
|
raise ValueError("MINIO_ENDPOINT is not configured")
|
|
|
|
secure = getattr(settings, "MINIO_SECURE", False)
|
|
self._client = Minio(
|
|
endpoint,
|
|
access_key=getattr(settings, "MINIO_ACCESS_KEY", None),
|
|
secret_key=getattr(settings, "MINIO_SECRET_KEY", None),
|
|
secure=secure,
|
|
)
|
|
self._bucket = getattr(settings, "MINIO_BUCKET_CHAT", "chat")
|
|
self._expiry = timedelta(
|
|
seconds=getattr(settings, "MINIO_PRESIGN_EXPIRY_SECONDS", 3600)
|
|
)
|
|
|
|
def get_download_url(self, object_key: str) -> str | None:
|
|
"""
|
|
Sign a time-limited download URL for an object the client already
|
|
uploaded. Generated fresh on every call rather than cached/stored,
|
|
since a stored link would eventually expire while still displayed.
|
|
Returns None on failure so one bad key can't fail an entire message
|
|
list — callers should treat that as "link unavailable", not an error.
|
|
"""
|
|
try:
|
|
return self._client.presigned_get_object(
|
|
self._bucket, object_key, expires=self._expiry
|
|
)
|
|
except Exception:
|
|
return None
|