mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	Refactored delete_empty_directory into try_delete_empty_directories and
implemented feature to ensure, that all created and now empty directories are really deleted
This commit is contained in:
		@@ -294,7 +294,7 @@ class Document(models.Model):
 | 
				
			|||||||
            key = t.name[:delimeter]
 | 
					            key = t.name[:delimeter]
 | 
				
			||||||
            value = t.name[delimeter+1:]
 | 
					            value = t.name[delimeter+1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mydictionary[key] = value
 | 
					            mydictionary[key] = slugify(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return mydictionary
 | 
					        return mydictionary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -302,10 +302,10 @@ class Document(models.Model):
 | 
				
			|||||||
        # Create directory name based on configured format
 | 
					        # Create directory name based on configured format
 | 
				
			||||||
        if settings.PAPERLESS_DIRECTORY_FORMAT is not None:
 | 
					        if settings.PAPERLESS_DIRECTORY_FORMAT is not None:
 | 
				
			||||||
            directory = settings.PAPERLESS_DIRECTORY_FORMAT.format(
 | 
					            directory = settings.PAPERLESS_DIRECTORY_FORMAT.format(
 | 
				
			||||||
                        correspondent=self.correspondent,
 | 
					                        correspondent=slugify(self.correspondent),
 | 
				
			||||||
                        title=self.title,
 | 
					                        title=slugify(self.title),
 | 
				
			||||||
                        created=self.created,
 | 
					                        created=slugify(self.created),
 | 
				
			||||||
                        added=self.added,
 | 
					                        added=slugify(self.added),
 | 
				
			||||||
                        tags=defaultdict(str,
 | 
					                        tags=defaultdict(str,
 | 
				
			||||||
                                         self.many_to_dictionary(self.tags)))
 | 
					                                         self.many_to_dictionary(self.tags)))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
@@ -314,16 +314,16 @@ class Document(models.Model):
 | 
				
			|||||||
        # Create filename based on configured format
 | 
					        # Create filename based on configured format
 | 
				
			||||||
        if settings.PAPERLESS_FILENAME_FORMAT is not None:
 | 
					        if settings.PAPERLESS_FILENAME_FORMAT is not None:
 | 
				
			||||||
            filename = settings.PAPERLESS_FILENAME_FORMAT.format(
 | 
					            filename = settings.PAPERLESS_FILENAME_FORMAT.format(
 | 
				
			||||||
                        correspondent=self.correspondent,
 | 
					                        correspondent=slugify(self.correspondent),
 | 
				
			||||||
                        title=self.title,
 | 
					                        title=slugify(self.title),
 | 
				
			||||||
                        created=self.created,
 | 
					                        created=slugify(self.created),
 | 
				
			||||||
                        added=self.added,
 | 
					                        added=slugify(self.added),
 | 
				
			||||||
                        tags=defaultdict(str,
 | 
					                        tags=defaultdict(str,
 | 
				
			||||||
                                         self.many_to_dictionary(self.tags)))
 | 
					                                         self.many_to_dictionary(self.tags)))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            filename = ""
 | 
					            filename = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        path = os.path.join(slugify(directory), slugify(filename))
 | 
					        path = os.path.join(directory, filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Always append the primary key to guarantee uniqueness of filename
 | 
					        # Always append the primary key to guarantee uniqueness of filename
 | 
				
			||||||
        if len(path) > 0:
 | 
					        if len(path) > 0:
 | 
				
			||||||
@@ -398,13 +398,18 @@ class Document(models.Model):
 | 
				
			|||||||
            self.filename = filename
 | 
					            self.filename = filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def delete_empty_directory(directory):
 | 
					def try_delete_empty_directories(directory):
 | 
				
			||||||
    if len(os.listdir(directory)) == 0:
 | 
					    # Go up in the directory hierarchy and try to delete all directories
 | 
				
			||||||
 | 
					    while directory != Document.filename_to_path(""):
 | 
				
			||||||
 | 
					        # Try to delete the current directory
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            os.rmdir(directory)
 | 
					            os.rmdir(directory)
 | 
				
			||||||
        except os.error:
 | 
					        except os.error:
 | 
				
			||||||
            # Directory not empty
 | 
					            # Directory not empty, no need to go further up
 | 
				
			||||||
            pass
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Cut off actual directory and go one level up
 | 
				
			||||||
 | 
					        directory, tmp = os.path.split(directory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@receiver(models.signals.m2m_changed, sender=Document.tags.through)
 | 
					@receiver(models.signals.m2m_changed, sender=Document.tags.through)
 | 
				
			||||||
@@ -441,7 +446,7 @@ def update_filename(sender, instance, **kwargs):
 | 
				
			|||||||
    # Delete empty directory
 | 
					    # Delete empty directory
 | 
				
			||||||
    old_dir = os.path.dirname(instance.filename)
 | 
					    old_dir = os.path.dirname(instance.filename)
 | 
				
			||||||
    old_path = instance.filename_to_path(old_dir)
 | 
					    old_path = instance.filename_to_path(old_dir)
 | 
				
			||||||
    delete_empty_directory(old_path)
 | 
					    try_delete_empty_directories(old_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    instance.filename = new_filename
 | 
					    instance.filename = new_filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -469,7 +474,7 @@ def delete_files(sender, instance, **kwargs):
 | 
				
			|||||||
    # And remove the directory (if applicable)
 | 
					    # And remove the directory (if applicable)
 | 
				
			||||||
    old_dir = os.path.dirname(instance.filename)
 | 
					    old_dir = os.path.dirname(instance.filename)
 | 
				
			||||||
    old_path = instance.filename_to_path(old_dir)
 | 
					    old_path = instance.filename_to_path(old_dir)
 | 
				
			||||||
    delete_empty_directory(old_path)
 | 
					    try_delete_empty_directories(old_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Log(models.Model):
 | 
					class Log(models.Model):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -145,6 +145,37 @@ class TestDate(TestCase):
 | 
				
			|||||||
                  "/documents/originals/none/none-0000001.pdftest")
 | 
					                  "/documents/originals/none/none-0000001.pdftest")
 | 
				
			||||||
        os.rmdir(settings.MEDIA_ROOT + "/documents/originals/none")
 | 
					        os.rmdir(settings.MEDIA_ROOT + "/documents/originals/none")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @override_settings(MEDIA_ROOT="/tmp/paperless-tests-{}".
 | 
				
			||||||
 | 
					                       format(str(uuid4())[:8]))
 | 
				
			||||||
 | 
					    @override_settings(PAPERLESS_DIRECTORY_FORMAT="{correspondent}/{correspondent}")
 | 
				
			||||||
 | 
					    @override_settings(PAPERLESS_FILENAME_FORMAT="{correspondent}")
 | 
				
			||||||
 | 
					    def test_nested_directory_cleanup(self):
 | 
				
			||||||
 | 
					        document = Document()
 | 
				
			||||||
 | 
					        document.file_type = "pdf"
 | 
				
			||||||
 | 
					        document.storage_type = Document.STORAGE_TYPE_UNENCRYPTED
 | 
				
			||||||
 | 
					        document.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Ensure that filename is properly generated
 | 
				
			||||||
 | 
					        tmp = document.source_filename
 | 
				
			||||||
 | 
					        self.assertEqual(document.generate_source_filename(),
 | 
				
			||||||
 | 
					                         "none/none/none-0000001.pdf")
 | 
				
			||||||
 | 
					        document.create_source_directory()
 | 
				
			||||||
 | 
					        Path(document.source_path).touch()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Check proper handling of files
 | 
				
			||||||
 | 
					        self.assertEqual(os.path.isdir(settings.MEDIA_ROOT +
 | 
				
			||||||
 | 
					                         "/documents/originals/none/none"), True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        document.delete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(os.path.isfile(settings.MEDIA_ROOT +
 | 
				
			||||||
 | 
					                         "/documents/originals/none/none/none-0000001.pdf"), False)
 | 
				
			||||||
 | 
					        self.assertEqual(os.path.isdir(settings.MEDIA_ROOT +
 | 
				
			||||||
 | 
					                         "/documents/originals/none/none"), False)
 | 
				
			||||||
 | 
					        self.assertEqual(os.path.isdir(settings.MEDIA_ROOT +
 | 
				
			||||||
 | 
					                         "/documents/originals/none"), False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @override_settings(MEDIA_ROOT="/tmp/paperless-tests-{}".
 | 
					    @override_settings(MEDIA_ROOT="/tmp/paperless-tests-{}".
 | 
				
			||||||
                       format(str(uuid4())[:8]))
 | 
					                       format(str(uuid4())[:8]))
 | 
				
			||||||
    @override_settings(PAPERLESS_DIRECTORY_FORMAT=None)
 | 
					    @override_settings(PAPERLESS_DIRECTORY_FORMAT=None)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user