use sorl-thumbnail (fixes #15857)
It replaces GraphicsMagick, we do not use the templatetag as the files are private.
This commit is contained in:
parent
3a6a89da48
commit
48b598000f
|
@ -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)
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 %}
|
||||
|
|
Loading…
Reference in New Issue