diff --git a/opentech/apply/funds/blocks.py b/opentech/apply/funds/blocks.py index 7750bb0281cf2b1257fd67d529df2c23a8ed549f..cbe885a8cef4937fae55a412ecb4db14fdd95d07 100644 --- a/opentech/apply/funds/blocks.py +++ b/opentech/apply/funds/blocks.py @@ -1,3 +1,7 @@ +from collections import Counter + +from django.core.exceptions import ValidationError +from django.forms.utils import ErrorList from django.utils.translation import ugettext_lazy as _ from django.utils.text import mark_safe @@ -14,6 +18,51 @@ class CustomFormFieldsBlock(FormFieldsBlock): child_blocks = [(block.name, block(group=_('Required'))) for block in MustIncludeFieldBlock.__subclasses__()] super().__init__(child_blocks, *args, **kwargs) + def clean(self, value): + try: + value = super().clean(value) + except ValidationError as e: + error_dict = e.params + else: + error_dict = dict() + + required_block_names = [block.name for block in MustIncludeFieldBlock.__subclasses__()] + + block_types = [block.block_type for block in value] + missing = set(required_block_names) - set(block_types) + + counted_types = Counter(block_types) + duplicates = [ + name for name, count in counted_types.items() + if name in required_block_names and count > 1 + ] + + all_errors = list() + if missing: + all_errors.append( + 'You are missing the following required fields: {}'.format(', '.join(missing).title()) + ) + + if duplicates: + all_errors.append( + 'You have duplicates of the following required fields: {}'.format(', '.join(duplicates).title()) + ) + for name in duplicates: + for i, block_name in enumerate(block_types): + if block_name == name: + try: + error_dict[i].data[0].params['info'] = ErrorList(['Duplicate']) + except KeyError: + error_dict[i] = ErrorList( + [ValidationError('Error', params={'info': ErrorList(['Duplicate'])})] + ) + + if all_errors: + error_dict['__all__'] = all_errors + raise ValidationError('Error', params=error_dict) + + return value + class MustIncludeStatic(StaticBlock): def __init__(self, *args, description='', **kwargs): @@ -24,15 +73,20 @@ class MustIncludeStatic(StaticBlock): admin_text = 'Much be included in the form once.' def render_form(self, *args, **kwargs): + errors = kwargs.pop('errors') + if errors: + error_message= '<div class="error"><input readonly placeholder="{}"></div>'.format(errors[0]) + else: + error_message = '' form = super().render_form(*args, **kwargs) - form = '<br>'.join([self.description, form]) + form = '<br>'.join([self.description, form]) + error_message return mark_safe(form) class MustIncludeFieldBlock(FormFieldBlock): def __init__(self, *args, **kwargs): - info_name = f'{self.name}_field' - child_blocks = [(info_name, MustIncludeStatic(description=self.description))] + info_name = f'{self.name.title()} Field' + child_blocks = [('info', MustIncludeStatic(label=info_name, description=self.description))] super().__init__(child_blocks, *args, **kwargs)