From 5c83167e19e817de785678b3f68f9ebbe8612399 Mon Sep 17 00:00:00 2001 From: maltaesousa Date: Fri, 29 Oct 2021 18:17:29 +0200 Subject: [PATCH] handle duplicate filenames in zip --- back/api/helpers.py | 28 ++++++++++++++++++++++++---- back/api/tests/test_zip.py | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 back/api/tests/test_zip.py diff --git a/back/api/helpers.py b/back/api/helpers.py index 49e642ad..a678fc73 100644 --- a/back/api/helpers.py +++ b/back/api/helpers.py @@ -75,22 +75,42 @@ def send_geoshop_email(subject, message='', recipient=None, template_name=None, fail_silently=False, ) +def _rename_duplicate_file(filenames_dict, filename): + """ + Keeps track of filenames in a filenames_dict and counts number of + occurences for duplicate filenames returning + the up-to-date filename_dict and an unique filename. + """ + final_name = filename + if filename in filenames_dict: + occurrences = filenames_dict[filename] + 1 + final_name = Path(filename) + final_name = f'{final_name.stem}_{occurrences}{final_name.suffix}' + filenames_dict[filename] = occurrences + else: + filenames_dict[filename] = 0 + return filenames_dict, final_name + def _zip_them_all(full_zip_path, files_list_path): """ - Takes a list of zip paths and brings the content together in a single zip + Takes a list of zip paths and brings the content together in a single zip. + If duplicate names are detected, it will rename the files. """ full_zip_file = zipfile.ZipFile(full_zip_path, 'w', zipfile.ZIP_DEFLATED) - + filenames_dict = {} for file_path in files_list_path: if file_path.endswith(".zip"): zip_file = zipfile.ZipFile('{}/{}'.format(settings.MEDIA_ROOT, file_path), 'r') for unzipped_file in zip_file.namelist(): - full_zip_file.writestr(unzipped_file, zip_file.open(unzipped_file).read()) + filenames_dict, final_name = _rename_duplicate_file(filenames_dict, unzipped_file) + full_zip_file.writestr(final_name, zip_file.open(unzipped_file).read()) + elif file_path != '': + filenames_dict, final_name = _rename_duplicate_file(filenames_dict, Path(file_path).name) full_zip_file.write( '{}/{}'.format(settings.MEDIA_ROOT, file_path), - Path(file_path).name) + final_name) full_zip_file.close() diff --git a/back/api/tests/test_zip.py b/back/api/tests/test_zip.py new file mode 100644 index 00000000..fec13658 --- /dev/null +++ b/back/api/tests/test_zip.py @@ -0,0 +1,24 @@ +from api.helpers import _zip_them_all +from unittest import TestCase +import zipfile +from pathlib import Path + +class ZipTest(TestCase): + """ + Test Zips + """ + + def setUp(self): + self.file = open("files/file.txt", "a") + self.file.write("some data") + self.file.close() + + def test_zip_duplicate_name(self): + zip_file1 = zipfile.ZipFile('files/zip1.zip', 'w', zipfile.ZIP_DEFLATED) + zip_file1.write(self.file.name, Path(self.file.name).name) + zip_file1.close() + zip_file2 = zipfile.ZipFile('files/zip2.zip', 'w', zipfile.ZIP_DEFLATED) + zip_file2.write(self.file.name, Path(self.file.name).name) + zip_file2.close() + + _zip_them_all('files/full_zip.zip', ['zip1.zip', 'zip2.zip', 'file.txt'])