diff --git a/kobo/apps/openrosa/apps/viewer/models/data_dictionary.py b/kobo/apps/openrosa/apps/viewer/models/data_dictionary.py index 0fc84ba253..50abab70a2 100644 --- a/kobo/apps/openrosa/apps/viewer/models/data_dictionary.py +++ b/kobo/apps/openrosa/apps/viewer/models/data_dictionary.py @@ -19,6 +19,7 @@ DictOrganizer, ) from kobo.apps.openrosa.libs.utils.model_tools import queryset_iterator, set_uuid +from kpi.constants import DEFAULT_SURVEY_NAME from kpi.utils.mongo_helper import MongoHelper @@ -156,10 +157,11 @@ def add_instances(self): def save(self, *args, **kwargs): if self.xls: - survey = create_survey_from_xls(self.xls) - survey.update({ - 'name': survey.id_string, - }) + survey = create_survey_from_xls( + self.xls, default_name=DEFAULT_SURVEY_NAME + ) + if survey.name == DEFAULT_SURVEY_NAME: + survey.name = survey.id_string self.json = survey.to_json() self.xml = survey.to_xml() self._mark_start_time_boolean() diff --git a/kpi/constants.py b/kpi/constants.py index c0ec2ddd4c..33e0635a7b 100644 --- a/kpi/constants.py +++ b/kpi/constants.py @@ -61,6 +61,8 @@ ASSET_TYPE_TEMPLATE: [ASSET_TYPE_SURVEY, ASSET_TYPE_TEMPLATE] } +DEFAULT_SURVEY_NAME = '__kobo_default_survey_name_value__' + ASSET_TYPE_ARG_NAME = 'asset_type' # List of app labels that need to read/write data from KoBoCAT database diff --git a/kpi/tests/test_assets.py b/kpi/tests/test_assets.py index 3506a04078..23721c9cc0 100644 --- a/kpi/tests/test_assets.py +++ b/kpi/tests/test_assets.py @@ -12,6 +12,8 @@ from rest_framework import serializers from kobo.apps.kobo_auth.shortcuts import User +from kobo.apps.openrosa.apps.logger.models import XForm +from kobo.apps.openrosa.apps.logger.xform_instance_parser import XFormInstanceParser from kpi.constants import ( ASSET_TYPE_SURVEY, ASSET_TYPE_COLLECTION, @@ -779,3 +781,77 @@ def test_anonymous_as_baseline_for_authenticated(self): for user_obj in AnonymousUser(), self.anotheruser: self.assertTrue(user_obj.has_perm( PERM_VIEW_ASSET, self.asset)) + + +class TestAssetNameSettingHandling(AssetsTestCase): + """ + Tests for the 'name' setting in the asset content + """ + def test_asset_name_matches_instance_root(self): + """ + Test if 'name' setting is provided, it should match with the root node. + """ + content = { + 'survey': [ + { + 'type': 'text', + 'name': 'some_text', + 'label': 'Enter some text', + }, + ], + 'settings': {'name': 'custom_root_node_name'} + } + + # Create and deploy the asset + asset = Asset.objects.create( + owner=User.objects.get(username=self.user), + content=content, + asset_type=ASSET_TYPE_SURVEY + ) + asset.deploy(backend='mock', active=True) + + # Get the deployed XForm and parse it + xform = XForm.objects.get(id_string=asset.uid) + parser = XFormInstanceParser(xform.xml, xform.data_dictionary()) + + # Access the first child element of the node + instance_node = parser.get_root_node().getElementsByTagName('instance')[0] + root_element = instance_node.firstChild + + # Assert that the name setting matches the root node name + assert root_element.nodeName == 'custom_root_node_name' + + def test_asset_without_name_setting(self): + """ + Test if 'name' setting is not provided, the root node should fall back + to asset UID + """ + content = { + 'survey': [ + { + 'type': 'text', + 'name': 'some_text', + 'label': 'Enter some text', + }, + ], + # No 'name' setting provided in this case + } + + # Create and deploy the asset + asset = Asset.objects.create( + owner=User.objects.get(username=self.user), + content=content, + asset_type=ASSET_TYPE_SURVEY + ) + asset.deploy(backend='mock', active=True) + + # Get the deployed XForm and parse it + xform = XForm.objects.get(id_string=asset.uid) + parser = XFormInstanceParser(xform.xml, xform.data_dictionary()) + + # Access the first child element of the node + instance_node = parser.get_root_node().getElementsByTagName('instance')[0] + root_element = instance_node.firstChild + + # Assert that the root node name is the asset.uid + assert root_element.nodeName == asset.uid