From 7428ba0c6df2a67abd1b0e372a66d8b5353bdd3c Mon Sep 17 00:00:00 2001 From: mlbonhomme <bonhomme@teklia.com> Date: Thu, 10 Mar 2022 13:46:48 +0000 Subject: [PATCH] don't allow duplicates in metadata_list when creating metadata in bulk --- arkindex/documents/serializers/elements.py | 26 ++++++++++++++ arkindex/documents/tests/test_metadata.py | 42 ++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/arkindex/documents/serializers/elements.py b/arkindex/documents/serializers/elements.py index 19a09447bb..776711a5de 100644 --- a/arkindex/documents/serializers/elements.py +++ b/arkindex/documents/serializers/elements.py @@ -172,6 +172,32 @@ class MetaDataBulkSerializer(serializers.Serializer): super().__init__(*args, **kwargs) self.fields['metadata_list'] = MetaDataBulkItemSerializer(many=True, allow_empty=False, context=self.context) + def make_metadata_tuples(self, meta_list): + tuples_list = [] + for item in meta_list: + item_tuple = ( + item.get('name'), + item.get('type').value, + item.get('value') + ) + tuples_list.append(item_tuple) + return tuples_list + + def validate(self, data): + data = super().validate(data) + request_metadata = self.make_metadata_tuples(data['metadata_list']) + unique_metadata = set(request_metadata) + if len(unique_metadata) != len(request_metadata): + raise ValidationError('Metadata in metadata list must make a unique set.') + names = [item['name'] for item in data['metadata_list']] + types = [item['type'] for item in data['metadata_list']] + filtered_metadata = MetaData.objects.filter(element=self.context['element'].id, name__in=names, type__in=types).values() + existing_metadata = self.make_metadata_tuples(filtered_metadata) + meta_matches = set(request_metadata) & set(existing_metadata) + if meta_matches: + raise ValidationError(f'Metadata {meta_matches} already exist(s) on this element.') + return data + def create(self, validated_data): validated_data['metadata_list'] = MetaData.objects.bulk_create([ MetaData( diff --git a/arkindex/documents/tests/test_metadata.py b/arkindex/documents/tests/test_metadata.py index 248dc5efb6..180ee8ccc1 100644 --- a/arkindex/documents/tests/test_metadata.py +++ b/arkindex/documents/tests/test_metadata.py @@ -967,3 +967,45 @@ class TestMetaData(FixtureAPITestCase): {'name': 'not allowed', 'type': MetaType.Location} ] ) + + def test_bulk_create_metadata_unique(self): + """ + The metadata created with the bulk endpoint must be unique + """ + self.client.force_login(self.user) + with self.assertNumQueries(5): + response = self.client.post( + reverse('api:element-metadata-bulk', kwargs={'pk': str(self.vol.id)}), + data={'metadata_list': [ + {'type': 'location', 'name': 'location', 'value': 'Texas'}, + {'type': 'location', 'name': 'location', 'value': 'Texas'} + ]}, + format='json' + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertDictEqual(response.json(), { + 'non_field_errors': ['Metadata in metadata list must make a unique set.'] + }) + + def test_bulk_create_metadata_no_duplicates(self): + """ + Do not create metadata that already exist on the element + """ + self.client.force_login(self.user) + response_1 = self.client.post( + reverse('api:element-metadata', kwargs={'pk': str(self.vol.id)}), + data={'type': 'location', 'name': 'location', 'value': 'Texas'} + ) + self.assertEqual(response_1.status_code, status.HTTP_201_CREATED) + with self.assertNumQueries(4): + response_2 = self.client.post( + reverse('api:element-metadata-bulk', kwargs={'pk': str(self.vol.id)}), + data={'metadata_list': [ + {'type': 'location', 'name': 'location', 'value': 'Texas'} + ]}, + format='json' + ) + self.assertEqual(response_2.status_code, status.HTTP_400_BAD_REQUEST) + self.assertDictEqual(response_2.json(), { + 'non_field_errors': ["Metadata {('location', 'location', 'Texas')} already exist(s) on this element."] + }) -- GitLab