diff options
| -rw-r--r-- | archaeological_operations/forms.py | 7 | ||||
| -rw-r--r-- | archaeological_operations/tests.py | 23 | ||||
| -rw-r--r-- | archaeological_operations/wizards.py | 6 | ||||
| -rw-r--r-- | ishtar_common/admin.py | 4 | ||||
| -rw-r--r-- | ishtar_common/forms.py | 21 | ||||
| -rw-r--r-- | ishtar_common/migrations/0024_custom_form_enabled.py | 24 | ||||
| -rw-r--r-- | ishtar_common/models.py | 4 | ||||
| -rw-r--r-- | ishtar_common/utils.py | 19 | ||||
| -rw-r--r-- | ishtar_common/wizards.py | 55 | 
9 files changed, 132 insertions, 31 deletions
| diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index 61be371d1..47fe746f5 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -997,8 +997,10 @@ OperationFormModifGeneral.associated_models = \  OperationFormModifGeneral.associated_models['associated_file'] = File -class CollaboratorForm(forms.Form): +class CollaboratorForm(CustomForm, forms.Form):      form_label = _(u"Collaborators") +    form_admin_name = _(u"Operation - Collaborators") +    form_slug = "operation-collaborators"      base_models = ['collaborator']      associated_models = {'collaborator': Person, }      collaborator = widgets.Select2MultipleField( @@ -1006,7 +1008,8 @@ class CollaboratorForm(forms.Form):      def __init__(self, *args, **kwargs):          super(CollaboratorForm, self).__init__(*args, **kwargs) -        self.fields['collaborator'].widget.attrs['full-width'] = True +        if 'collaborator' in self.fields: +            self.fields['collaborator'].widget.attrs['full-width'] = True  class OperationFormPreventive(forms.Form): diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py index 9f07aff45..af6199774 100644 --- a/archaeological_operations/tests.py +++ b/archaeological_operations/tests.py @@ -1221,6 +1221,29 @@ class CustomFormTest(TestCase, OperationInitTest):              msg="filter user - 'address' field not found on the modification "                  "wizard. It should not have been filtered.") +    def test_enabled(self): +        c = Client() +        c.login(username=self.username, password=self.password) + +        cls_wiz = OperationWizardModifTest +        url = reverse(cls_wiz.url_name) +        # first wizard step +        step = 'selec-operation_modification' +        cls_wiz.wizard_post(c, url, step, {'pk': self.operations[0].pk}) + +        step = 'collaborators-operation_modification' +        data = { +            '{}{}-current_step'.format(cls_wiz.url_name, +                                       cls_wiz.wizard_name): [step], +        } +        response = c.post(url, data) +        self.assertNotEqual(response.status_code, 404) +        CustomForm.objects.create( +            name="Test2", form="operation-collaborators", available=True, +            apply_to_all=True, enabled=False) +        response = c.post(url, data) +        self.assertEqual(response.status_code, 404) +  class OperationSearchTest(TestCase, OperationInitTest):      fixtures = FILE_FIXTURES diff --git a/archaeological_operations/wizards.py b/archaeological_operations/wizards.py index fffe34ca7..24c1af45b 100644 --- a/archaeological_operations/wizards.py +++ b/archaeological_operations/wizards.py @@ -23,6 +23,7 @@ from django.conf import settings  from django.core.exceptions import ObjectDoesNotExist  from django.core.urlresolvers import reverse  from django.db.models import Max +from django.http import Http404  from django.shortcuts import render  from django.utils.translation import ugettext_lazy as _ @@ -149,7 +150,10 @@ class OperationWizard(Wizard):              data = {}          if not step:              step = self.steps.current -        form = self.get_form_list()[step] +        try: +            form = self.get_form_list()[step] +        except KeyError: +            raise Http404()          # manage the dynamic choice of towns          if step.startswith('towns') and hasattr(form, 'management_form'):              data['TOWNS'] = self.get_towns() diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index 7c21fa4be..189a02c05 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -519,9 +519,9 @@ class ExcludeFieldInline(admin.TabularInline):  class CustomFormAdmin(admin.ModelAdmin): -    list_display = ['name', 'form', 'available', 'apply_to_all', +    list_display = ['name', 'form', 'available', 'enabled', 'apply_to_all',                      'users_lbl', 'user_types_lbl'] -    fields = ('name', 'form', 'available', 'apply_to_all', 'users', +    fields = ('name', 'form', 'available', 'enabled', 'apply_to_all', 'users',                'user_types')      form = CustomFormForm      inlines = [ExcludeFieldInline] diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 683726e67..da6a1c051 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -34,7 +34,7 @@ from django.utils.translation import ugettext_lazy as _  import models  import widgets -from wizards import MultiValueDict +from ishtar_common.utils import MultiValueDict  # from formwizard.forms import NamedUrlSessionFormWizard @@ -311,7 +311,17 @@ class CustomForm(object):              except AttributeError:                  pass          super(CustomForm, self).__init__(*args, **kwargs) -        base_q = {"form": self.form_slug, 'available': True} +        available, excluded = self.check_availability_and_excluded_fields( +            current_user) +        for exc in excluded: +            if exc in self.fields: +                self.fields.pop(exc) + +    @classmethod +    def check_availability_and_excluded_fields(cls, current_user): +        if not current_user: +            return True, [] +        base_q = {"form": cls.form_slug, 'available': True}          # order is important : try for user, user type then all          query_dicts = []          if current_user: @@ -325,17 +335,20 @@ class CustomForm(object):          dct = base_q.copy()          dct.update({'apply_to_all': True})          query_dicts.append(dct) +        excluded_lst = []          for query_dict in query_dicts:              q = models.CustomForm.objects.filter(**query_dict)              if not q.count():                  continue              # todo: prevent multiple result in database              form = q.all()[0] +            if not form.enabled: +                return False, []              for excluded in form.excluded_fields.all():                  # could have be filtered previously -                if excluded.field in self.fields: -                    self.fields.pop(excluded.field) +                excluded_lst.append(excluded.field)              break +        return True, excluded_lst      @classmethod      def get_custom_fields(cls): diff --git a/ishtar_common/migrations/0024_custom_form_enabled.py b/ishtar_common/migrations/0024_custom_form_enabled.py new file mode 100644 index 000000000..92fd32f6e --- /dev/null +++ b/ishtar_common/migrations/0024_custom_form_enabled.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-11-21 09:55 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + +    dependencies = [ +        ('ishtar_common', '0023_excludedfield'), +    ] + +    operations = [ +        migrations.AlterModelOptions( +            name='excludedfield', +            options={'verbose_name': 'Excluded field', 'verbose_name_plural': 'Excluded fields'}, +        ), +        migrations.AddField( +            model_name='customform', +            name='enabled', +            field=models.BooleanField(default=True, help_text='Disable with caution: disabling a form with mandatory fields may lead to database errors.', verbose_name='Enable this form'), +        ), +    ] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index c888e87fd..b0751f661 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1635,6 +1635,10 @@ class CustomForm(models.Model):      name = models.CharField(_(u"Name"), max_length=250)      form = models.CharField(_(u"Form"), max_length=250)      available = models.BooleanField(_(u"Available"), default=True) +    enabled = models.BooleanField( +        _(u"Enable this form"), default=True, +        help_text=_(u"Disable with caution: disabling a form with mandatory " +                    u"fields may lead to database errors."))      apply_to_all = models.BooleanField(          _(u"Apply to all"), default=False,          help_text=_(u"Apply this form to all users. If set to True, selecting " diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index ae178a752..cc01f23e7 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -28,6 +28,7 @@ from django.conf import settings  from django.contrib.gis.geos import GEOSGeometry  from django.core.cache import cache  from django.core.urlresolvers import reverse +from django.utils.datastructures import MultiValueDict as BaseMultiValueDict  from django.utils.safestring import mark_safe  from django.utils.translation import ugettext_lazy as _, ugettext  from django.template.defaultfilters import slugify @@ -47,6 +48,24 @@ class BColors:      UNDERLINE = '\033[4m' +class MultiValueDict(BaseMultiValueDict): +    def get(self, *args, **kwargs): +        v = super(MultiValueDict, self).getlist(*args, **kwargs) +        if callable(v): +            v = v() +        if type(v) in (list, tuple) and len(v) > 1: +            v = ",".join(v) +        elif type(v) not in (int, unicode): +            v = super(MultiValueDict, self).get(*args, **kwargs) +        return v + +    def getlist(self, *args, **kwargs): +        lst = super(MultiValueDict, self).getlist(*args, **kwargs) +        if type(lst) not in (tuple, list): +            lst = [lst] +        return lst + +  def get_current_year():      return datetime.datetime.now().year diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index f86e03df0..e82b32671 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -34,37 +34,19 @@ from django.db.models.fields.files import FileField, ImageFieldFile  from django.db.models.fields.related import ManyToManyField  from django.db.models.fields import NOT_PROVIDED -from django.http import HttpResponseRedirect +from django.http import HttpResponseRedirect, Http404  from django.forms import ValidationError  from django.shortcuts import redirect, render  from django.template import loader -from django.utils.datastructures import MultiValueDict as BaseMultiValueDict  from django.utils.translation import ugettext_lazy as _  from ishtar_common import models -from ishtar_common.utils import get_all_field_names +from ishtar_common.forms import CustomForm +from ishtar_common.utils import get_all_field_names, MultiValueDict  logger = logging.getLogger(__name__) -class MultiValueDict(BaseMultiValueDict): -    def get(self, *args, **kwargs): -        v = super(MultiValueDict, self).getlist(*args, **kwargs) -        if callable(v): -            v = v() -        if type(v) in (list, tuple) and len(v) > 1: -            v = ",".join(v) -        elif type(v) not in (int, unicode): -            v = super(MultiValueDict, self).get(*args, **kwargs) -        return v - -    def getlist(self, *args, **kwargs): -        lst = super(MultiValueDict, self).getlist(*args, **kwargs) -        if type(lst) not in (tuple, list): -            lst = [lst] -        return lst - -  def check_rights(rights=[], redirect_url='/'):      """      Decorator that checks the rights to access the view. @@ -125,6 +107,19 @@ def _check_right(step, condition=True):  """ +def filter_no_fields_form(form, other_check=None): +    def func(self): +        if issubclass(form, CustomForm): +            enabled, exc = form.check_availability_and_excluded_fields( +                self.request.user.ishtaruser) +            if not enabled: +                return False +        if other_check: +            return other_check(self) +        return True +    return func + +  class Wizard(NamedUrlWizardView):      model = None      label = '' @@ -155,6 +150,19 @@ class Wizard(NamedUrlWizardView):              self.condition_dict[form_key] = cond      ''' +    @classmethod +    def get_initkwargs(cls, *args, **kwargs): +        kwargs = super(Wizard, cls).get_initkwargs(*args, **kwargs) +        # remove +        for form_key in kwargs['form_list']: +            form = kwargs['form_list'][form_key] +            other_check = None +            if form_key in kwargs['condition_dict']: +                other_check = kwargs['condition_dict'][form_key] +            kwargs['condition_dict'][form_key] = filter_no_fields_form( +                form, other_check) +        return kwargs +      def dispatch(self, request, *args, **kwargs):          self.current_right = kwargs.get('current_right', None) @@ -813,7 +821,10 @@ class Wizard(NamedUrlWizardView):              data = data.copy()              if not step:                  step = self.steps.current -            form = self.get_form_list()[step] +            try: +                form = self.get_form_list()[step] +            except KeyError: +                raise Http404()              if hasattr(form, 'management_form'):                  # manage deletion                  to_delete, not_to_delete = self.get_deleted(data.keys()) | 
