Skip to content

Commit

Permalink
Merge branch 'master_pbs' into BEN-2875_increase_filer_file_size
Browse files Browse the repository at this point in the history
  • Loading branch information
andreilupuleasa committed Nov 1, 2023
2 parents 03e85a9 + e7b51ec commit 39463e9
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 35 deletions.
2 changes: 1 addition & 1 deletion filer/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# version string following pep-0440
__version__ = '0.9.112' # pragma: nocover
__version__ = '0.9.116' # pragma: nocover

default_app_config = 'filer.apps.FilerConfig'
23 changes: 22 additions & 1 deletion filer/management/commands/fixfoldertrees.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ def add_arguments(self, parser):
default=False,
help='Performs only a check for corrupted folder trees. '
'Prints all the corruptions it finds.')
parser.add_argument('--force-rebuild',
action='store_true',
dest='force_full_rebuild',
default=False,
help='Force a full tree rebuild.')

def handle(self, *args, **options):
checker = TreeChecker()
Expand All @@ -39,4 +44,20 @@ def handle(self, *args, **options):
else:
self.stdout.write("There are no corruptions\n")
else:
checker.rebuild()
if options['force_full_rebuild']:
self.stdout.write("\nPerforming full rebuild...")
checker.manager.rebuild()
else:
self.stdout.write("Checking folder trees before fixing...\n")
checker.check_corruptions()
if checker.full_rebuild:
self.stdout.write("\nPerforming full rebuild...")
checker.manager.rebuild()
elif checker.corrupted_folders:
self.stdout.write("\nPerforming corrupted folders rebuild...")
for folder in checker.get_corrupted_root_nodes():
self.stdout.write(f"\n\tPerforming partial rebuild for folder {folder.name}")
checker.manager.partial_rebuild(folder.tree_id)
else:
self.stdout.write("There are no corruptions, nothing to be done.\n")
self.stdout.write("\nRebuild Done.")
15 changes: 15 additions & 0 deletions filer/migrations/0006_default_caption_text_size.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.db import migrations, models

class Migration(migrations.Migration):

dependencies = [
('filer', '0005_default_alt_text_size'),
]

operations = [
migrations.AlterField(
model_name='Image',
name='default_caption',
field=models.TextField(null=True), # Use TextField to allow unlimited length
),
]
20 changes: 7 additions & 13 deletions filer/models/imagemodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@
except ImportError:
raise ImportError("The Python Imaging Library was not found.")
from datetime import datetime
from django.urls import reverse
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.conf import settings
from django.core.exceptions import ValidationError
from filer import settings as filer_settings
from filer.models.filemodels import File
from filer.utils.filer_easy_thumbnails import FilerThumbnailer
from filer.utils.pil_exif import get_exif_for_file
import os

Expand All @@ -36,25 +34,25 @@ class Image(File):
}
file_type = 'Image'
_icon = "image"
_filename_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.ico']
_filename_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.ico', '.svg', '.webp']

_height = models.IntegerField(null=True, blank=True)
_width = models.IntegerField(null=True, blank=True)

date_taken = models.DateTimeField(_('date taken'), null=True, blank=True,
editable=False)

default_alt_text = models.CharField(
_('default alt text'), max_length=255, blank=True, null=True,
default_alt_text = models.TextField(
_('default alt text'), blank=True, null=True,
help_text=_('Describes the essence of the image for users who have '
'images turned off in their browser, or are visually '
'impaired and using a screen reader; and it is used to '
'identify images to search engines.'))
default_caption = models.CharField(
_('default caption'), max_length=255, blank=True, null=True,
default_caption = models.TextField(
_('default caption'), blank=True, null=True,
help_text=_('Caption text is displayed directly below an image '
'plugin to add context; there is a 140-character limit,'
' including spaces; for images fewer than 200 pixels '
'plugin to add context; there is no character limit;'
'for images fewer than 200 pixels '
'wide, the caption text is only displayed on hover.'))
default_credit = models.CharField(
_('default credit text'), max_length=255, blank=True, null=True,
Expand Down Expand Up @@ -95,10 +93,6 @@ def clean(self):
raise ValidationError(
"Ensure default credit text has at most 30 characters ("
"%s characters found)." % len(self.default_credit))
if int(len(self.default_caption or '')) > 140:
raise ValidationError(
"Ensure default caption text has at most 140 characters ("
"%s characters found)." % len(self.default_caption))
super(Image, self).clean()

def save(self, *args, **kwargs):
Expand Down
33 changes: 15 additions & 18 deletions filer/utils/checktrees.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ class TreeCorruption(Exception):


class TreeChecker(object):

ordering = ['tree_id', 'lft', 'rght']

def __init__(self, folder_manager=None):
Expand All @@ -19,14 +18,13 @@ def __init__(self, folder_manager=None):
else:
self.manager = folder_manager


def find_corruptions(self):
self.check_corruptions()
if (self.full_rebuild or self.corrupted_folders):
raise TreeCorruption()

def _build_diff_msg(self, expected, actual):
attr_idx = {'lft':0, 'rght':1, 'level':2, 'tree_id':3}
attr_idx = {'lft': 0, 'rght': 1, 'level': 2, 'tree_id': 3}
expected, actual = list(expected), list(actual)
diff = []
for attr, idx in list(attr_idx.items()):
Expand All @@ -50,29 +48,31 @@ def get_corrupted_root_nodes(self):
if not self.corruption_check_done:
self.check_corruptions()
corrupted_trees = self.manager.filter(
pk__in=list(self.corrupted_folders.keys())).\
pk__in=list(self.corrupted_folders.keys())). \
values_list('tree_id', flat=True).distinct()
return self.manager.filter(
parent__isnull=True, tree_id__in=corrupted_trees)
parent__isnull=True, deleted_at__isnull=True, tree_id__in=corrupted_trees)

def check_tree(self, pk, lft, tree_id, level=0):
"""
* checks if a certain folder tree is corrupted or not.
* uses the same logic as django-mptt's rebuild tree
* ignores deleted folders, same as django-mptt's rebuild
"""
rght = lft + 1
child_ids = self.manager.filter(parent__pk=pk).\
child_ids = self.manager.filter(parent__pk=pk). \
order_by(*self.ordering).values_list('pk', flat=True)

for child_id in child_ids:
rght = self.check_tree(child_id, rght, tree_id, level + 1)

folder = self.manager.get(pk=pk)
expected = (lft, rght, level, tree_id)
actual = (folder.lft, folder.rght, folder.level, folder.tree_id)
if expected != actual:
self.corrupted_folders.setdefault(
pk, self._build_diff_msg(expected, actual))
if folder.deleted_at is None:
expected = (lft, rght, level, tree_id)
actual = (folder.lft, folder.rght, folder.level, folder.tree_id)
if expected != actual:
self.corrupted_folders.setdefault(
pk, self._build_diff_msg(expected, actual))
return rght + 1

def check_corruptions(self):
Expand All @@ -82,15 +82,15 @@ def check_corruptions(self):
* checks if there are multiple root folders with the
same tree id(fixing this will require a full rebuild)
"""
tree_duplicates = self.manager.filter(parent=None).\
values_list('tree_id').\
tree_duplicates = self.manager.filter(parent=None). \
values_list('tree_id'). \
annotate(count=Count('id')).filter(count__gt=1)
if len(tree_duplicates) > 0:
self.full_rebuild = True
self.corruption_check_done = True
return

pks = self.manager.filter(parent=None).\
pks = self.manager.filter(parent=None). \
order_by(*self.ordering).values_list('pk', flat=True)
idx = 0
for pk in pks:
Expand All @@ -107,7 +107,4 @@ def rebuild(self):
self.manager.rebuild()
elif self.corrupted_folders:
for folder in self.get_corrupted_root_nodes():
# since we use an older version of djang-mptt and method
# partial_rebuild does not exist ...
self.manager._rebuild_helper(
folder.pk, 1, folder.tree_id)
self.manager.partial_rebuild(folder.tree_id)
6 changes: 4 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from setuptools import setup, find_packages
import os

from setuptools import setup, find_packages

try:
from setuptest import test
except ImportError:
Expand All @@ -25,8 +26,9 @@ def read(fname):
author_email='[email protected]',
packages=find_packages(),
install_requires=(
'django-js-asset==2.0.0',
'django>=1.11,<3.0',
'django-mptt>=0.6,<1.0', # the exact version depends on Django
'django-mptt==0.11.1', # the exact version depends on Django
'django_polymorphic>=0.7,<2.2',
'easy-thumbnails>=2,<3.0',
'Unidecode>=0.04,<1.2',
Expand Down

0 comments on commit 39463e9

Please sign in to comment.