From b2f1c5a6af6c9d879cd2a317af0e280be5e02d2f Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 14 Sep 2025 19:05:03 -0700 Subject: [PATCH] Enhancement: support custom field values with post document endpoint --- src/documents/serialisers.py | 27 ++++++++++++++ src/documents/tests/test_api_documents.py | 44 +++++++++++++++++++++++ src/documents/views.py | 15 +++++--- 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index c71a856d7..b64fe9fb2 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -1682,6 +1682,12 @@ class PostDocumentSerializer(serializers.Serializer): required=False, ) + custom_fields_w_values = serializers.JSONField( + label="Custom fields with values", + write_only=True, + required=False, + ) + def validate_document(self, document): document_data = document.file.read() mime_type = magic.from_buffer(document_data, mime=True) @@ -1732,6 +1738,27 @@ class PostDocumentSerializer(serializers.Serializer): else: return None + def validate_custom_fields_w_values(self, custom_fields_w_values): + if custom_fields_w_values: + custom_field_serializer = CustomFieldInstanceSerializer() + for field_id, value in custom_fields_w_values.items(): + try: + field = CustomField.objects.get(id=field_id) + except CustomField.DoesNotExist: + raise serializers.ValidationError( + _("Custom field with id %(id)s does not exist") + % { + "id": field_id, + }, + ) + # validate the value using the CustomFieldInstanceSerializer + custom_field_serializer.validate( + { + "field": field, + "value": value, + }, + ) + def validate_created(self, created): # support datetime format for created for backwards compatibility if isinstance(created, datetime): diff --git a/src/documents/tests/test_api_documents.py b/src/documents/tests/test_api_documents.py index 77d099b85..ebdafeb4c 100644 --- a/src/documents/tests/test_api_documents.py +++ b/src/documents/tests/test_api_documents.py @@ -1537,6 +1537,50 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase): overrides.update(new_overrides) self.assertEqual(overrides.custom_fields, {cf.id: None, cf2.id: 123}) + def test_upload_with_custom_field_values(self): + """ + GIVEN: A document with a source file + WHEN: Upload the document with custom fields and values + THEN: Metadata is set correctly + """ + self.consume_file_mock.return_value = celery.result.AsyncResult( + id=str(uuid.uuid4()), + ) + + cf_string = CustomField.objects.create( + name="stringfield", + data_type=CustomField.FieldDataType.STRING, + ) + cf_int = CustomField.objects.create( + name="intfield", + data_type=CustomField.FieldDataType.INT, + ) + + with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f: + response = self.client.post( + "/api/documents/post_document/", + { + "document": f, + "custom_fields_w_values": { + str(cf_string.id): "a string", + str(cf_int.id): 123, + }, + }, + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + self.consume_file_mock.assert_called_once() + + input_doc, overrides = self.get_last_consume_delay_call_args() + + self.assertEqual(input_doc.original_file.name, "simple.pdf") + self.assertEqual(overrides.filename, "simple.pdf") + self.assertEqual( + overrides.custom_fields, + {cf_string.id: "a string", cf_int.id: 123}, + ) + def test_upload_with_webui_source(self): """ GIVEN: A document with a source file diff --git a/src/documents/views.py b/src/documents/views.py index 002cb0eea..55e401a3a 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -1498,6 +1498,9 @@ class PostDocumentView(GenericAPIView): created = serializer.validated_data.get("created") archive_serial_number = serializer.validated_data.get("archive_serial_number") custom_field_ids = serializer.validated_data.get("custom_fields") + custom_fields_w_values = serializer.validated_data.get( + "custom_fields_w_values", + ) from_webui = serializer.validated_data.get("from_webui") t = int(mktime(datetime.now().timetuple())) @@ -1516,6 +1519,13 @@ class PostDocumentView(GenericAPIView): source=DocumentSource.WebUI if from_webui else DocumentSource.ApiUpload, original_file=temp_file_path, ) + custom_fields = None + if custom_fields_w_values: + custom_fields = { + cf_id: value for cf_id, value in custom_fields_w_values.items() + } + elif custom_field_ids: + custom_fields = {cf_id: None for cf_id in custom_field_ids} input_doc_overrides = DocumentMetadataOverrides( filename=doc_name, title=title, @@ -1526,10 +1536,7 @@ class PostDocumentView(GenericAPIView): created=created, asn=archive_serial_number, owner_id=request.user.id, - # TODO: set values - custom_fields={cf_id: None for cf_id in custom_field_ids} - if custom_field_ids - else None, + custom_fields=custom_fields, ) async_task = consume_file.delay(