diff --git a/arkindex/documents/models.py b/arkindex/documents/models.py index e9d13d9e2d9294f8a3a8d961b709320c94f282f3..dbd019c2abd2ea8cfaf0bfd20d5d2c07cd448e09 100644 --- a/arkindex/documents/models.py +++ b/arkindex/documents/models.py @@ -625,6 +625,7 @@ class MetaType(Enum): # Element's original structure reference (intended to be indexed) Reference = 'reference' Numeric = 'numeric' + URL = 'url' class AllowedMetaData(models.Model): diff --git a/arkindex/documents/serializers/elements.py b/arkindex/documents/serializers/elements.py index 0a6c2a8a1e8733da18bb0a57688ee74f4572f173..1c202d91c06a3c9406a6c6ec2ede9123a5658211 100644 --- a/arkindex/documents/serializers/elements.py +++ b/arkindex/documents/serializers/elements.py @@ -4,6 +4,8 @@ from collections import defaultdict from uuid import UUID from django.contrib.gis.geos import LinearRing +from django.core.exceptions import ValidationError as DjangoValidationError +from django.core.validators import URLValidator from django.db import transaction from django.utils.functional import cached_property from drf_spectacular.utils import extend_schema_field @@ -83,6 +85,7 @@ class MetaDataBulkItemSerializer(MetaDataLightSerializer): # Those can be None if someone messed up their input; DRF will catch it itself afterwards, so we ignore None. meta_type = data.get('type', self.instance.type if self.instance else None) value = data.get('value', self.instance.value if self.instance else None) + if meta_type == MetaType.Numeric and value is not None: try: # Python allows _ to separate numbers (123_456.789_101), but Postgres does not, so we forbid them. @@ -94,6 +97,15 @@ class MetaDataBulkItemSerializer(MetaDataLightSerializer): raise serializers.ValidationError({ 'value': ['The value of a numeric metadata should be a valid floating-point number.'] }) + + if meta_type == MetaType.URL and value is not None: + try: + URLValidator(schemes=['http', 'https'])(value) + except DjangoValidationError: + raise serializers.ValidationError({ + 'value': ['The value of a URL metadata must be a valid HTTP or HTTPS URL.'] + }) + return data diff --git a/arkindex/documents/tests/test_metadata.py b/arkindex/documents/tests/test_metadata.py index 109ea852bf8ed0cb860342c917451cd7b9db813e..e906d0fb95e011b17e54f5ecc7a9dff7605a59c7 100644 --- a/arkindex/documents/tests/test_metadata.py +++ b/arkindex/documents/tests/test_metadata.py @@ -586,6 +586,34 @@ class TestMetaData(FixtureAPITestCase): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertDictEqual(response.json(), {'value': ['The value of a numeric metadata should be a valid floating-point number.']}) + def test_create_url_metadata(self): + self.client.force_login(self.superuser) + response = self.client.post( + reverse('api:element-metadata', kwargs={'pk': str(self.vol.id)}), + data={'type': 'url', 'name': 'blah', 'value': 'http://nowhere.com'} + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + md = self.vol.metadatas.get(type=MetaType.URL, name='blah') + self.assertEqual(md.value, 'http://nowhere.com') + + def test_create_url_metadata_invalid(self): + self.client.force_login(self.superuser) + response = self.client.post( + reverse('api:element-metadata', kwargs={'pk': str(self.vol.id)}), + data={'type': 'url', 'name': 'blah', 'value': 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertDictEqual(response.json(), {'value': ['The value of a URL metadata must be a valid HTTP or HTTPS URL.']}) + + def test_create_url_metadata_scheme(self): + self.client.force_login(self.superuser) + response = self.client.post( + reverse('api:element-metadata', kwargs={'pk': str(self.vol.id)}), + data={'type': 'url', 'name': 'blah', 'value': 'git+https://gitlab.com/arkindex/backend.git'} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertDictEqual(response.json(), {'value': ['The value of a URL metadata must be a valid HTTP or HTTPS URL.']}) + def test_bulk_create_metadata_verified(self): response = self.client.post(reverse('api:element-metadata-bulk', kwargs={'pk': str(self.vol.id)})) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)