Skip to content

Commit 7dddfac

Browse files
authored
Merge pull request #4787 from kobotoolbox/edit-submission-with-xml-encoding-declaration
Fix error when editing submissions with XML encoding declaration
2 parents f7ddadb + 88aa374 commit 7dddfac

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

kpi/deployment_backends/mock_backend.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from backports.zoneinfo import ZoneInfo
2121

2222
from deepmerge import always_merger
23-
from dict2xml import dict2xml
23+
from dict2xml import dict2xml as dict2xml_real
2424
from django.conf import settings
2525
from django.urls import reverse
2626
from django.utils.translation import gettext as t
@@ -50,6 +50,11 @@
5050
from ..exceptions import KobocatBulkUpdateSubmissionsClientException
5151

5252

53+
def dict2xml(*args, **kwargs):
54+
""" To facilitate mocking in unit tests """
55+
return dict2xml_real(*args, **kwargs)
56+
57+
5358
class MockDeploymentBackend(BaseDeploymentBackend):
5459
"""
5560
Only used for unit testing and interface testing.

kpi/tests/api/v2/test_api_submissions.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import copy
33
import json
44
import lxml
5+
import mock
56
import random
67
import string
78
import time
@@ -14,6 +15,7 @@
1415

1516
import pytest
1617
import responses
18+
from dict2xml import dict2xml
1719
from django.conf import settings
1820
from django.contrib.auth.models import User
1921
from django.urls import reverse
@@ -1247,6 +1249,47 @@ def test_edit_submission_with_different_root_name(self):
12471249
)
12481250
assert new_snapshot.pk != snapshot.pk
12491251

1252+
@responses.activate
1253+
def test_edit_submission_with_xml_encoding_declaration(self):
1254+
def dict2xml_with_encoding_declaration(*args, **kwargs):
1255+
return '<?xml version="1.0" encoding="utf-8"?>' + dict2xml(
1256+
*args, **kwargs
1257+
)
1258+
1259+
with mock.patch(
1260+
'kpi.deployment_backends.mock_backend.dict2xml'
1261+
) as mock_dict2xml:
1262+
mock_dict2xml.side_effect = dict2xml_with_encoding_declaration
1263+
submission = self.submissions[-1]
1264+
submission_xml = self.asset.deployment.get_submissions(
1265+
user=self.asset.owner,
1266+
format_type=SUBMISSION_FORMAT_TYPE_XML,
1267+
submission_ids=[submission['_id']],
1268+
)[0]
1269+
assert submission_xml.startswith(
1270+
'<?xml version="1.0" encoding="utf-8"?>'
1271+
)
1272+
1273+
# Get edit endpoint
1274+
edit_url = reverse(
1275+
self._get_endpoint('submission-enketo-edit'),
1276+
kwargs={
1277+
'parent_lookup_asset': self.asset.uid,
1278+
'pk': submission['_id'],
1279+
},
1280+
)
1281+
1282+
# Set up a mock Enketo response and attempt the edit request
1283+
ee_url = f'{settings.ENKETO_URL}/{settings.ENKETO_EDIT_INSTANCE_ENDPOINT}'
1284+
responses.add_callback(
1285+
responses.POST,
1286+
ee_url,
1287+
callback=enketo_edit_instance_response_with_uuid_validation,
1288+
content_type='application/json',
1289+
)
1290+
response = self.client.get(edit_url, {'format': 'json'})
1291+
assert response.status_code == status.HTTP_200_OK
1292+
12501293
@responses.activate
12511294
def test_edit_submission_with_xml_missing_uuids(self):
12521295
# Make a new submission without UUIDs

kpi/views/v2/data.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,13 @@ def _get_enketo_link(
655655
submission_xml = deployment.get_submission(
656656
submission_id, user, SUBMISSION_FORMAT_TYPE_XML
657657
)
658+
if isinstance(submission_xml, str):
659+
# Workaround for "Unicode strings with encoding declaration are not
660+
# supported. Please use bytes input or XML fragments without
661+
# declaration."
662+
# TODO: handle this in a unified way instead of haphazardly. See,
663+
# e.g., `kpi.utils.xml.strip_nodes()`
664+
submission_xml = submission_xml.encode()
658665
submission_xml_root = etree.fromstring(submission_xml)
659666
# The JSON version is needed to detect its version
660667
submission_json = deployment.get_submission(

0 commit comments

Comments
 (0)