diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index add3610af..aaded56fe 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -1829,18 +1829,27 @@ class BulkEditSerializer( f"Some custom fields in {name} don't exist or were specified twice.", ) - if isinstance(custom_fields, dict): - custom_field_map = CustomField.objects.in_bulk(ids) - for raw_field_id, value in custom_fields.items(): - field = custom_field_map.get(int(raw_field_id)) - if ( - field is not None - and field.data_type == CustomField.FieldDataType.DOCUMENTLINK - and value is not None - ): - if not isinstance(value, list): - raise serializers.ValidationError("Value must be a list") - validate_documentlink_targets(self.user, value) + def _validate_custom_field_values(self, custom_fields, name): + if not isinstance(custom_fields, dict): + return custom_fields + + validated = {} + errors = {} + for raw_field_id, value in custom_fields.items(): + field_id = int(raw_field_id) + validator = CustomFieldInstanceSerializer( + data={"field": field_id, "value": value}, + context=self.context, + ) + if validator.is_valid(): + validated[field_id] = validator.validated_data["value"] + else: + errors[str(field_id)] = validator.errors + + if errors: + raise serializers.ValidationError({name: errors}) + + return validated def validate_method(self, method): if method == "set_correspondent": @@ -1944,6 +1953,10 @@ class BulkEditSerializer( parameters["add_custom_fields"], "add_custom_fields", ) + parameters["add_custom_fields"] = self._validate_custom_field_values( + parameters["add_custom_fields"], + "add_custom_fields", + ) else: raise serializers.ValidationError("add_custom_fields not specified") diff --git a/src/documents/tests/test_api_bulk_edit.py b/src/documents/tests/test_api_bulk_edit.py index e4272e78f..dd62f0c74 100644 --- a/src/documents/tests/test_api_bulk_edit.py +++ b/src/documents/tests/test_api_bulk_edit.py @@ -343,9 +343,33 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase): m.assert_called_once() args, kwargs = m.call_args self.assertListEqual(args[0], [self.doc1.id, self.doc3.id]) - self.assertEqual(kwargs["add_custom_fields"], {str(self.cf1.id): "foo"}) + self.assertEqual(kwargs["add_custom_fields"], {self.cf1.id: "foo"}) self.assertEqual(kwargs["remove_custom_fields"], [self.cf2.id]) + @mock.patch("documents.serialisers.bulk_edit.modify_custom_fields") + def test_api_modify_custom_fields_rejects_invalid_value(self, m) -> None: + self.setup_mock(m, "modify_custom_fields") + + response = self.client.post( + "/api/documents/bulk_edit/", + json.dumps( + { + "documents": [self.doc1.id], + "method": "modify_custom_fields", + "parameters": { + "add_custom_fields": {self.cf1.id: "x" * 129}, + "remove_custom_fields": [], + }, + }, + ), + content_type="application/json", + ) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("add_custom_fields", response.data) + self.assertIn(str(self.cf1.id), response.data["add_custom_fields"]) + m.assert_not_called() + @mock.patch("documents.serialisers.bulk_edit.modify_custom_fields") def test_api_modify_custom_fields_invalid_params(self, m) -> None: """