From 73bc1dc91166b757b4d8f72341ef5f75aee82c19 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Tue, 8 Oct 2024 12:21:57 -0300 Subject: [PATCH] Refs #35818 - Added hook to make it easier to customize file extensions parsing --- django/core/files/storage/base.py | 14 +++++--------- tests/file_storage/tests.py | 14 +++++++++++--- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/django/core/files/storage/base.py b/django/core/files/storage/base.py index f8b0e0cdc5..2728e1cd76 100644 --- a/django/core/files/storage/base.py +++ b/django/core/files/storage/base.py @@ -84,15 +84,7 @@ class Storage: "Detected path traversal attempt in '%s'" % dir_name ) validate_file_name(file_name) - # Extract file extensions (.txt, .jpeg, .tar.gz) from the filename - suffixes = pathlib.PurePath(file_name).suffixes - file_ext = "" - # Iterate backwards from the last suffix. Consider suffixes - # shorter than 5 characters to be part of the extension - for index, suffix in enumerate(suffixes[::-1]): - if index > 0 and len(suffix) >= 5: - break - file_ext = suffix + file_ext + file_ext = self.get_filename_extensions(file_name) file_root = file_name.removesuffix(file_ext) # If the filename is not available, generate an alternative # filename until one is available. @@ -122,6 +114,10 @@ class Storage: ) return name + def get_filename_extensions(self, filename): + """Extract all extensions from the filename.""" + return "".join(pathlib.PurePath(filename).suffixes) + def generate_filename(self, filename): """ Validate the filename by calling get_valid_name() and return a filename diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py index 3ebeee22c1..c6b62ef0cc 100644 --- a/tests/file_storage/tests.py +++ b/tests/file_storage/tests.py @@ -738,11 +738,19 @@ class OverwritingStorageTests(FileStorageTests): self.assertEqual(stored_name, "test_l.txt") self.assertEqual(len(stored_name), 10) - def test_file_name_truncation_with_dotted_name(self): + def test_file_name_truncation_with_dotted_name_custom_strategy(self): + class DottedFileNameStorage(FileSystemStorage): + def get_filename_extensions(self, filename): + ext = filename.split(".")[-1] + return f".{ext}" + + storage = DottedFileNameStorage( + location=self.temp_dir, base_url="/test_media_url/", allow_overwrite=True + ) name = "test.long.dotted.name.txt" file = ContentFile(b"content") - stored_name = self.storage.save(name, file, max_length=10) - self.addCleanup(self.storage.delete, stored_name) + stored_name = storage.save(name, file, max_length=10) + self.addCleanup(storage.delete, stored_name) self.assertEqual(stored_name, "test.l.txt") self.assertEqual(len(stored_name), 10)