Skip to content

Commit

Permalink
Fix #1638: Check for xlsform relevant clause syntax errors
Browse files Browse the repository at this point in the history
  • Loading branch information
bohare committed Jul 7, 2017
1 parent 4057753 commit f2cf63f
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
11 changes: 11 additions & 0 deletions cadasta/questionnaires/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
ATTRIBUTE_GROUPS = settings.ATTRIBUTE_GROUPS


def check_relevant_clause(relevant):
if not re.match(r"^\$\{\w+\}=('|\"|”)\w+('|\"|”)$", relevant):
raise InvalidQuestionnaire(
[_("Invalid relevant clause: {0}".format(relevant))])


def create_children(children, errors=[], project=None,
default_language='', kwargs={}):
if children:
Expand Down Expand Up @@ -83,6 +89,7 @@ def create_attrs_schema(project=None, dict=None, content_type=None,
if bind:
relevant = bind.get('relevant', None)
if relevant:
check_relevant_clause(relevant)
clauses = relevant.split('=')
selector = re.sub("'", '', clauses[1])
selectors += (selector,)
Expand Down Expand Up @@ -262,6 +269,8 @@ def create_from_dict(self, dict=None, question_group=None,
bind = dict.get('bind')
if bind:
relevant = bind.get('relevant', None)
if relevant:
check_relevant_clause(relevant)

instance.name = dict.get('name')
instance.label_xlat = dict.get('label', {})
Expand Down Expand Up @@ -296,6 +305,8 @@ def create_from_dict(self, errors=[], index=0, **kwargs):
bind = dict.get('bind')
if bind:
relevant = bind.get('relevant', None)
if relevant:
check_relevant_clause(relevant)
required = True if bind.get('required', 'no') == 'yes' else False

instance.type = type_dict[dict.get('type')]
Expand Down
66 changes: 65 additions & 1 deletion cadasta/questionnaires/tests/test_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,34 @@ def test_create_children_with_repeat_group(self):
questionnaire=questionnaire,
question_group__isnull=False).count() == 2

def test_invalid_relevant_clause_in_children(self):
questionnaire = factories.QuestionnaireFactory.create()
children = [{
'label': 'This form showcases the different question',
'name': 'intro',
'type': 'note'
}, {
'label': 'Text question type',
'name': 'text_questions',
'type': 'group',
'children': [
{
'hint': 'Can be short or long but '
'always one line (type = '
'text)',
'label': 'Text',
'name': 'my_string',
'type': 'text',
'bind': {'relevant': '$geo_type="geoshape"'} # invalid
}
],
}]

with pytest.raises(InvalidQuestionnaire) as e:
create_children(children, kwargs={'questionnaire': questionnaire})

assert str(e.value) == 'Invalid relevant clause: $geo_type="geoshape"'


class CreateOptionsTest(TestCase):

Expand Down Expand Up @@ -287,7 +315,7 @@ def test_create_from_dict(self):
'label': 'Basic Select question types',
'name': 'select_questions',
'type': 'group',
'bind': {'relevant': "${party_type}='IN'"}
'bind': {'relevant': "${party_type}=”IN”"}
}
questionnaire = factories.QuestionnaireFactory.create()

Expand Down Expand Up @@ -326,6 +354,21 @@ def test_create_nested_group_from_dict(self):
assert model.question_groups.count() == 1
assert questionnaire.question_groups.count() == 2

def test_invalid_relevant_clause(self):
question_group_dict = {
'label': 'Basic Select question types',
'name': 'select_questions',
'type': 'group',
'bind': {'relevant': "$party_type='IN'"} # invalid
}
questionnaire = factories.QuestionnaireFactory.create()
with pytest.raises(InvalidQuestionnaire) as e:
models.QuestionGroup.objects.create_from_dict(
dict=question_group_dict,
questionnaire=questionnaire
)
assert str(e.value) == "Invalid relevant clause: $party_type='IN'"


class QuestionManagerTest(TestCase):

Expand Down Expand Up @@ -381,6 +424,27 @@ def test_create_from_dict_with_group(self):
assert model.name == question_dict['name']
assert model.type == 'IN'

def test_invalid_relevant_clause(self):
question_dict = {
'hint': 'For this field (type=integer)',
'label': 'Integer',
'name': 'my_int',
'type': 'integer',
'default': 'default val',
'hint': 'An informative hint',
'bind': {
'relevant': "$party_id='abc123'", # invalid
'required': 'yes'
}
}
questionnaire = factories.QuestionnaireFactory.create()
with pytest.raises(InvalidQuestionnaire) as e:
models.Question.objects.create_from_dict(
dict=question_dict,
questionnaire=questionnaire
)
assert str(e.value) == "Invalid relevant clause: $party_id='abc123'"


class MultilingualQuestionnaireTest(UserTestCase, FileStorageTestCase,
TestCase):
Expand Down

0 comments on commit f2cf63f

Please sign in to comment.