]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
When a StoragePath is changed, check if related documents require a rename
authorTrenton H <797416+stumpylog@users.noreply.github.com>
Fri, 17 Feb 2023 18:02:19 +0000 (10:02 -0800)
committerTrenton H <797416+stumpylog@users.noreply.github.com>
Sat, 18 Feb 2023 20:19:33 +0000 (12:19 -0800)
docs/advanced_usage.md
src/documents/signals/handlers.py
src/documents/tests/test_file_handling.py

index 61e7eee2014eb1eddb4c0418fc0f5cb3cb398ab2..cd82ab78e2670bd7c88cd5f4e3690b292f8b2374 100644 (file)
@@ -414,13 +414,6 @@ structure as in the previous example above.
     Defining a storage path is optional. If no storage path is defined for a
     document, the global `PAPERLESS_FILENAME_FORMAT` is applied.
 
-!!! warning
-
-    If you adjust the format of an existing storage path, old documents
-    don't get relocated automatically. You need to run the
-    [document renamer](/administration#renamer) to
-    adjust their paths.
-
 ## Celery Monitoring {#celery-monitoring}
 
 The monitoring tool
index cd42c90303ed99e8ddf7daec8cf7422d2962b5e7..3b4021a2ef7f4dcab36fed3adb9395c81d173e9c 100644 (file)
@@ -27,6 +27,7 @@ from ..file_handling import generate_unique_filename
 from ..models import Document
 from ..models import MatchingModel
 from ..models import PaperlessTask
+from ..models import StoragePath
 from ..models import Tag
 
 logger = logging.getLogger("paperless.handlers")
@@ -495,6 +496,16 @@ def update_filename_and_move_files(sender, instance, **kwargs):
             )
 
 
+@receiver(models.signals.post_save, sender=StoragePath)
+def update_document_storage_path(sender, instance, **kwargs):
+    """
+    Triggers when a storage path is changed, running against any documents using
+    the path, and checks to see if they need to be renamed
+    """
+    for document in instance.documents.all():
+        update_filename_and_move_files(None, document)
+
+
 def set_log_entry(sender, document=None, logging_group=None, **kwargs):
 
     ct = ContentType.objects.get(model="document")
index 8d726b339dbe8609914c875b45cd12d99f7fbd19..6b55d9b88f690fec5593bc7c9944a0fb8f30eb93 100644 (file)
@@ -1,9 +1,6 @@
 import datetime
-import hashlib
 import os
-import random
 import tempfile
-import uuid
 from pathlib import Path
 from unittest import mock
 
@@ -16,7 +13,6 @@ from django.utils import timezone
 from ..file_handling import create_source_path_directory
 from ..file_handling import delete_empty_directories
 from ..file_handling import generate_filename
-from ..file_handling import generate_unique_filename
 from ..models import Correspondent
 from ..models import Document
 from ..models import DocumentType
@@ -871,7 +867,7 @@ class TestFileHandlingWithArchive(DirectoriesMixin, TestCase):
         self.assertTrue(os.path.isfile(doc.archive_path))
 
 
-class TestFilenameGeneration(TestCase):
+class TestFilenameGeneration(DirectoriesMixin, TestCase):
     @override_settings(FILENAME_FORMAT="{title}")
     def test_invalid_characters(self):
 
@@ -1036,6 +1032,47 @@ class TestFilenameGeneration(TestCase):
         self.assertEqual(generate_filename(doc_a), "0000002.pdf")
         self.assertEqual(generate_filename(doc_b), "SomeImportantNone/2020-07-25.pdf")
 
+    def test_document_storage_path_changed(self):
+        """
+        GIVEN:
+            - Document with a defined storage path
+        WHEN:
+            - The storage path format is updated
+        THEN:
+            - Document is renamed to the new format
+        """
+        sp = StoragePath.objects.create(path="TestFolder/{created}")
+        document = Document.objects.create(
+            mime_type="application/pdf",
+            created=timezone.make_aware(datetime.datetime(2020, 6, 25, 7, 36, 51, 153)),
+            storage_path=sp,
+        )
+
+        # Ensure that filename is properly generated
+        document.filename = generate_filename(document)
+        self.assertEqual(
+            document.source_path,
+            os.path.join(settings.ORIGINALS_DIR, "TestFolder/2020-06-25.pdf"),
+        )
+
+        # Actually create the file
+        create_source_path_directory(document.source_path)
+        Path(document.source_path).touch()
+        self.assertTrue(os.path.isfile(document.source_path))
+        document.save()
+
+        # Change format
+        sp.path = "NewFolder/{created}"
+        sp.save()
+
+        document.refresh_from_db()
+
+        self.assertEqual(
+            document.source_path,
+            os.path.join(settings.ORIGINALS_DIR, "NewFolder/2020-06-25.pdf"),
+        )
+        self.assertTrue(os.path.isfile(document.source_path))
+
     @override_settings(
         FILENAME_FORMAT="{created_year_short}/{created_month_name_short}/{created_month_name}/{title}",
     )
@@ -1063,28 +1100,3 @@ class TestFilenameGeneration(TestCase):
             checksum="2",
         )
         self.assertEqual(generate_filename(doc), "84/August/Aug/The Title.pdf")
-
-
-def run():
-    doc = Document.objects.create(
-        checksum=str(uuid.uuid4()),
-        title=str(uuid.uuid4()),
-        content="wow",
-    )
-    doc.filename = generate_unique_filename(doc)
-    Path(doc.thumbnail_path).touch()
-    with open(doc.source_path, "w") as f:
-        f.write(str(uuid.uuid4()))
-    with open(doc.source_path, "rb") as f:
-        doc.checksum = hashlib.md5(f.read()).hexdigest()
-
-    with open(doc.archive_path, "w") as f:
-        f.write(str(uuid.uuid4()))
-    with open(doc.archive_path, "rb") as f:
-        doc.archive_checksum = hashlib.md5(f.read()).hexdigest()
-
-    doc.save()
-
-    for i in range(30):
-        doc.title = str(random.randrange(1, 5))
-        doc.save()