]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Enhancement: auto-update document filenames with CF select fields (#8045)
authorshamoon <4887959+shamoon@users.noreply.github.com>
Sun, 27 Oct 2024 23:45:21 +0000 (16:45 -0700)
committerGitHub <noreply@github.com>
Sun, 27 Oct 2024 23:45:21 +0000 (23:45 +0000)
src/documents/signals/handlers.py
src/documents/tests/test_file_handling.py

index 93d201e914cac6d905cd8b00476533c4681073d2..eec6b135e7edad6280e4ee15f384481478eda363 100644 (file)
@@ -29,6 +29,7 @@ from documents.data_models import DocumentMetadataOverrides
 from documents.file_handling import create_source_path_directory
 from documents.file_handling import delete_empty_directories
 from documents.file_handling import generate_unique_filename
+from documents.models import CustomField
 from documents.models import CustomFieldInstance
 from documents.models import Document
 from documents.models import MatchingModel
@@ -364,6 +365,20 @@ class CannotMoveFilesException(Exception):
     pass
 
 
+@receiver(models.signals.post_save, sender=CustomField)
+def update_cf_instance_documents(sender, instance: CustomField, **kwargs):
+    """
+    'Select' custom field instances get their end-user value (e.g. in file names) from the select_options in extra_data,
+    which is contained in the custom field itself. So when the field is changed, we (may) need to update the file names
+    of all documents that have this custom field.
+    """
+    if (
+        instance.data_type == CustomField.FieldDataType.SELECT
+    ):  # Only select fields, for now
+        for cf_instance in instance.fields.all():
+            update_filename_and_move_files(sender, cf_instance)
+
+
 @receiver(models.signals.post_save, sender=CustomFieldInstance)
 @receiver(models.signals.m2m_changed, sender=Document.tags.through)
 @receiver(models.signals.post_save, sender=Document)
index fbe945ae07341112dac68e38257e57121dafaa47..037e47f06268f75db1859f776bac5e6be4577a23 100644 (file)
@@ -527,6 +527,48 @@ class TestFileHandling(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
             self.assertNotEqual(original_modified, doc.modified)
             mock_move.assert_not_called()
 
+    @override_settings(
+        FILENAME_FORMAT="{{title}}_{{custom_fields|get_cf_value('test')}}",
+    )
+    @mock.patch("documents.signals.handlers.update_filename_and_move_files")
+    def test_select_cf_updated(self, m):
+        """
+        GIVEN:
+            - A document with a select type custom field
+        WHEN:
+            - The custom field select options are updated
+        THEN:
+            - The update_filename_and_move_files handler is called and the document filename is updated
+        """
+        cf = CustomField.objects.create(
+            name="test",
+            data_type=CustomField.FieldDataType.SELECT,
+            extra_data={
+                "select_options": ["apple", "banana", "cherry"],
+            },
+        )
+        doc = Document.objects.create(
+            title="document",
+            filename="document.pdf",
+            archive_filename="document.pdf",
+            checksum="A",
+            archive_checksum="B",
+            mime_type="application/pdf",
+        )
+        CustomFieldInstance.objects.create(field=cf, document=doc, value_select=0)
+
+        self.assertEqual(generate_filename(doc), "document_apple.pdf")
+
+        # handler should not have been called
+        self.assertEqual(m.call_count, 0)
+        cf.extra_data = {
+            "select_options": ["aubergine", "banana", "cherry"],
+        }
+        cf.save()
+        self.assertEqual(generate_filename(doc), "document_aubergine.pdf")
+        # handler should have been called
+        self.assertEqual(m.call_count, 1)
+
 
 class TestFileHandlingWithArchive(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
     @override_settings(FILENAME_FORMAT=None)