Skip to content

Commit

Permalink
Merge remote-tracking branch 'dCA/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
jrief committed Nov 22, 2023
2 parents 05fe956 + b0f39ab commit d10c7e9
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 27 deletions.
18 changes: 10 additions & 8 deletions .github/workflows/publish-to-live-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ jobs:
build-n-publish:
name: Build and publish Python 🐍 distributions 📦 to pypi
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/django-filer
permissions:
id-token: write
steps:
- uses: actions/checkout@master
- name: Set up Python 3.9
uses: actions/setup-python@v1
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.9
python-version: '3.12'

- name: Install pypa/build
run: >-
Expand All @@ -33,7 +38,4 @@ jobs:
- name: Publish distribution 📦 to PyPI
if: startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
uses: pypa/gh-action-pypi-publish@release/v1
21 changes: 12 additions & 9 deletions .github/workflows/publish-to-test-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ jobs:
build-n-publish:
name: Build and publish Python 🐍 distributions 📦 to TestPyPI
runs-on: ubuntu-latest
environment:
name: test
url: https://test.pypi.org/p/django-filer
permissions:
id-token: write
steps:
- uses: actions/checkout@master
- name: Set up Python 3.9
uses: actions/setup-python@v1
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.9
python-version: '3.12'

- name: Install pypa/build
run: >-
Expand All @@ -32,9 +37,7 @@ jobs:
.
- name: Publish distribution 📦 to Test PyPI
uses: pypa/gh-action-pypi-publish@master
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
skip_existing: true
repository-url: https://test.pypi.org/legacy/
skip-existing: true
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ repos:
- id: yesqa

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: check-merge-conflict
- id: mixed-line-ending
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
CHANGELOG
=========

3.1.1 (2023-11-18)
==================

* fix: Added compatibility code in aldryn_config go support setting THUMBNAIL_DEFAULT_STORAGE in django 4.2
* fix: address failing gulp ci jobs
* feat: Image dimensions update management command
* ci: pre-commit autoupdate

3.1.0 (2023-10-01)
==================

Expand Down
7 changes: 6 additions & 1 deletion aldryn_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ def to_settings(self, data, settings):
# If the DEFAULT_FILE_STORAGE has been set to a value known by
# aldryn-django, then use that as THUMBNAIL_DEFAULT_STORAGE as well.
for storage_backend in storage.SCHEMES.values():
if storage_backend == settings['DEFAULT_FILE_STORAGE']:
# Process before django 4.2
if storage_backend == settings.get('DEFAULT_FILE_STORAGE', None):
settings['THUMBNAIL_DEFAULT_STORAGE'] = storage_backend
break
# Process django 4.2 and after
if storage_backend == settings.get('STORAGES', {}).get('default', {}).get('BACKEND', None):
settings['THUMBNAIL_DEFAULT_STORAGE'] = storage_backend
break
return settings
2 changes: 1 addition & 1 deletion filer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
8. Publish the release and it will automatically release to pypi
"""

__version__ = '3.1.0'
__version__ = '3.1.1'
49 changes: 49 additions & 0 deletions filer/management/commands/filer_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from django.core.management.base import BaseCommand
from django.utils.module_loading import import_string

from PIL import UnidentifiedImageError

from filer import settings as filer_settings


Expand Down Expand Up @@ -41,6 +43,13 @@ def add_arguments(self, parser):
default=False,
help="Delete references in database if files are missing in media folder.",
)
parser.add_argument(
'--image-dimensions',
action='store_true',
dest='image_dimensions',
default=False,
help="Look for images without dimensions set, set them accordingly.",
)
parser.add_argument(
'--noinput',
'--no-input',
Expand Down Expand Up @@ -72,6 +81,8 @@ def handle(self, *args, **options):
self.stdout.write("Aborted: Delete orphaned files from storage.")
return
self.verify_storages(options)
if options['image_dimensions']:
self.image_dimensions(options)

def verify_references(self, options):
from filer.models.filemodels import File
Expand Down Expand Up @@ -112,3 +123,41 @@ def walk(prefix):
filer_public = filer_settings.FILER_STORAGES['public']['main']
storage = import_string(filer_public['ENGINE'])()
walk(filer_public['UPLOAD_TO_PREFIX'])

def image_dimensions(self, options):
from django.db.models import Q

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(
Q(_width=0) | Q(_width__isnull=True)
)
self.stdout.write(f"trying to set dimensions on {no_dimensions.count()} files")
for image in no_dimensions:
if image.file_ptr:
file_holder = image.file_ptr
else:
file_holder = image
try:
imgfile = file_holder.file
imgfile.seek(0)
except (FileNotFoundError):
pass
else:
if image.file.name.lower().endswith('.svg'):
with VILImage.load(imgfile) as vil_image:
# invalid svg doesnt throw errors
image._width, image._height = vil_image.size
else:
try:
with PILImage.open(imgfile) as pil_image:
image._width, image._height = pil_image.size
image._transparent = easy_thumbnails.utils.is_transparent(pil_image)
except UnidentifiedImageError:
continue
image.save()
return
12 changes: 7 additions & 5 deletions filer/static/filer/js/addons/dropzone.init.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ djQuery(function ($) {

// Handle initialization of the dropzone on dynamic formsets (i.e. Django admin inlines)
$(document).on('formset:added', function (ev, row) {
if(ev.detail && ev.detail.formsetName) {
var dropzones, rowIdx, row_;
if (ev.detail && ev.detail.formsetName) {
/*
Django 4.1 changed the event type being fired when adding
a new formset from a jQuery to a vanilla JavaScript event.
Expand All @@ -172,16 +173,17 @@ djQuery(function ($) {
In this case we find the newly added row and initialize the
dropzone on any dropzoneSelector on that row.
*/
let rowIdx = parseInt(

rowIdx = parseInt(
document.getElementById(
'id_' + event.detail.formsetName + '-TOTAL_FORMS'
).value, 10
) - 1;
let row_ = document.getElementById(event.detail.formsetName + '-' + rowIdx);
var dropzones = $(row_).find(dropzoneSelector)
row_ = document.getElementById(event.detail.formsetName + '-' + rowIdx);
dropzones = $(row_).find(dropzoneSelector);

} else {
var dropzones = $(row).find(dropzoneSelector);
dropzones = $(row).find(dropzoneSelector);
}

dropzones.each(createDropzone);
Expand Down
2 changes: 1 addition & 1 deletion tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ def test_image_expand_view(self):

self.assertContains(
response,
f"""<img id="img" src="{ original_url }" onclick="this.classList.toggle('zoom')"/>"""
f"""<img id="img" src="{original_url}" onclick="this.classList.toggle('zoom')"/>"""
)


Expand Down
91 changes: 90 additions & 1 deletion tests/test_filer_check.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
import shutil
from io import StringIO
from io import BytesIO, StringIO

from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.management import call_command
Expand All @@ -9,10 +9,21 @@

from filer import settings as filer_settings
from filer.models.filemodels import File
from filer.models.imagemodels import Image
from tests.helpers import create_image


class FilerCheckTestCase(TestCase):

svg_file_string = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "
http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" width="50" height="50" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900"
stroke="#004400"/>
{}
</svg>"""

def setUp(self):
# ensure that filer_public directory is empty from previous tests
storage = import_string(filer_settings.FILER_STORAGES['public']['main']['ENGINE'])()
Expand Down Expand Up @@ -67,3 +78,81 @@ def test_delete_orphans(self):

call_command('filer_check', delete_orphans=True, interactive=False, verbosity=0)
self.assertFalse(os.path.exists(orphan_file))

def test_image_dimensions_corrupted_file(self):
original_filename = 'testimage.jpg'
file_obj = SimpleUploadedFile(
name=original_filename,
# corrupted!
content=create_image().tobytes(),
content_type='image/jpeg')
self.filer_image = Image.objects.create(
file=file_obj,
original_filename=original_filename)

self.filer_image._width = 0
self.filer_image.save()
call_command('filer_check', image_dimensions=True)

def test_image_dimensions_file_not_found(self):
self.filer_image = Image.objects.create(
file="123.jpg",
original_filename="123.jpg")
call_command('filer_check', image_dimensions=True)
self.filer_image.refresh_from_db()

def test_image_dimensions(self):

original_filename = 'testimage.jpg'
with BytesIO() as jpg:
create_image().save(jpg, format='JPEG')
jpg.seek(0)
file_obj = SimpleUploadedFile(
name=original_filename,
content=jpg.read(),
content_type='image/jpeg')
self.filer_image = Image.objects.create(
file=file_obj,
original_filename=original_filename)

self.filer_image._width = 0
self.filer_image.save()

call_command('filer_check', image_dimensions=True)
self.filer_image.refresh_from_db()
self.assertGreater(self.filer_image._width, 0)

def test_image_dimensions_invalid_svg(self):

original_filename = 'test.svg'
svg_file = bytes("<asdva>" + self.svg_file_string, "utf-8")
file_obj = SimpleUploadedFile(
name=original_filename,
content=svg_file,
content_type='image/svg+xml')
self.filer_image = Image.objects.create(
file=file_obj,
original_filename=original_filename)

self.filer_image._width = 0
self.filer_image.save()
call_command('filer_check', image_dimensions=True)

def test_image_dimensions_svg(self):

original_filename = 'test.svg'
svg_file = bytes(self.svg_file_string, "utf-8")
file_obj = SimpleUploadedFile(
name=original_filename,
content=svg_file,
content_type='image/svg+xml')
self.filer_image = Image.objects.create(
file=file_obj,
original_filename=original_filename)

self.filer_image._width = 0
self.filer_image.save()

call_command('filer_check', image_dimensions=True)
self.filer_image.refresh_from_db()
self.assertGreater(self.filer_image._width, 0)

0 comments on commit d10c7e9

Please sign in to comment.