diff --git a/shared/media_archive/admin.py b/shared/media_archive/admin.py index e4b8204..5d1f345 100644 --- a/shared/media_archive/admin.py +++ b/shared/media_archive/admin.py @@ -2,12 +2,11 @@ from django import VERSION as DJANGO_VERSION from django.contrib import admin from django.contrib.admin.filters import ChoicesFieldListFilter, FieldListFilter from django.db.models import Count +from django.template.loader import render_to_string from django.utils.encoding import smart_text -from django.utils.html import format_html, mark_safe +from django.utils.html import format_html, mark_safe, strip_tags from django.utils.translation import gettext_lazy as _ -from imagekit.admin import AdminThumbnail - from .conf import USE_TRANSLATABLE_FIELDS from .forms import MediaCategoryAdminForm from . import admin_actions, mixins, models @@ -22,6 +21,38 @@ else: return fieldname +class AdminThumbnail: + # Taken from ImageKit and adapted for django-imagefield + image_field = 'file' + format_name = 'admin_thumbnail' + template = 'imagekit/admin/selectable_thumbnail.html' + short_description = _('Thumbnail') + allow_tags = True + + def __init__(self, image_field=None, format_name=None, template=None): + if image_field: + self.image_field = image_field + if format_name: + self.format_name = format_name + if template: + self.template = template + + def __call__(self, obj): + if callable(self.image_field): + thumbnail = self.image_field(obj) + else: + thumbnail = getattr(getattr(obj, self.image_field), self.format_name) + + original_image = getattr(thumbnail, 'source', None) or thumbnail + template = self.template or 'imagekit/admin/thumbnail.html' + + return render_to_string(template, { + 'model': obj, + 'thumbnail': thumbnail, + 'original_image': original_image, + }) + + class CategoryFieldListFilter(ChoicesFieldListFilter): """ Customization of ChoicesFilterSpec which sorts in the user-expected format. @@ -121,36 +152,42 @@ class MediaAdminBase(admin_actions.MediaBaseActionsMixin, mixins.DropUploadAdmin fieldsets = ( (None, { 'fields': [ - 'is_public', - ('file', 'image_ppoi'), + *i18n_fields('caption'), *i18n_fields('name'), - 'role', + ('file', 'image_ppoi'), + ( + 'is_public', + 'role', + ), ]}), - (_("Texte"), { + (_("Bildnachweise"), { 'fields': [ - *i18n_fields('caption'), *i18n_fields('credits'), *i18n_fields('copyright'), ]}), - (_("Ordnung"), { + (_("Verwaltung"), { + 'classes': ['collapse'], 'fields': [ 'categories', ]}), ) filter_horizontal = ['categories'] - admin_thumbnail = AdminThumbnail( - image_field='thumbnail', - template='imagekit/admin/selectable_thumbnail.html') - admin_thumbnail.short_description = _("Foto") + admin_thumbnail = AdminThumbnail() # TODO class Media: add switch_languages script def get_name_display(self, obj): + caption = strip_tags(obj.caption) + if obj.name and obj.name != caption: + caption = mark_safe(f"
{caption}") + else: + caption = "" return format_html( - "{categories}
{caption}", + "{categories}
{name}{caption}", categories=", ".join([str(p) for p in obj.categories.all()]), - caption=str(obj), + name=str(obj), + caption=caption, ) get_name_display.short_description = _("Name") get_name_display.admin_order_field = lang_suffix(fieldname='name') @@ -189,9 +226,7 @@ class ImageGalleryRelInline(admin.TabularInline): verbose_name = _("Bild") verbose_name_plural = _("Bilder") - admin_thumbnail = AdminThumbnail( - image_field=image_thumbnail_image, - template='imagekit/admin/selectable_thumbnail.html') + admin_thumbnail = AdminThumbnail() admin_thumbnail.short_description = _("Foto") diff --git a/shared/media_archive/conf.py b/shared/media_archive/conf.py index 37353ae..0598672 100644 --- a/shared/media_archive/conf.py +++ b/shared/media_archive/conf.py @@ -1,5 +1,6 @@ from django.conf import settings + USE_TRANSLATABLE_FIELDS = ( getattr(settings, 'CONTENT_PLUGINS_USE_TRANSLATABLE_FIELDS', False) or getattr(settings, 'USE_TRANSLATABLE_FIELDS', False) diff --git a/shared/media_archive/models.py b/shared/media_archive/models.py index 07ceaa6..e24a0fc 100644 --- a/shared/media_archive/models.py +++ b/shared/media_archive/models.py @@ -1,14 +1,15 @@ import logging import posixpath import re +from functools import partial from django.db import models from django.utils.html import strip_tags +from django.utils.text import Truncator from django.utils.translation import ugettext_lazy as _ from imagefield.fields import ImageField, PPOIField -from imagekit.models import ImageSpecField -from imagekit.processors import Adjust, Thumbnail, ResizeToFit, ResizeToFill +from shared.utils.text import html_to_text, sanitized_html from shared.utils.models.slugs import DowngradingSlugField, slugify from .conf import UPLOAD_TO, USE_TRANSLATABLE_FIELDS @@ -34,7 +35,7 @@ class MediaCategoryManager(models.Manager): class MediaCategory(models.Model): - name = models.CharField(_("name"), max_length=200) + name = models.CharField(_("name"), blank=True, max_length=200) parent = models.ForeignKey( 'self', blank=True, null=True, on_delete=models.CASCADE, @@ -78,7 +79,8 @@ class Gallery(models.Model): help_text=_("Publicly visible name.")) slug = models.SlugField(_("Slug"), null=True, blank=True) credits = TranslatableCharField(_("Credits"), null=True, blank=True, max_length=500) - caption = TranslatableCleansedRichTextField(_("Caption"), null=True, blank=True) + caption = TranslatableCleansedRichTextField(_("Caption"), + null=True, blank=True, config_name='caption') is_public = models.BooleanField(_("Active"), default=False) order_index = models.PositiveIntegerField(_("Order Index"), default=0) # background_color = models.ForeignKey('site_pages.Color', on_delete=models.PROTECT, @@ -165,8 +167,8 @@ class MediaRole(models.Model): name = TranslatableCharField(_("name"), max_length=200) class Meta: - verbose_name = _("Bild-Typ") - verbose_name_plural = _("Bild-Typen") + verbose_name = _("Art") + verbose_name_plural = _("Arten") ordering = i18n_fields('name') def __str__(self): @@ -194,7 +196,9 @@ class MediaBase(DeleteOldFileMixin, models.Model): verbose_name=_("Typ"), null=True, blank=True) name = TranslatableCharField(_("Name"), max_length=200, null=True, blank=True) - caption = TranslatableCleansedRichTextField(_("Bildunterschrift"), blank=True) + caption = TranslatableCleansedRichTextField(_("Bildunterschrift"), blank=True, + config_name='caption', + cleanse=partial(sanitized_html, config_name='caption')) credits = TranslatableCharField(_("Credits"), max_length=500, null=True, blank=True) copyright = TranslatableCharField(_('Rechteinhaber/in'), max_length=2000, blank=True) @@ -211,6 +215,11 @@ class MediaBase(DeleteOldFileMixin, models.Model): return self.name or strip_tags(self.caption) or posixpath.basename(self.file.name) def save(self, *args, **kwargs): + if not self.name: + if self.caption: + self.name = Truncator(html_to_text(self.caption)).chars(200, truncate=' …') + else: + self.name = Truncator(posixpath.basename(self.file.name)).chars(200, truncate=' …') if self.file: try: self.file_size = self.file.size @@ -221,14 +230,6 @@ class MediaBase(DeleteOldFileMixin, models.Model): class Image(MediaBase): - image_width = models.PositiveIntegerField( - _("image width"), blank=True, null=True, editable=False - ) - image_height = models.PositiveIntegerField( - _("image height"), blank=True, null=True, editable=False - ) - image_ppoi = PPOIField(_("primary point of interest")) - # file = models.ImageField(_("Datei")) file = ImageField( _("image"), max_length=200, @@ -238,43 +239,11 @@ class Image(MediaBase): ppoi_field="image_ppoi", blank=True, ) - - logo_image = ImageSpecField(source='file', - processors=[ResizeToFit(150, 150)]) - - thumbnail = ImageSpecField(source='file', - processors=[Adjust(contrast=1.2, sharpness=1.1), - Thumbnail(100, 50)], - format='JPEG', options={'quality': 90}) - - square_image = ImageSpecField(source='file', - processors=[ResizeToFill(800, 800)], - format='JPEG', options={'quality': 90}) - - small_article_image = ImageSpecField(source='file', - processors=[ResizeToFit(400, 400)], - format='JPEG', options={'quality': 90}) - - article_image = ImageSpecField(source='file', - processors=[ResizeToFit(800, 800)], - format='JPEG', options={'quality': 90}) - - gallery_image = ImageSpecField(source='file', - processors=[ResizeToFit(1200, 1200)], - format='JPEG', options={'quality': 90}) - - gallery_image_thumbnail = ImageSpecField(source='file', - processors=[ - Adjust(contrast=1.2, sharpness=1.1), - # ResizeToFit(180, 120) - ResizeToFit(220, 155) - ], - format='JPEG', options={'quality': 90}) - - lightbox_image = ImageSpecField(source='file', - processors=[ResizeToFit(1600, 1600)], - format='JPEG', options={'quality': 90}) - highres_image = lightbox_image + image_width = models.PositiveIntegerField( + _("image width"), blank=True, null=True, editable=False) + image_height = models.PositiveIntegerField( + _("image height"), blank=True, null=True, editable=False) + image_ppoi = PPOIField(_("primary point of interest")) type = 'image' diff --git a/shared/media_archive/templates/imagekit/admin/selectable_thumbnail.html b/shared/media_archive/templates/imagekit/admin/selectable_thumbnail.html index 6d88740..8effd7b 100644 --- a/shared/media_archive/templates/imagekit/admin/selectable_thumbnail.html +++ b/shared/media_archive/templates/imagekit/admin/selectable_thumbnail.html @@ -1,3 +1 @@ -{% if thumbnail %} - -{% endif %} +{% if thumbnail %}{% endif %}