From d6fbe51ef59ed87d65b3e8d4c8e2d1fb8c068259 Mon Sep 17 00:00:00 2001 From: RandomJo Date: Wed, 30 Jan 2019 15:58:18 -0600 Subject: [PATCH 1/4] Fix rmtree method of S3BotoStorageMixin The listdir function returns two values, one for directory names and one for file names. These are lists of strings and thus do not have a delete method. Instead of trying to delete each array, we loop through them to build keys that we can delete. --- filebrowser_safe/storage.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/filebrowser_safe/storage.py b/filebrowser_safe/storage.py index 88d1d15..3609355 100644 --- a/filebrowser_safe/storage.py +++ b/filebrowser_safe/storage.py @@ -112,9 +112,13 @@ def makedirs(self, name): def rmtree(self, name): name = self._normalize_name(self._clean_name(name)) - dirlist = self.listdir(self._encode_name(name)) - for item in dirlist: - item.delete() + directories, files = self.listdir(self._encode_name(name)) + + for key in files: + self.delete('/'.join([name, key])) + + for dirname in directories: + self.rmtree('/'.join([name, dirname])) class GoogleStorageMixin(StorageMixin): From 6f23b88f7348d06878198bb63c2392266e7b9fc5 Mon Sep 17 00:00:00 2001 From: Tirso Rodriguez Date: Wed, 6 Mar 2019 14:19:28 +0000 Subject: [PATCH 2/4] Fixes issue with old methods in gcs support --- .gitignore | 1 + filebrowser_safe/storage.py | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4d8f39b..994aaf8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ *.pyc *.eggs/ *.egg-info +.idea mezzanine-git/ diff --git a/filebrowser_safe/storage.py b/filebrowser_safe/storage.py index 88d1d15..adc18b8 100644 --- a/filebrowser_safe/storage.py +++ b/filebrowser_safe/storage.py @@ -4,6 +4,7 @@ # PYTHON IMPORTS import os import shutil +import posixpath # DJANGO IMPORTS from django.core.files.move import file_move_safe @@ -133,7 +134,7 @@ def isdir(self, name): return False name = self._normalize_name(self._clean_name(name)) - dirlist = self.bucket.list(self._encode_name(name)) + dirlist = self.listdir(self._encode_name(name)) # Check whether the iterator is empty for item in dirlist: @@ -163,6 +164,32 @@ def makedirs(self, name): def rmtree(self, name): name = self._normalize_name(self._clean_name(name)) - dirlist = self.bucket.list(self._encode_name(name)) + dirlist = self.listdir(self._encode_name(name)) for item in dirlist: item.delete() + + def _clean_name(self, name): + """ + Cleans the name so that Windows style paths work + """ + return clean_name(name) + + +def clean_name(name): + """ + Cleans the name so that Windows style paths work + """ + # Normalize Windows style paths + clean_name = posixpath.normpath(name).replace('\\', '/') + + # os.path.normpath() can strip trailing slashes so we implement + # a workaround here. + if name.endswith('/') and not clean_name.endswith('/'): + # Add a trailing slash as it was stripped. + clean_name = clean_name + '/' + + # Given an empty string, os.path.normpath() will return ., which we don't want + if clean_name == '.': + clean_name = '' + + return clean_name From 3b86e2868b3e0f2e198b7c128ba5ace9058f0038 Mon Sep 17 00:00:00 2001 From: Tirso Rodriguez Date: Sun, 24 Mar 2019 16:03:11 +0000 Subject: [PATCH 3/4] Fix cs specification that is breaking compilemessages command --- filebrowser_safe/locale/cs/LC_MESSAGES/django.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filebrowser_safe/locale/cs/LC_MESSAGES/django.po b/filebrowser_safe/locale/cs/LC_MESSAGES/django.po index ca8b3fc..fb66196 100644 --- a/filebrowser_safe/locale/cs/LC_MESSAGES/django.po +++ b/filebrowser_safe/locale/cs/LC_MESSAGES/django.po @@ -322,7 +322,7 @@ msgstr[1] "%(counter) výsledky" #: templates/filebrowser/include/toolbar.html:9 #, python-format msgid "%(full_result_count)s total" -msgstr "%(full_result_count) celkem" +msgstr "%(full_result_count)s celkem" #: templates/filebrowser/include/search.html:5 msgid "Clear Restrictions" From 18686f56e8b093405eecff266c318a0d6ab171fb Mon Sep 17 00:00:00 2001 From: Wanchao Zhang Date: Thu, 17 Oct 2019 14:56:10 +0800 Subject: [PATCH 4/4] Pre-setting FileObject._is_folder for performance This is especially useful for `filebrowser_safe.views.browse`, in which we already know whether an object is folder or not before initializing the FileObject instance. PS: I am using S3 storage backend, I can observe about 3x performance optimization. --- filebrowser_safe/base.py | 9 ++++++--- filebrowser_safe/views.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/filebrowser_safe/base.py b/filebrowser_safe/base.py index 6955f91..7c2a0ac 100644 --- a/filebrowser_safe/base.py +++ b/filebrowser_safe/base.py @@ -23,7 +23,8 @@ class FileObjectAPI(object): """ A mixin class providing file properties. """ - def __init__(self, path): + def __init__(self, path, is_folder=None): + self._is_folder = is_folder self.head = os.path.dirname(path) self.filename = os.path.basename(path) self.filename_lower = self.filename.lower() @@ -94,6 +95,8 @@ def folder(self): @cached_property def is_folder(self): + if self._is_folder is not None: + return self._is_folder return default_storage.isdir(self.path) @property @@ -121,9 +124,9 @@ class FileObject(FileObjectAPI): where path is a relative path to a storage location. """ - def __init__(self, path): + def __init__(self, path, *args, **kwargs): self.path = path - super(FileObject, self).__init__(path) + super(FileObject, self).__init__(path, *args, **kwargs) @property def name(self): diff --git a/filebrowser_safe/views.py b/filebrowser_safe/views.py index 69bf1d1..2c595a4 100644 --- a/filebrowser_safe/views.py +++ b/filebrowser_safe/views.py @@ -122,7 +122,7 @@ def browse(request): # CREATE FILEOBJECT url_path = "/".join([s.strip("/") for s in [get_directory(), path.replace("\\", "/"), file] if s.strip("/")]) - fileobject = FileObject(url_path) + fileobject = FileObject(url_path, is_folder=file in dir_list) # FILTER / SEARCH