From 95da28c79e54d94d893976e123d0352e61135332 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Sat, 31 Mar 2018 11:41:47 +0200 Subject: [PATCH] use sorl-thumbnail (fixes #15857) It replaces GraphicsMagick, we do not use the templatetag as the files are private. --- debian/control | 3 ++- fargo/fargo/admin.py | 10 ++-------- fargo/fargo/models.py | 54 +++++++++++++++++++++++---------------------------- fargo/fargo/views.py | 6 +----- fargo/settings.py | 3 +++ setup.py | 1 + 6 files changed, 33 insertions(+), 44 deletions(-) diff --git a/debian/control b/debian/control index e95090e..48ff339 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,8 @@ Depends: ${misc:Depends}, ${python:Depends}, python-django-filters (>= 1), python-django-filters (<< 2), python-gadjo, - python-magic + python-magic, + python-sorl-thumbnail Recommends: python-django-mellon Description: Fargo Document Box (Python module) diff --git a/fargo/fargo/admin.py b/fargo/fargo/admin.py index d7fdaad..08c8f4a 100644 --- a/fargo/fargo/admin.py +++ b/fargo/fargo/admin.py @@ -14,10 +14,7 @@ class UserDocumentAdmin(admin.ModelAdmin): 'origin__label'] def thumbnail(self, instance): - data_url = instance.document.thumbnail_data_url - if data_url: - return format_html('', data_url) - return '' + return instance.document.thumbnail_img_tag thumbnail.short_description = _('thumbnail') @@ -32,10 +29,7 @@ class DocumentAdmin(admin.ModelAdmin): return u', '.join(unicode(u) for u in qs) def thumbnail(self, instance): - data_url = instance.thumbnail_data_url - if data_url: - return format_html('', data_url) - return '' + return instance.thumbnail_img_tag thumbnail.short_description = _('thumbnail') diff --git a/fargo/fargo/models.py b/fargo/fargo/models.py index 6f0f17b..5a68d38 100644 --- a/fargo/fargo/models.py +++ b/fargo/fargo/models.py @@ -11,10 +11,14 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.text import slugify from django.utils.http import urlquote +from django.utils.html import format_html from django.dispatch import receiver from django.db.models.signals import post_save, post_delete from django.core.files.storage import default_storage +from sorl.thumbnail import get_thumbnail, delete +from sorl.thumbnail.conf import settings as thumbnail_settings + from jsonfield import JSONField from . import utils, managers @@ -182,27 +186,31 @@ class Document(models.Model): self.mime_type = utils.get_mime_type(self.content.file.name) or '' super(Document, self).save(*args, **kwargs) - @property - def thumbnail_path(self): - name = os.path.basename(self.content.name) - return os.path.join('thumbmails', name + '.png') - - @property - def thumbnail_full_path(self): - return default_storage.path(self.thumbnail_path) - @property def thumbnail(self): + if not (self.mime_type.startswith('image/') or self.mime_type == 'application/pdf'): + return None + thumbnail = get_thumbnail(self.content, '200x200') try: - return default_storage.open(self.thumbnail_path) + # check file exists and is readable + default_storage.open(thumbnail.name) + return thumbnail except IOError: - return None + pass + return None @property - def thumbnail_data_url(self): - if self.thumbnail: - return 'data:image/png;base64,%s' % base64.b64encode(self.thumbnail.read()) - return None + def thumbnail_img_tag(self): + thumbnail = self.thumbnail + if not thumbnail: + return '' + + mime_type = 'image/' + thumbnail_settings.THUMBNAIL_FORMAT.lower() + data_url = 'data:%s;base64,%s' % (mime_type, base64.b64encode(thumbnail.read())) + return format_html('', + thumbnail.width, + thumbnail.height, + data_url) class Meta: verbose_name = _('document') @@ -210,23 +218,9 @@ class Document(models.Model): ordering = ('content_hash',) -@receiver(post_save, sender=Document) -def create_thumbnail(sender, instance, created, **kwargs): - if not created: - return - - def do(): - dirpath = os.path.dirname(instance.thumbnail_full_path) - if not os.path.isdir(dirpath): - os.makedirs(dirpath) - subprocess.call(['gm', 'convert', '-geometry', 'x200', - instance.content.file.name, - instance.thumbnail_full_path]) - threading.Thread(target=do).start() - - @receiver(post_delete, sender=Document) def delete_file(sender, instance, **kwargs): if instance.content: if os.path.isfile(instance.content.path): os.remove(instance.content.path) + delete(instance.content) diff --git a/fargo/fargo/views.py b/fargo/fargo/views.py index 03e4f82..904a3c5 100644 --- a/fargo/fargo/views.py +++ b/fargo/fargo/views.py @@ -179,14 +179,10 @@ class Thumbnail(Documents, View): def get(self, request, pk, filename): user_document = get_object_or_404(self.get_queryset(), pk=pk, user=self.request.user) - return self.return_user_document(user_document) - - def return_user_document(self, user_document): thumbnail = user_document.document.thumbnail if not thumbnail: raise Http404 - response = HttpResponse(thumbnail.chunks(), content_type='image/png') - return response + return HttpResponse(thumbnail.chunks(), content_type='image/jpeg') class RemoteDownload(Download): diff --git a/fargo/settings.py b/fargo/settings.py index cdc92ae..fd4fe1a 100644 --- a/fargo/settings.py +++ b/fargo/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = ( 'fargo.fargo', 'rest_framework', 'fargo.oauth2', + 'sorl.thumbnail', ) MIDDLEWARE_CLASSES = ( @@ -226,6 +227,8 @@ LOGGING = { INCLUDE_EDIT_LINK = False +THUMBNAIL_ENGINE = 'sorl.thumbnail.engines.convert_engine.Engine' + FARGO_CODE_LIFETIME = 300 FARGO_ACCESS_TOKEN_LIFETIME = 3600 FARGO_OAUTH2_TEMPFILE_LIFETIME = 86400 diff --git a/setup.py b/setup.py index 345ccb9..e394204 100755 --- a/setup.py +++ b/setup.py @@ -105,6 +105,7 @@ setup( 'djangorestframework>=3.3,<3.4', 'file-magic', 'requests', + 'sorl-thumbnail', ], zip_safe=False, cmdclass={ -- 2.16.3