This is an automated email from the ASF dual-hosted git repository. machristie pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/airavata-django-portal-sdk.git
commit c0baca904a945a0ba87d56a98ab36c8ebe7e51db Author: Marcus Christie <[email protected]> AuthorDate: Fri Nov 19 17:38:57 2021 -0500 AIRAVATA-3542 rename files matching include patterns --- airavata_django_portal_sdk/serializers.py | 10 ++++++++-- airavata_django_portal_sdk/views.py | 28 ++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/airavata_django_portal_sdk/serializers.py b/airavata_django_portal_sdk/serializers.py index e86d010..7348c0c 100644 --- a/airavata_django_portal_sdk/serializers.py +++ b/airavata_django_portal_sdk/serializers.py @@ -6,7 +6,13 @@ class FilenamePatternSerializer(serializers.Serializer): class IncludeFilenamePatternSerializer(FilenamePatternSerializer): - rename = serializers.CharField(required=False) + rename = serializers.CharField( + required=False, + help_text=""" + New name of matching file. Can be a pattern where $root is the original + filename without the extension and $ext is the extension including the + leading period. + """) class ExperimentDownloadSerializer(serializers.Serializer): @@ -18,4 +24,4 @@ class ExperimentDownloadSerializer(serializers.Serializer): class MultiExperimentDownloadSerializer(serializers.Serializer): experiments = ExperimentDownloadSerializer(many=True) - # TODO: filename parameter? + filename = serializers.CharField(default=None) diff --git a/airavata_django_portal_sdk/views.py b/airavata_django_portal_sdk/views.py index 4c697b6..d785aa7 100644 --- a/airavata_django_portal_sdk/views.py +++ b/airavata_django_portal_sdk/views.py @@ -4,6 +4,7 @@ import os import tempfile import uuid import zipfile +from string import Template from django.core.exceptions import ObjectDoesNotExist from django.http import FileResponse, Http404 @@ -116,7 +117,8 @@ def download_experiments(request, download_id=None): elif request.method == 'GET' and download_id is not None: download_key = f"download_experiments:{download_id}" if download_key in request.session: - experiments = request.session[download_key]['experiments'] + download_spec = request.session[download_key] + experiments = download_spec['experiments'] fp = tempfile.TemporaryFile() with zipfile.ZipFile(fp, 'w', compression=zipfile.ZIP_DEFLATED) as zf: for experiment in experiments: @@ -129,7 +131,9 @@ def download_experiments(request, download_id=None): zipfile_prefix=os.path.join(get_valid_filename(experiment_model.experimentName), path), includes=experiment['includes'], excludes=experiment['excludes']) - filename = "experiments.zip" + filename = download_spec.get("filename") + if filename is None: + filename = "experiments.zip" fp.seek(0) # FileResponse will automatically close the temporary file return FileResponse(fp, as_attachment=True, filename=filename) @@ -153,10 +157,10 @@ def _add_directory_to_zipfile(request, zf, path, directory=""): def _add_experiment_directory_to_zipfile(request, zf, experiment_id, path, directory="", zipfile_prefix="", includes=None, excludes=None): directories, files = user_storage.list_experiment_dir(request, experiment_id, os.path.join(path, directory)) for file in files: - matches = _matches_filters(file['name'], includes=includes, excludes=excludes) + matches, rename = _matches_filters(file['name'], includes=includes, excludes=excludes) if matches: o = user_storage.open_file(request, data_product_uri=file['data-product-uri']) - zf.writestr(os.path.join(zipfile_prefix, directory, file['name']), o.read()) + zf.writestr(os.path.join(zipfile_prefix, directory, rename if rename is not None else file['name']), o.read()) if os.path.getsize(zf.filename) > MAX_DOWNLOAD_ZIPFILE_SIZE: raise Exception(f"Zip file size exceeds max of {MAX_DOWNLOAD_ZIPFILE_SIZE} bytes") for d in directories: @@ -166,15 +170,23 @@ def _add_experiment_directory_to_zipfile(request, zf, experiment_id, path, direc def _matches_filters(filename, includes=None, excludes=None): + """Return as a tuple True if matching and a new name for the file if renamed.""" # excludes take precedence if excludes is not None and len(excludes) > 0: for exclude in excludes: if fnmatch.fnmatch(filename, exclude['pattern']): - return False + return False, None # if there are no include patterns, default to include all if includes is None or len(includes) == 0: - return True + return True, None for include in includes: if fnmatch.fnmatch(filename, include['pattern']): - return True - return False + rename = include.get('rename') + if rename: + root, ext = os.path.splitext(filename) + template = Template(rename) + new_filename = template.safe_substitute(root=root, ext=ext) + return True, new_filename + else: + return True, None + return False, None
