diff options
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/forms.py | 180 | ||||
-rw-r--r-- | ishtar_common/tests.py | 2 |
2 files changed, 108 insertions, 74 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index da6a1c051..8b97cfbab 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -105,7 +105,92 @@ def get_readonly_clean(key): return func -class FormSet(BaseFormSet): +class CustomForm(object): + form_admin_name = "" + form_slug = "" + need_user_for_initialization = True + + def __init__(self, *args, **kwargs): + current_user = None + if 'user' in kwargs: + try: + current_user = kwargs.pop('user').ishtaruser + except AttributeError: + pass + super(CustomForm, self).__init__(*args, **kwargs) + available, excluded = self.check_availability_and_excluded_fields( + current_user) + for exc in excluded: + if hasattr(self, 'fields'): + self.remove_field(exc) + else: + # formset + for form in self.forms: + if exc in form.fields: + form.fields.pop(exc) + + def are_available(self, keys): + for k in keys: + if k not in self.fields: + return False + return True + + def remove_field(self, key): + if key in self.fields: + self.fields.pop(key) + + @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: + dct = base_q.copy() + dct.update({'users__pk': current_user.pk}) + query_dicts = [dct] + for user_type in current_user.person.person_types.all(): + dct = base_q.copy() + dct.update({'user_types__pk': user_type.pk}), + query_dicts.append(dct) + 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 + excluded_lst.append(excluded.field) + break + return True, excluded_lst + + @classmethod + def get_custom_fields(cls): + if hasattr(cls, 'base_fields'): + fields = cls.base_fields + else: + # formset + fields = cls.form.base_fields + customs = [] + for key in fields: + field = fields[key] + # cannot customize display of required and hidden field + # field with no label are also rejected + if field.required or field.widget.is_hidden or not field.label: + continue + customs.append((key, field.label)) + return sorted(customs, key=lambda x: x[1]) + + +class FormSet(CustomForm, BaseFormSet): def __init__(self, *args, **kwargs): self.readonly = False if 'readonly' in kwargs: @@ -250,8 +335,23 @@ def get_data_from_formset(data): return values +class FieldType(object): + def __init__(self, key, model, is_multiple=False): + self.key = key + self.model = model + self.is_multiple = is_multiple + + def get_choices(self, initial=None): + return self.model.get_types( + empty_first=not self.is_multiple, + initial=initial) + + def get_help(self): + return self.model.get_help() + + class ManageOldType(object): - TYPES = [] # (field_name, model, is_multiple) list + TYPES = [] # FieldType list def __init__(self, *args, **kwargs): """ @@ -290,78 +390,12 @@ class ManageOldType(object): self.init_data[k].append(val) self.init_data = MultiValueDict(self.init_data) super(ManageOldType, self).__init__(*args, **kwargs) - for field_name, model, is_multiple in self.TYPES: - self.fields[field_name].choices = \ - model.get_types( - empty_first=not is_multiple, - initial=self.init_data.get(field_name)) - self.fields[field_name].help_text = model.get_help() - - -class CustomForm(object): - form_admin_name = "" - form_slug = "" - need_user_for_initialization = True - - def __init__(self, *args, **kwargs): - current_user = None - if 'user' in kwargs: - try: - current_user = kwargs.pop('user').ishtaruser - except AttributeError: - pass - super(CustomForm, self).__init__(*args, **kwargs) - 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: - dct = base_q.copy() - dct.update({'users__pk': current_user.pk}) - query_dicts = [dct] - for user_type in current_user.person.person_types.all(): - dct = base_q.copy() - dct.update({'user_types__pk': user_type.pk}), - query_dicts.append(dct) - 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(): + for field in self.TYPES: + if field.key not in self.fields: 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 - - @classmethod - def get_custom_fields(cls): - fields = cls.base_fields - customs = [] - for key in fields: - field = fields[key] - # cannot customize display of required and hidden field - # field with no label are also rejected - if field.required or field.widget.is_hidden or not field.label: - continue - customs.append((key, field.label)) - return sorted(customs, key=lambda x: x[1]) + self.fields[field.key].choices = field.get_choices( + initial=self.init_data.get(field.key)) + self.fields[field.key].help_text = field.get_help() class DocumentGenerationForm(forms.Form): diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py index 016596772..7c8b2fd5c 100644 --- a/ishtar_common/tests.py +++ b/ishtar_common/tests.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2015-2016 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2015-2017 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as |