loko/streetup/common/private_files/views.py
2026-07-22 14:48:40 +02:00

68 lines
2.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# common/private_files/views.py
import os
from django.apps import apps
from django.http import FileResponse, Http404, HttpResponseBadRequest
from django.contrib.auth.decorators import login_required
from django.core import signing
from django.core.signing import BadSignature, SignatureExpired
from django.utils.encoding import smart_str
from django.utils.translation import gettext as _
from django.conf import settings
from .registry import get_guard
_TOKEN_MAX_AGE = getattr(settings, "PRIVATE_FILES_TOKEN_MAX_AGE", 14400)
@login_required
def private_file_download(request):
"""
Accès générique: app=<app>&model=<Model>&pk=<id>&field=<field>&token=<signed>
"""
app_label = request.GET.get("app")
model_name = request.GET.get("model")
pk = request.GET.get("pk")
field_name = request.GET.get("field")
token = request.GET.get("token")
if not all([app_label, model_name, pk, field_name]):
return HttpResponseBadRequest("Missing params")
# Vérifie le token signé (facultatif si tu ne veux pas signer)
if token:
try:
signing.loads(token, salt="private-files", max_age=_TOKEN_MAX_AGE)
except (BadSignature, SignatureExpired):
raise Http404(_("Lien expiré ou invalide"))
# Récupère le modèle et l’objet
try:
model = apps.get_model(app_label, model_name)
except LookupError:
raise Http404(_("Modèle inconnu"))
obj = model._default_manager.select_related().filter(pk=pk).first()
if not obj:
raise Http404(_("Objet introuvable"))
# Récupère le guard
guard = get_guard(app_label, model_name, field_name)
if guard is None:
# Par défaut, refuse si pas de guard enregistré (sécurité par défaut)
raise Http404(_("Fichier non exposé"))
# Vérif d’accès
if not guard(obj, request.user):
from django.core.exceptions import PermissionDenied
raise PermissionDenied(_("Accès refusé"))
# Ouvre le FileField
f = getattr(obj, field_name, None)
if not f or not getattr(f, "storage", None) or not f.name or not f.storage.exists(f.name):
raise Http404(_("Fichier introuvable"))
resp = FileResponse(f.open("rb"))
resp["Content-Disposition"] = f'inline; filename="{smart_str(os.path.basename(f.name))}"'
resp['X-Frame-Options'] = 'ALLOWALL' # Permet l’affichage dans un iframe
return resp