summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2017-11-21 10:46:58 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2017-11-21 10:46:58 +0100
commitc410be9b3c3ba193ee8c233cc6a50d065d4090fd (patch)
tree7fe4800634a6079854d7ab10c782c79fce24ea10
parent9309d89a48cee876ef17213924b2cc0b026677f9 (diff)
downloadIshtar-c410be9b3c3ba193ee8c233cc6a50d065d4090fd.tar.bz2
Ishtar-c410be9b3c3ba193ee8c233cc6a50d065d4090fd.zip
Custom forms: disable completly a form
-rw-r--r--archaeological_operations/forms.py7
-rw-r--r--archaeological_operations/tests.py23
-rw-r--r--archaeological_operations/wizards.py6
-rw-r--r--ishtar_common/admin.py4
-rw-r--r--ishtar_common/forms.py21
-rw-r--r--ishtar_common/migrations/0024_custom_form_enabled.py24
-rw-r--r--ishtar_common/models.py4
-rw-r--r--ishtar_common/utils.py19
-rw-r--r--ishtar_common/wizards.py55
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())