From 3401f15720f13d399024f76bef23f66e9f5c4948 Mon Sep 17 00:00:00 2001 From: Olivier Leger Date: Mon, 13 Jan 2025 14:21:53 -0500 Subject: [PATCH] Handle Settings sheet name --- kpi/mixins/xls_exportable.py | 4 +-- kpi/serializers/v2/deployment.py | 11 +++---- kpi/tests/api/v2/test_api_assets.py | 46 ++++++++++++++++++++++++++--- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/kpi/mixins/xls_exportable.py b/kpi/mixins/xls_exportable.py index 14c0ba7825..76d08d57fc 100644 --- a/kpi/mixins/xls_exportable.py +++ b/kpi/mixins/xls_exportable.py @@ -14,9 +14,7 @@ class XlsExportableMixin: - def ordered_xlsform_content(self, - kobo_specific_types=False, - append=None): + def ordered_xlsform_content(self, kobo_specific_types=False, append=None): # currently, this method depends on "FormpackXLSFormUtilsMixin" content = copy.deepcopy(self.content) if append: diff --git a/kpi/serializers/v2/deployment.py b/kpi/serializers/v2/deployment.py index 1bd57729c1..da48c8eef5 100644 --- a/kpi/serializers/v2/deployment.py +++ b/kpi/serializers/v2/deployment.py @@ -1,7 +1,7 @@ -# coding: utf-8 from django.conf import settings from pyxform.errors import PyXFormError from rest_framework import serializers +from xlsxwriter.exceptions import DuplicateWorksheetName from .asset import AssetSerializer @@ -16,8 +16,9 @@ class DeploymentSerializer(serializers.Serializer): def _raise_unless_current_version(asset, validated_data): # Stop if the requester attempts to deploy any version of the asset # except the current one - if 'version_id' in validated_data and \ - validated_data['version_id'] != str(asset.version_id): + if 'version_id' in validated_data and validated_data[ + 'version_id' + ] != str(asset.version_id): raise NotImplementedError( 'Only the current version_id can be deployed') @@ -35,8 +36,8 @@ def create(self, validated_data): # 'deployed' boolean value try: asset.deploy(backend=backend_id, active=validated_data.get('active', False)) - except PyXFormError as e: - raise serializers.ValidationError({'error': (f'ODK Validation Error: {e}')}) + except (DuplicateWorksheetName, PyXFormError) as e: + raise serializers.ValidationError({'error': str(e)}) return asset.deployment def update(self, instance, validated_data): diff --git a/kpi/tests/api/v2/test_api_assets.py b/kpi/tests/api/v2/test_api_assets.py index fa60d507d5..708df0b9d8 100644 --- a/kpi/tests/api/v2/test_api_assets.py +++ b/kpi/tests/api/v2/test_api_assets.py @@ -1862,10 +1862,48 @@ def test_asset_deployment_validation_error(self): self.assertEqual(deploy_response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( deploy_response.data['error'], - ( - 'ODK Validation Error: ' - "The survey element named 'Enter_an_int_number' has no label or hint." - ), + "The survey element named 'Enter_an_int_number' has no label or hint.", + ) + + def test_asset_deployment_with_sheet_name_Settings(self): # noqa + content = { + 'schema': '1', + 'survey': [ + { + 'name': 'Enter_a_float_number', + 'type': 'decimal', + 'label': ['Enter a float number'], + 'required': False, + }, + ], + 'choices': [], + 'settings': {}, + 'Settings': [], # simulate sheet name called `Settings` on import + } + assets_url = reverse(self._get_endpoint('asset-list')) + asset_response = self.client.post( + assets_url, + {'content': content, 'asset_type': 'survey'}, + format='json', + ) + asset = Asset.objects.get(uid=asset_response.data.get('uid')) + + deployment_url = reverse( + self._get_endpoint('asset-deployment'), kwargs={'uid': asset.uid} + ) + + deploy_response = self.client.post( + deployment_url, + { + 'backend': 'mock', + 'active': True, + }, + ) + + assert deploy_response.status_code == status.HTTP_400_BAD_REQUEST + assert ( + "Sheetname 'Settings', with case ignored, is already in use" + in deploy_response.data['error'] ) @patch('kpi.views.v2.asset.ProjectHistoryLog.create_from_deployment_request')