diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a81258e7e..bf6464912 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11' ] + python-version: ['3.8', '3.9', '3.10', '3.11'] requirements-file: [ django-3.2.txt, django-4.0.txt, @@ -16,6 +16,7 @@ jobs: django-4.2.txt, django-5.0.txt, ] + custom-image-model: [false, true] exclude: - requirements-file: django-5.0.txt python-version: 3.8 @@ -41,8 +42,10 @@ jobs: python -m pip install --upgrade pip pip install -r tests/requirements/${{ matrix.requirements-file }} python setup.py install + - name: Enable the custom image model + run: echo "CUSTOM_IMAGE=custom_image.Image" >> $GITHUB_ENV + if: ${{ matrix.custom-image-model }} - name: Run coverage run: coverage run setup.py test - - name: Upload Coverage to Codecov uses: codecov/codecov-action@v1 diff --git a/filer/admin/fileadmin.py b/filer/admin/fileadmin.py index afe2edbfb..7efa03ada 100644 --- a/filer/admin/fileadmin.py +++ b/filer/admin/fileadmin.py @@ -1,6 +1,7 @@ import mimetypes from django import forms +from django.contrib.admin.templatetags.admin_urls import admin_urlname from django.contrib.admin.utils import unquote from django.contrib.staticfiles.storage import staticfiles_storage from django.http import Http404, HttpResponse, HttpResponseRedirect @@ -19,10 +20,14 @@ from .. import settings from ..models import BaseImage, File from ..settings import DEFERRED_THUMBNAIL_SIZES +from ..utils.loader import load_model from .permissions import PrimitivePermissionAwareModelAdmin from .tools import AdminContext, admin_url_params_encoded, popup_status +Image = load_model(settings.FILER_IMAGE_MODEL) + + class FileAdminChangeFrom(forms.ModelForm): class Meta: model = File @@ -123,12 +128,18 @@ def response_change(self, request, obj): def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): - info = self.model._meta.app_label, self.model._meta.model_name - extra_context = {'show_delete': True, - 'history_url': 'admin:%s_%s_history' % info, - 'is_popup': popup_status(request), - 'filer_admin_context': AdminContext(request)} - context.update(extra_context) + context.update({ + 'show_delete': True, + 'history_url': admin_urlname(self.opts, 'history'), + 'expand_image_url': None, + 'is_popup': popup_status(request), + 'filer_admin_context': AdminContext(request), + }) + if obj and obj.mime_maintype == 'image' and obj.file.exists(): + if 'svg' in obj.mime_type: + context['expand_image_url'] = reverse(admin_urlname(Image._meta, 'expand'), args=(obj.pk,)) + else: + context['expand_image_url'] = obj.file.url return super().render_change_form( request=request, context=context, add=add, change=change, form_url=form_url, obj=obj) diff --git a/filer/admin/imageadmin.py b/filer/admin/imageadmin.py index 0104a32cd..8182a190d 100644 --- a/filer/admin/imageadmin.py +++ b/filer/admin/imageadmin.py @@ -91,7 +91,7 @@ def get_urls(self): return super().get_urls() + [ path("expand/", self.admin_site.admin_view(self.expand_view), - name=f"filer_{self.model._meta.model_name}_expand_view") + name=f"{self.opts.app_label}_{self.opts.model_name}_expand") ] def expand_view(self, request, file_id): diff --git a/filer/management/commands/filer_check.py b/filer/management/commands/filer_check.py index 3eb77d12b..efe39027a 100644 --- a/filer/management/commands/filer_check.py +++ b/filer/management/commands/filer_check.py @@ -7,6 +7,7 @@ from PIL import UnidentifiedImageError from filer import settings as filer_settings +from filer.utils.loader import load_model class Command(BaseCommand): @@ -130,10 +131,9 @@ def image_dimensions(self, options): import easy_thumbnails from easy_thumbnails.VIL import Image as VILImage - from filer.models.imagemodels import Image from filer.utils.compatibility import PILImage - no_dimensions = Image.objects.filter( + no_dimensions = load_model(filer_settings.FILER_IMAGE_MODEL).objects.filter( Q(_width=0) | Q(_width__isnull=True) ) self.stdout.write(f"trying to set dimensions on {no_dimensions.count()} files") diff --git a/filer/templates/admin/filer/tools/detail_info.html b/filer/templates/admin/filer/tools/detail_info.html index a111bb487..1e18f34ea 100644 --- a/filer/templates/admin/filer/tools/detail_info.html +++ b/filer/templates/admin/filer/tools/detail_info.html @@ -10,9 +10,8 @@   {% translate "Download" %} - {% if original.mime_maintype == 'image' %} - + {% if expand_image_url %} + {% translate "Expand" %}  diff --git a/tests/requirements/base.txt b/tests/requirements/base.txt index e48dff237..6edaa2909 100644 --- a/tests/requirements/base.txt +++ b/tests/requirements/base.txt @@ -7,3 +7,4 @@ django-app-helper>=3.3.1 coverage isort flake8 +packaging diff --git a/tests/test_admin.py b/tests/test_admin.py index ce5a23ad1..4aacad7c1 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -6,6 +6,7 @@ from django.conf import settings from django.contrib import admin from django.contrib.admin import helpers +from django.contrib.admin.templatetags.admin_urls import admin_urlname from django.contrib.auth import get_user_model from django.contrib.auth.models import Permission from django.contrib.messages import ERROR, get_messages @@ -327,7 +328,7 @@ def test_detail_view_missing_file(self): image._height = 200 image.save() - url = reverse(f'admin:{image.__class__._meta.app_label}_image_change', kwargs={ + url = reverse(admin_urlname(Image._meta, 'change'), kwargs={ 'object_id': image.pk, }) @@ -338,8 +339,36 @@ def test_detail_view_missing_file(self): self.assertContains(response, 'height="210"') self.assertContains(response, 'alt="File is missing"') + def test_image_expand_link_in_change_view(self): + files = [ + # Files can use the same contents for this test - it's the mime type that counts + File.objects.create(owner=self.superuser, original_filename='some-file.txt', file=self.file_object.file), + Image.objects.create(owner=self.superuser, original_filename='some-image.jpg'), # missing file + Image.objects.create(owner=self.superuser, original_filename='some-image.jpg', file=self.file_object.file), + Image.objects.create(owner=self.superuser, original_filename='some-image.svg', file=self.file_object.file), + ] + test_set = [ + (files[0], 'text/plain', None), + (files[1], 'image/jpeg', None), + (files[2], 'image/jpeg', files[2].file.url), + (files[3], 'image/svg+xml', reverse(admin_urlname(Image._meta, 'expand'), args=(files[3].pk,))), + ] + for file, mime_type, expected_url in test_set: + file.mime_type = mime_type + file.save() + models = [File] + if isinstance(file, Image): + models.append(Image) + for model in models: + response = self.client.get(reverse(admin_urlname(model._meta, 'change'), + kwargs={'object_id': file.pk})) + if expected_url: + self.assertContains(response, f'href="{expected_url}"') + else: + self.assertNotContains(response, 'filer-icon-expand') + def test_image_expand_view(self): - url = reverse("admin:filer_image_expand_view", kwargs={ + url = reverse(admin_urlname(Image._meta, 'expand'), kwargs={ 'file_id': self.file_object.pk }) original_url = self.file_object.url diff --git a/tests/test_filer_check.py b/tests/test_filer_check.py index f18bd389c..98592df1d 100644 --- a/tests/test_filer_check.py +++ b/tests/test_filer_check.py @@ -9,10 +9,14 @@ from filer import settings as filer_settings from filer.models.filemodels import File -from filer.models.imagemodels import Image +from filer.settings import FILER_IMAGE_MODEL +from filer.utils.loader import load_model from tests.helpers import create_image +Image = load_model(FILER_IMAGE_MODEL) + + class FilerCheckTestCase(TestCase): svg_file_string = """