Skip to content
This repository has been archived by the owner on Feb 13, 2022. It is now read-only.

Commit

Permalink
Merge cf60432 into 4cd126d
Browse files Browse the repository at this point in the history
  • Loading branch information
codiebeulaine committed Aug 16, 2018
2 parents 4cd126d + cf60432 commit 7fd5f1c
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 1 deletion.
76 changes: 76 additions & 0 deletions molo/surveys/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from .blocks import SkipState, VALID_SKIP_LOGIC, VALID_SKIP_SELECTORS
from .widgets import NaturalDateInput

CHARACTER_COUNT_CHOICE_LIMIT = 512


class CharacterCountWidget(forms.TextInput):
class Media:
Expand All @@ -40,6 +42,45 @@ def render(self, name, value, attrs=None):
)


class CharacterCountMixin(object):
max_length = CHARACTER_COUNT_CHOICE_LIMIT

def __init__(self, *args, **kwargs):
self.max_length = kwargs.pop('max_length', self.max_length)
super(CharacterCountMixin, self).__init__(*args, **kwargs)
self.error_messages['max_length'] = _(
'This field can not be more than {max_length} characters long'
).format(max_length=self.max_length)

def validate(self, value):
super(CharacterCountMixin, self).validate(value)
if len(value) > self.max_length:
raise ValidationError(
self.error_messages['max_length'],
code='max_length', params={'value': value},
)


class CharacterCountMultipleChoiceField(
CharacterCountMixin, forms.MultipleChoiceField):
""" Limit character count for Multi choice fields """


class CharacterCountChoiceField(
CharacterCountMixin, forms.ChoiceField):
""" Limit character count for choice fields """


class CharacterCountCheckboxSelectMultiple(
CharacterCountMixin, forms.CheckboxSelectMultiple):
""" Limit character count for checkbox fields """


class CharacterCountCheckboxInput(
CharacterCountMixin, forms.CheckboxInput):
""" Limit character count for checkbox fields """


class SurveysFormBuilder(FormBuilder):
def create_singleline_field(self, field, options):
options['widget'] = CharacterCountWidget
Expand All @@ -63,6 +104,28 @@ def create_datetime_field(self, field, options):
def create_positive_number_field(self, field, options):
return forms.DecimalField(min_value=0, **options)

def create_dropdown_field(self, field, options):
options['choices'] = map(
lambda x: (x.strip(), x.strip()),
field.choices.split(','))
return CharacterCountChoiceField(**options)

def create_radio_field(self, field, options):
options['choices'] = map(
lambda x: (x.strip(), x.strip()),
field.choices.split(','))
return CharacterCountChoiceField(widget=forms.RadioSelect, **options)

def create_checkboxes_field(self, field, options):
options['choices'] = [
(x.strip(), x.strip()) for x in field.choices.split(',')
]
options['initial'] = [
x.strip() for x in field.default_value.split(',')
]
return CharacterCountMultipleChoiceField(
widget=forms.CheckboxSelectMultiple, **options)

@property
def formfields(self):
'''
Expand Down Expand Up @@ -183,13 +246,26 @@ def clean(self):
'Options: a True and False'),
)
elif data['field_type'] in VALID_SKIP_LOGIC:
choices_length = 0
for i, logic in enumerate(data['skip_logic']):
if not logic.value['choice']:
self.add_stream_field_error(
i,
'choice',
_('This field is required.'),
)
else:
choices_length += len(logic.value['choice'])

if choices_length > CHARACTER_COUNT_CHOICE_LIMIT:
err = 'The combined choices\' maximum characters ' \
'limit has been exceeded ({max_limit} '\
'character(s)).'
self.add_form_field_error(
'field_type',
_(err).format(
max_limit=CHARACTER_COUNT_CHOICE_LIMIT),
)

for i, logic in enumerate(data['skip_logic']):
if logic.value['skip_logic'] == SkipState.SURVEY:
Expand Down
3 changes: 2 additions & 1 deletion molo/surveys/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,8 @@ class MoloSurveyFormField(SkipLogicMixin, AdminLabelMixin,
blank=True,
help_text=_(
'Comma separated list of choices. Only applicable in checkboxes,'
'radio and dropdown.')
'radio and dropdown. The full length of the choice list and the ',
'commas that separate them are resctricted to 512 characters.')
)
field_type = models.CharField(
verbose_name=_('field type'),
Expand Down
70 changes: 70 additions & 0 deletions molo/surveys/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
PersonalisableSurvey,
PersonalisableSurveyFormField,
)
from ..forms import CHARACTER_COUNT_CHOICE_LIMIT
from wagtail_personalisation.models import Segment
from wagtail_personalisation.rules import UserIsLoggedInRule

Expand Down Expand Up @@ -98,6 +99,75 @@ def create_personalisable_molo_survey_page(self, parent, **kwargs):

return personalisable_survey, molo_survey_form_field

def test_survey_edit_view(self):
self.client.force_login(self.super_user)
child_of_index_page = create_molo_survey_page(
self.surveys_index,
title="Child of SurveysIndexPage Survey",
slug="child-of-surveysindexpage-survey"
)
form_field = MoloSurveyFormField.objects.create(
page=child_of_index_page, field_type='radio', choices='a,b,c')
response = self.client.get(
'/admin/pages/%d/edit/' % child_of_index_page.pk)
self.assertEqual(response.status_code, 200)
form = response.context['form']
data = form.initial
data.update(
form.formsets['survey_form_fields'].management_form.initial)
data.update({u'description-count': 0})
data.update({
'survey_form_fields-0-admin_label': 'a',
'survey_form_fields-0-label': 'a',
'survey_form_fields-0-default_value': 'a',
'survey_form_fields-0-field_type': form_field.field_type,
'survey_form_fields-0-help_text': 'a',
'survey_form_fields-0-id': form_field.pk,
'go_live_at': '',
'expire_at': '',
'image': '',
'survey_form_fields-0-ORDER': 1,
'survey_form_fields-0-required': 'on',
'survey_form_fields-0-skip_logic-0-deleted': '',
'survey_form_fields-0-skip_logic-0-id': 'None',
'survey_form_fields-0-skip_logic-0-order': 0,
'survey_form_fields-0-skip_logic-0-type': 'skip_logic',
'survey_form_fields-0-skip_logic-0-value-choice': 'a',
'survey_form_fields-0-skip_logic-0-value-question_0': 'a',
'survey_form_fields-0-skip_logic-0-value-skip_logic': 'next',
'survey_form_fields-0-skip_logic-0-value-survey': '',
'survey_form_fields-0-skip_logic-count': 1,
'survey_form_fields-INITIAL_FORMS': 1,
'survey_form_fields-MAX_NUM_FORMS': 1000,
'survey_form_fields-MIN_NUM_FORMS': 0,
'survey_form_fields-TOTAL_FORMS': 1,
'terms_and_conditions-INITIAL_FORMS': 0,
'terms_and_conditions-MAX_NUM_FORMS': 1000,
'terms_and_conditions-MIN_NUM_FORMS': 0,
'terms_and_conditions-TOTAL_FORMS': 0,
})
response = self.client.post(
'/admin/pages/%d/edit/' % child_of_index_page.pk, data=data)
self.assertEqual(
response.context['message'],
u"Page 'Child of SurveysIndexPage Survey' has been updated."
)
data.update({
'survey_form_fields-0-skip_logic-0-value-choice':
'a' + 'a' * CHARACTER_COUNT_CHOICE_LIMIT,
})
response = self.client.post(
'/admin/pages/%d/edit/' % child_of_index_page.pk, data=data)
self.assertEqual(response.status_code, 200)
form = response.context['form'].formsets['survey_form_fields']
err = u'The combined choices\' maximum characters ' \
u'limit has been exceeded ({max_limit} ' \
u'character(s)).'
self.assertTrue(
err.format(max_limit=CHARACTER_COUNT_CHOICE_LIMIT) in
form.errors[0]['field_type'].error_list[0]
)

def test_convert_to_article(self):
molo_survey_page, molo_survey_form_field = \
self.create_molo_survey_page(parent=self.section_index)
Expand Down

0 comments on commit 7fd5f1c

Please sign in to comment.