diff --git a/HISTORY.rst b/HISTORY.rst index e5b851be22..e0b47b086a 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -8,6 +8,11 @@ directories. * Fixed duplicated FUSE directory removal. * Add link and view to show the parsed content of each document page. +* Add a modelform for adding and editing transformation and perform + YAML validation of arguments. +* Add stricted error checking to the crop transformation. +* Update compressed files class module to work with Python 3. + 3.1.4 (2018-10-4) ================= diff --git a/mayan/apps/converter/forms.py b/mayan/apps/converter/forms.py new file mode 100644 index 0000000000..41dd34b4f4 --- /dev/null +++ b/mayan/apps/converter/forms.py @@ -0,0 +1,25 @@ +from __future__ import unicode_literals + +import yaml + +from django import forms +from django.core.exceptions import ValidationError +from django.utils.translation import ugettext_lazy as _ + +from .models import Transformation + + +class TransformationForm(forms.ModelForm): + class Meta: + fields = ('name', 'arguments', 'order') + model = Transformation + + def clean(self): + try: + yaml.safe_load(self.cleaned_data['arguments']) + except yaml.YAMLError: + raise ValidationError( + _( + '"%s" not a valid entry.' + ) % self.cleaned_data['arguments'] + ) diff --git a/mayan/apps/converter/managers.py b/mayan/apps/converter/managers.py index 6050a56cd9..484fe45b24 100644 --- a/mayan/apps/converter/managers.py +++ b/mayan/apps/converter/managers.py @@ -18,7 +18,7 @@ class TransformationManager(models.Manager): self.create( content_type=content_type, object_id=obj.pk, - name=transformation.name, arguments=arguments + name=transformation.name, arguments=yaml.safe_dump(arguments) ) def copy(self, source, targets): diff --git a/mayan/apps/converter/transformations.py b/mayan/apps/converter/transformations.py index deca867239..365f4ae0b7 100644 --- a/mayan/apps/converter/transformations.py +++ b/mayan/apps/converter/transformations.py @@ -84,10 +84,25 @@ class TransformationCrop(BaseTransformation): def execute_on(self, *args, **kwargs): super(TransformationCrop, self).execute_on(*args, **kwargs) - left = float(self.left or '0') - top = float(self.top or '0') - right = self.image.size[0] - float(self.right or '0') - bottom = self.image.size[1] - float(self.bottom or '0') + try: + left = int(self.left or '0') + except ValueError: + left = 0 + + try: + top = int(self.top or '0') + except ValueError: + top = 0 + + try: + right = int(self.right or '0') + except ValueError: + right = 0 + + try: + bottom = int(self.bottom or '0') + except ValueError: + bottom = 0 if left < 0: left = 0 @@ -113,6 +128,15 @@ class TransformationCrop(BaseTransformation): if bottom > self.image.size[1] - 1: bottom = self.image.size[1] - 1 + # Invert right value + # Pillow uses left, top, right, bottom to define a viewport + # of real coordinates + # We invert the right and bottom to define a viewport + # that can crop from the right and bottom borders without + # having to know the real dimensions of an image + right = self.image.size[0] - right + bottom = self.image.size[1] - bottom + if left > right: left = right - 1 diff --git a/mayan/apps/converter/views.py b/mayan/apps/converter/views.py index ace519c2f7..f9af17a751 100644 --- a/mayan/apps/converter/views.py +++ b/mayan/apps/converter/views.py @@ -15,6 +15,7 @@ from common.views import ( SingleObjectListView ) +from .forms import TransformationForm from .icons import icon_transformation from .links import link_transformation_create from .models import Transformation @@ -75,7 +76,7 @@ class TransformationDeleteView(SingleObjectDeleteView): class TransformationCreateView(SingleObjectCreateView): - fields = ('name', 'arguments') + form_class = TransformationForm def dispatch(self, request, *args, **kwargs): content_type = get_object_or_404( @@ -133,7 +134,7 @@ class TransformationCreateView(SingleObjectCreateView): class TransformationEditView(SingleObjectEditView): - fields = ('name', 'arguments', 'order') + form_class = TransformationForm model = Transformation def dispatch(self, request, *args, **kwargs):