summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/forms.py78
-rw-r--r--ishtar_common/migrations/0053_auto_20180523_1504.py (renamed from ishtar_common/migrations/0053_auto_20180523_1126.py)4
-rw-r--r--ishtar_common/models.py3
-rw-r--r--ishtar_common/wizards.py45
4 files changed, 116 insertions, 14 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py
index c314e4f13..5de0db91d 100644
--- a/ishtar_common/forms.py
+++ b/ishtar_common/forms.py
@@ -20,6 +20,7 @@
"""
Forms definition
"""
+from collections import OrderedDict
import datetime
import re
import types
@@ -107,6 +108,16 @@ def get_readonly_clean(key):
return func
+JSON_VALUE_TYPES_FIELDS = {
+ 'T': (forms.CharField, None),
+ 'LT': (forms.CharField, forms.Textarea),
+ 'I': (forms.IntegerField, None),
+ 'F': (forms.FloatField, None),
+ 'D': (DateField, None),
+ 'C': (forms.CharField, None),
+}
+
+
class CustomForm(object):
form_admin_name = ""
form_slug = ""
@@ -120,8 +131,7 @@ class CustomForm(object):
except AttributeError:
pass
super(CustomForm, self).__init__(*args, **kwargs)
- available, excluded = self.check_availability_and_excluded_fields(
- current_user)
+ available, excluded, json_fields = self.check_custom_form(current_user)
for exc in excluded:
if hasattr(self, 'fields'):
self.remove_field(exc)
@@ -131,6 +141,25 @@ class CustomForm(object):
if exc in form.fields:
form.fields.pop(exc)
+ new_fields = {}
+ for order, key, field in json_fields:
+ while order in new_fields: # json fields with the same number
+ order += 1
+ new_fields[order] = (key, field)
+
+ if not new_fields:
+ return
+
+ # re-order for json fields
+ fields = OrderedDict()
+ for idx, field in enumerate(self.fields.items()):
+ key, c_field = field
+ if idx + 1 in new_fields:
+ alt_key, alt_field = new_fields[idx + 1]
+ fields[alt_key] = alt_field
+ fields[key] = c_field
+ self.fields = fields
+
def are_available(self, keys):
for k in keys:
if k not in self.fields:
@@ -142,9 +171,28 @@ class CustomForm(object):
self.fields.pop(key)
@classmethod
- def check_availability_and_excluded_fields(cls, current_user):
+ def _get_json_fields(cls, custom_form):
+ fields = []
+ for field in custom_form.json_fields.order_by('order').all():
+ key = "data__" + field.json_field.key
+ field_cls, widget = forms.CharField, None
+ if field.json_field.value_type in JSON_VALUE_TYPES_FIELDS:
+ field_cls, widget = JSON_VALUE_TYPES_FIELDS[
+ field.json_field.value_type]
+ attrs = {'label': field.label or field.json_field.name,
+ 'required': False}
+ if field.help_text:
+ attrs['help_text'] = field.help_text
+ if widget:
+ attrs['widget'] = widget(attrs={"class": "form-control"})
+ f = field_cls(**attrs)
+ fields.append((field.order or 1, key, f))
+ return fields
+
+ @classmethod
+ def check_custom_form(cls, current_user):
if not current_user:
- return True, []
+ return True, [], []
base_q = {"form": cls.form_slug, 'available': True}
# order is important : try for user, user type then all
query_dicts = []
@@ -159,23 +207,31 @@ class CustomForm(object):
dct = base_q.copy()
dct.update({'apply_to_all': True})
query_dicts.append(dct)
- excluded_lst = []
+ form = None
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
- excluded_lst.append(excluded.field)
break
- return True, excluded_lst
+ if not form:
+ return True, [], []
+ if not form.enabled:
+ return False, [], []
+ excluded_lst = []
+ for excluded in form.excluded_fields.all():
+ # could have be filtered previously
+ excluded_lst.append(excluded.field)
+ json_fields = cls._get_json_fields(form)
+ return True, excluded_lst, json_fields
@classmethod
def get_custom_fields(cls):
+ """
+ Get fields than can be customized: excluded, re-ordered (WIP) or
+ re-labeled (WIP)
+ """
if hasattr(cls, 'base_fields'):
fields = cls.base_fields
else:
diff --git a/ishtar_common/migrations/0053_auto_20180523_1126.py b/ishtar_common/migrations/0053_auto_20180523_1504.py
index f776dce30..14e34a866 100644
--- a/ishtar_common/migrations/0053_auto_20180523_1126.py
+++ b/ishtar_common/migrations/0053_auto_20180523_1504.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Generated by Django 1.11.10 on 2018-05-23 11:26
+# Generated by Django 1.11.10 on 2018-05-23 15:04
from __future__ import unicode_literals
from django.db import migrations, models
@@ -17,7 +17,9 @@ class Migration(migrations.Migration):
name='CustomFormJsonField',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('label', models.CharField(blank=True, default=b'', max_length=200, verbose_name='Label')),
('order', models.IntegerField(default=1, verbose_name='Order')),
+ ('help_text', models.TextField(blank=True, null=True, verbose_name='Help')),
('custom_form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='json_fields', to='ishtar_common.CustomForm')),
],
options={
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index bb285883f..e4c6d0e9a 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -1893,7 +1893,10 @@ class CustomFormJsonField(models.Model):
custom_form = models.ForeignKey(CustomForm, related_name='json_fields')
json_field = models.ForeignKey(JsonDataField,
related_name='custom_form_details')
+ label = models.CharField(_(u"Label"), max_length=200, blank=True,
+ default='')
order = models.IntegerField(verbose_name=_(u"Order"), default=1)
+ help_text = models.TextField(_(u"Help"), blank=True, null=True)
class Meta:
verbose_name = _(u"Custom form - Json data field")
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index a6844b674..40044f100 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -120,8 +120,12 @@ def filter_no_fields_form(form, other_check=None):
if not hasattr(self.request.user, 'ishtaruser'):
return False
if issubclass(form, CustomForm):
- enabled, exc = form.check_availability_and_excluded_fields(
+ enabled, excluded, json_fields = form.check_custom_form(
self.request.user.ishtaruser)
+ if not hasattr(self, 'json_fields'):
+ self.json_fields = {}
+ self.json_fields[form.form_slug] = [
+ key for order, key, field in json_fields]
if not enabled:
return False
if other_check:
@@ -595,11 +599,27 @@ class Wizard(NamedUrlWizardView):
return_object):
dct = self.get_extra_model(dct, form_list)
obj = self.get_current_saved_object()
- # manage dependant items
+ data = {}
+ if obj:
+ data = obj.data
+
+ # manage dependant items and json fields
other_objs = {}
for k in dct.keys():
if '__' not in k:
continue
+ # manage json field
+ if k.startswith('data__'):
+ data_keys = k[len('data__'):].split('__')
+ # tree
+ current_data = data
+ for data_key in data_keys[:-1]:
+ if data_key not in current_data:
+ current_data[data_key] = {}
+ current_data = current_data[data_key]
+ current_data[data_keys[-1]] = dct.pop(k)
+ continue
+
vals = k.split('__')
assert len(vals) == 2, \
"Only one level of dependant item is managed"
@@ -627,6 +647,7 @@ class Wizard(NamedUrlWizardView):
elif type(dct[k]) not in (list, tuple):
dct[k] = [dct[k]]
setattr(obj, k, dct[k])
+ obj.data = data
if hasattr(obj, 'pre_save'):
obj.pre_save()
try:
@@ -711,6 +732,7 @@ class Wizard(NamedUrlWizardView):
except ValidationError as e:
logger.warning(unicode(e))
return self.render(form_list[-1])
+ obj.data = data
obj.save(**saved_args)
for k in adds:
getattr(obj, k).add(adds[k])
@@ -1243,6 +1265,25 @@ class Wizard(NamedUrlWizardView):
Get initial data from an object: simple form
"""
initial = MultiValueDict()
+
+ # manage json field
+ if hasattr(self, 'json_fields') \
+ and getattr(c_form, 'form_slug', None) \
+ and c_form.form_slug in self.json_fields \
+ and obj.data:
+ for key in self.json_fields[c_form.form_slug]:
+ if not key.startswith('data__'):
+ continue
+ json_keys = key[len('data__'):].split('__')
+ value = obj.data
+ for json_key in json_keys:
+ if json_key not in value:
+ value = None
+ break
+ value = value[json_key]
+ if value:
+ initial[key] = value
+
for base_field in c_form.base_fields.keys():
value = obj
base_model = None