diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index c91b97430..074e6e12f 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -2,12 +2,14 @@ import datetime import math import re import zoneinfo +from typing import Any import magic from celery import states from django.conf import settings from django.contrib.auth.models import Group from django.contrib.auth.models import User +from django.core.validators import URLValidator from django.utils.crypto import get_random_string from django.utils.text import slugify from django.utils.translation import gettext as _ @@ -459,6 +461,14 @@ class CustomFieldInstanceSerializer(serializers.ModelSerializer): def get_value(self, obj: CustomFieldInstance): return obj.value + def run_validation(self, data: Any = ...) -> Any: + # other fields get validated by db + field = CustomField.objects.get(pk=data["field"]) + if field.data_type == CustomField.FieldDataType.URL: + validator = URLValidator() + URLValidator.__call__(validator, data["value"]) + return super().run_validation(data) + class Meta: model = CustomFieldInstance fields = [ diff --git a/src/documents/tests/test_api_custom_fields.py b/src/documents/tests/test_api_custom_fields.py index 274b3ae9c..725bd9254 100644 --- a/src/documents/tests/test_api_custom_fields.py +++ b/src/documents/tests/test_api_custom_fields.py @@ -322,3 +322,63 @@ class TestCustomField(DirectoriesMixin, APITestCase): self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(CustomFieldInstance.objects.count(), 0) self.assertEqual(len(doc.custom_fields.all()), 0) + + def test_custom_field_value_validation(self): + """ + GIVEN: + - Document & custom field exist + WHEN: + - API request to set a field value + THEN: + - HTTP 400 is returned + - No field instance is created or attached to the document + """ + doc = Document.objects.create( + title="WOW", + content="the content", + checksum="123", + mime_type="application/pdf", + ) + custom_field_url = CustomField.objects.create( + name="Test Custom Field URL", + data_type=CustomField.FieldDataType.URL, + ) + custom_field_int = CustomField.objects.create( + name="Test Custom Field INT", + data_type=CustomField.FieldDataType.INT, + ) + + resp = self.client.patch( + f"/api/documents/{doc.id}/", + data={ + "custom_fields": [ + { + "field": custom_field_url.id, + "value": "not a url", + }, + ], + }, + format="json", + ) + + self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(CustomFieldInstance.objects.count(), 0) + self.assertEqual(len(doc.custom_fields.all()), 0) + + self.assertRaises( + Exception, + self.client.patch, + f"/api/documents/{doc.id}/", + data={ + "custom_fields": [ + { + "field": custom_field_int.id, + "value": "not an int", + }, + ], + }, + format="json", + ) + + self.assertEqual(CustomFieldInstance.objects.count(), 0) + self.assertEqual(len(doc.custom_fields.all()), 0)