core/models: refactor SithFile moving and add methods to manage filesystem

Signed-off-by: Skia <skia@libskia.so>
This commit is contained in:
Skia
2018-03-20 22:09:27 +01:00
parent e9e51d34d3
commit 0d3c34c155
4 changed files with 161 additions and 18 deletions

View File

@ -759,25 +759,72 @@ class SithFile(models.Model):
self.save()
def move_to(self, parent):
"""Move a file to somewhere else"""
"""
Move a file to a new parent.
`parent` must be a SithFile with the `is_folder=True` property. Otherwise, this function doesn't change
anything.
This is done only at the DB level, so that it's very fast for the user. Indeed, this function doesn't modify
SithFiles recursively, so it stays efficient even with top-level folders.
"""
if not parent.is_folder:
return
import shutil
import os
with transaction.atomic():
if self.is_folder:
old_file_name = self.get_full_path()
else:
old_file_name = self.file.name
self.parent = parent
self.save()
if self.is_folder:
for c in self.children.all():
c.move_to(self)
shutil.rmtree(os.path.join(settings.MEDIA_ROOT, old_file_name))
else:
self.file.save(name=self.name, content=self.file)
os.remove(os.path.join(settings.MEDIA_ROOT, old_file_name))
self.parent = parent
self.clean()
self.save()
def _repair_fs(self):
"""
This function rebuilds recursively the filesystem as it should be
regarding the DB tree.
"""
if self.is_folder:
for c in self.children.all():
c._repair_fs()
return
else:
import os
# First get future parent path and the old file name
# Prepend "." so that we match all relative handling of Django's
# file storage
parent_path = "." + self.parent.get_full_path()
parent_full_path = settings.MEDIA_ROOT + parent_path
print("Parent full path: %s" % parent_full_path)
os.makedirs(parent_full_path, exist_ok=True)
old_path = self.file.name # Should be relative: "./users/skia/bleh.jpg"
new_path = "." + self.get_full_path()
print("Old path: %s " % old_path)
print("New path: %s " % new_path)
# Make this atomic, so that a FS problem rolls back the DB change
with transaction.atomic():
# Set the new filesystem path
self.file.name = new_path
self.save()
print("New file path: %s " % self.file.path)
# Really move at the FS level
if os.path.exists(parent_full_path):
os.rename(settings.MEDIA_ROOT + old_path, settings.MEDIA_ROOT + new_path)
# Empty directories may remain, but that's not really a
# problem, and that can be solved with a simple shell
# command: `find . -type d -empty -delete`
def _check_path_consistence(self):
file_path = str(self.file)
db_path = ".%s" % self.get_full_path()
if file_path != db_path:
print("%s: " % self.id, end='')
print("file path: %s" % file_path, end='')
print(" db path: %s" % db_path)
return False
else:
return True
def _check_fs(self):
if self.is_folder:
for c in self.children.all():
c._check_fs()
return
else:
self._check_path_consistence()
def __getattribute__(self, attr):
if attr == "is_file":