Source code for utils.media.views
"""Utility views"""
import os
from datetime import timedelta
from PIL import Image, ImageOps
from django.conf import settings
from django.core import signing
from django.core.exceptions import PermissionDenied
from django.core.signing import BadSignature
from django.http import Http404
from django.shortcuts import redirect
from django_sendfile import sendfile
def _get_signature_info(request):
if "sig" in request.GET:
signature = request.GET.get("sig")
try:
return signing.loads(signature, max_age=timedelta(hours=3))
except BadSignature:
pass
raise PermissionDenied
[docs]def generate_thumbnail(request, request_path):
"""
Generate thumbnail and redirect user to new location
The thumbnails are generated with this route. Because the
thumbnails will be generated in parallel, it will not block
page load when many thumbnails need to be generated.
After it is done, the user is redirected to the new location
of the thumbnail.
:param HttpRequest request: the request
:return: HTTP Redirect to thumbnail
"""
# Get image information from signature
# raises PermissionDenied if bad signature
query = ""
sig_info = _get_signature_info(request)
if not sig_info["thumb_path"].endswith(request_path):
# 404 if the file does not exist
raise Http404("Media not found.")
if sig_info["visibility"] == "public":
full_original_path = os.path.join(
settings.MEDIA_ROOT, "public", sig_info["path"]
)
full_thumb_path = os.path.join(
settings.MEDIA_ROOT, "public", sig_info["thumb_path"]
)
else:
full_original_path = os.path.join(settings.MEDIA_ROOT, sig_info["path"])
full_thumb_path = os.path.join(settings.MEDIA_ROOT, sig_info["thumb_path"])
if not os.path.exists(full_original_path):
raise Http404
# Check if directory for thumbnail exists, if not create it
os.makedirs(os.path.dirname(full_thumb_path), exist_ok=True)
# Skip generating the thumbnail if it exists
if not os.path.isfile(full_thumb_path) or os.path.getmtime(
full_original_path
) > os.path.getmtime(full_thumb_path):
# Create a thumbnail from the original_path, saved to thumb_path
image = Image.open(full_original_path)
size = tuple(int(dim) for dim in sig_info["size"].split("x"))
if not sig_info["fit"]:
ratio = min([a / b for a, b in zip(size, image.size)])
size = tuple(int(ratio * x) for x in image.size)
if size[0] == image.size[0] and size[1] == image.size[1]:
image.save(full_thumb_path)
else:
thumb = ImageOps.fit(image, size, Image.ANTIALIAS)
thumb.save(full_thumb_path)
if sig_info["visibility"] == "private":
query = f'?sig={request.GET["sig"]}'
# Redirect to the serving url of the image
# for public images this goes via a static file server (i.e. nginx)
# for private images this is a call to private_media
return redirect(
f"{settings.MEDIA_URL}"
f'{sig_info["visibility"]}/thumbnails/'
f'{sig_info["size"]}_{sig_info["fit"]}/'
f'{sig_info["path"]}{query}',
permanent=True,
)