diff --git a/kobo/apps/subsequences/jsonschemas/qual_schema.py b/kobo/apps/subsequences/jsonschemas/qual_schema.py index 36a8cb72b6..8211b06e38 100644 --- a/kobo/apps/subsequences/jsonschemas/qual_schema.py +++ b/kobo/apps/subsequences/jsonschemas/qual_schema.py @@ -59,7 +59,7 @@ def refdefpath(ss): 'type': 'object', 'properties': { 'type': {'const': 'qual_select_one'}, - 'val': {'type': 'string'}, + 'val': {'type': 'string', 'minLength': 1}, }, } DEFINITIONS['qual_select_multiple'] = { @@ -68,7 +68,7 @@ def refdefpath(ss): 'type': {'const': 'qual_select_multiple'}, 'val': { 'type': 'array', - 'items': {'type': 'string'}, + 'items': {'type': 'string', 'minLength': 1}, }, }, } diff --git a/kobo/apps/subsequences/tests/test_submission_stream.py b/kobo/apps/subsequences/tests/test_submission_stream.py index 4542d603e1..13506f5871 100644 --- a/kobo/apps/subsequences/tests/test_submission_stream.py +++ b/kobo/apps/subsequences/tests/test_submission_stream.py @@ -285,3 +285,39 @@ def test_stream_with_extras_handles_duplicated_submission_uuids(self): # Clear all mocked submissions to avoid duplicate submission errors self.asset.deployment.mock_submissions([]) + + def test_stream_with_extras_ignores_empty_qual_responses(self): + # Modify submission extras 'val' to be an empty string + submission_extras = SubmissionExtras.objects.get( + submission_uuid='1c05898e-b43c-491d-814c-79595eb84e81' + ) + content = submission_extras.content + content['Tell_me_a_story']['qual'][1]['val'] = '' + submission_extras.content = content + submission_extras.save() + + # Process submissions with extras + output = list( + stream_with_extras( + self.asset.deployment.get_submissions(user=self.asset.owner), + self.asset, + ) + ) + + # Ensure that the empty 'val' fields are skipped and not processed + for submission in output: + supplemental_details = submission.get('_supplementalDetails', {}) + for key, details in supplemental_details.items(): + qual_responses = details.get('qual', []) + for qual_response in qual_responses: + if qual_response['type'] in [ + 'qual_select_one', + 'qual_select_multiple', + ]: + val = qual_response['val'] + + if isinstance(val, list): + for v in val: + self.assertEqual(v, '') + else: + self.assertEqual(val, '') diff --git a/kobo/apps/subsequences/utils/__init__.py b/kobo/apps/subsequences/utils/__init__.py index bddf773004..9d1f35594e 100644 --- a/kobo/apps/subsequences/utils/__init__.py +++ b/kobo/apps/subsequences/utils/__init__.py @@ -176,6 +176,8 @@ def stream_with_extras(submission_stream, asset): val = [val] val_expanded = [] for v in val: + if v == '': + continue try: v_ex = qual_choices_per_question_by_uuid[ qual_q['uuid'] @@ -186,7 +188,7 @@ def stream_with_extras(submission_stream, asset): # added. They should simply be hidden v_ex = {'uuid': v, 'error': 'unknown choice'} val_expanded.append(v_ex) - if single_choice: + if single_choice and val_expanded: val_expanded = val_expanded[0] qual_response['val'] = val_expanded qual_response.update(qual_q)