use sorl-thumbnail (fixes #15857)

It replaces GraphicsMagick, we do not use the templatetag as the files
are private.
This commit is contained in:
Benjamin Dauvergne 2018-03-31 11:41:47 +02:00
parent 3a6a89da48
commit 48b598000f
8 changed files with 65 additions and 50 deletions

3
debian/control vendored
View File

@ -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)

View File

@ -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('<img src="{0}"/>', 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('<img src="{0}"/>', data_url)
return ''
return instance.thumbnail_img_tag
thumbnail.short_description = _('thumbnail')

View File

@ -1,4 +1,5 @@
from django.core.management.base import BaseCommand
from django.core.management import call_command
from fargo.fargo.utils import cleanup
@ -8,4 +9,5 @@ class Command(BaseCommand):
def handle(self, *args, **options):
cleanup()
call_command('thumbnail', 'cleanup')

View File

@ -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
@ -83,10 +87,13 @@ class UserDocument(models.Model):
def get_download_url(self):
return reverse('download', kwargs={'pk': self.id, 'filename': self.filename_encoded})
def get_thumbnail_url(self):
if self.document.thumbnail:
return reverse('thumbnail', kwargs={'pk': self.id, 'filename': self.filename_encoded})
return ''
@property
def thumbnail_image(self):
thumbnail = self.document.thumbnail
if not thumbnail:
return ''
src = reverse('thumbnail', kwargs={'pk': self.id, 'filename': self.filename_encoded})
return {'src': src, 'width': thumbnail.width, 'height': thumbnail.height}
@property
def css_classes(self):
@ -182,27 +189,48 @@ 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):
try:
return default_storage.open(self.thumbnail_path)
except IOError:
if not (self.mime_type.startswith('image/') or self.mime_type == 'application/pdf'):
return None
try:
thumbnail = get_thumbnail(self.content, '200x200')
except: # sorl-thumbnail can crash in unexpected ways
return None
try:
# check file exists and is readable
default_storage.open(thumbnail.name)
return thumbnail
except IOError:
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
thumbnail = self.thumbnail
if not thumbnail:
return ''
mime_type = 'image/' + thumbnail_settings.THUMBNAIL_FORMAT.lower()
return 'data:%s;base64,%s' % (mime_type, base64.b64encode(thumbnail.read()))
@property
def thumbnail_img_tag(self):
thumbnail = self.thumbnail
if not thumbnail:
return ''
return format_html('<img width="{}" height="{}" src="{}"/>',
thumbnail.width,
thumbnail.height,
self.thumbnail_data_url)
@property
def thumbnail_image(self):
thumbnail = self.thumbnail
if not thumbnail:
return ''
return {'src': self.thumbnail_data_url, 'width': thumbnail.width, 'height': thumbnail.height}
class Meta:
verbose_name = _('document')
@ -210,23 +238,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)

View File

@ -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):

View File

@ -41,6 +41,7 @@ INSTALLED_APPS = (
'fargo.fargo',
'rest_framework',
'fargo.oauth2',
'sorl.thumbnail',
)
MIDDLEWARE_CLASSES = (
@ -232,6 +233,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

View File

@ -31,8 +31,12 @@
{% for column, cell in row.items %}
<td {{ column.attrs.td.as_html }}>{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}</td>
{% endfor %}
{% with url=row.record.get_thumbnail_url %}
<td class="thumbnail" rowspan={{ row.record.description|yesno:"2,1" }}>{% if url %}<img src="{{ url }}"/>{% endif %}</td>
{% with thumbnail=row.record.thumbnail_image %}
<td class="thumbnail" rowspan={{ row.record.description|yesno:"2,1" }}>
{% if thumbnail %}
<img src="{{ thumbnail.src }}" height="{{ thumbnail.height }}" width="{{ thumbnail.width }}"/>
{% endif %}
</td>
{% endwith %}
<td class="action-column" rowspan={{ row.record.description|yesno:"2,1" }}>
{% block action-column %}

View File

@ -105,6 +105,7 @@ setup(
'djangorestframework>=3.3,<3.4',
'file-magic',
'requests',
'sorl-thumbnail',
],
zip_safe=False,
cmdclass={