From d15815a2b52466a4b8ad2a13ab6f6f72da9b635c Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Thu, 9 Mar 2023 18:23:16 +0100 Subject: [PATCH 01/27] Add support for importing zip archives --- .../tools/imp_exp/unpack_tar_gz_archive.py | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/galaxy/tools/imp_exp/unpack_tar_gz_archive.py b/lib/galaxy/tools/imp_exp/unpack_tar_gz_archive.py index 8fbd0a3aa751..0b630e34de40 100644 --- a/lib/galaxy/tools/imp_exp/unpack_tar_gz_archive.py +++ b/lib/galaxy/tools/imp_exp/unpack_tar_gz_archive.py @@ -1,6 +1,6 @@ #!/usr/bin/env python """ -Unpack a tar or tar.gz archive into a directory. +Unpack a tar, tar.gz or zip archive into a directory. usage: %prog archive_source dest_dir --[url|file] source type, either a URL or a file. @@ -11,6 +11,7 @@ import optparse import os import tarfile +import zipfile from base64 import b64decode from galaxy.files import ConfiguredFileSources @@ -35,11 +36,19 @@ def check_archive(archive_file, dest_dir): Ensure that a tar archive has no absolute paths or relative paths outside the archive. """ - with tarfile.open(archive_file, mode="r") as archive_fp: - for arc_path in archive_fp.getnames(): - assert os.path.normpath(os.path.join(dest_dir, arc_path)).startswith( - dest_dir.rstrip(os.sep) + os.sep - ), f"Archive member would extract outside target directory: {arc_path}" + if zipfile.is_zipfile(archive_file): + with zipfile.ZipFile(archive_file, "r") as archive_fp: + for arc_path in archive_fp.namelist(): + assert not os.path.isabs(arc_path), f"Archive member has absolute path: {arc_path}" + assert not os.path.relpath(arc_path).startswith( + ".." + ), f"Archive member would extract outside target directory: {arc_path}" + else: + with tarfile.open(archive_file, mode="r") as archive_fp: + for arc_path in archive_fp.getnames(): + assert os.path.normpath(os.path.join(dest_dir, arc_path)).startswith( + dest_dir.rstrip(os.sep) + os.sep + ), f"Archive member would extract outside target directory: {arc_path}" return True @@ -47,9 +56,13 @@ def unpack_archive(archive_file, dest_dir): """ Unpack a tar and/or gzipped archive into a destination directory. """ - archive_fp = tarfile.open(archive_file, mode="r") - archive_fp.extractall(path=dest_dir) - archive_fp.close() + if zipfile.is_zipfile(archive_file): + with zipfile.ZipFile(archive_file, "r") as zip_archive: + zip_archive.extractall(path=dest_dir) + else: + archive_fp = tarfile.open(archive_file, mode="r") + archive_fp.extractall(path=dest_dir) + archive_fp.close() def main(options, args): From 092f733a3a6a23ea6cff6922982695378886d4ba Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 10 Mar 2023 10:34:03 +0100 Subject: [PATCH 02/27] Provide getDownloadObjectUrl from STS composable --- client/src/composables/shortTermStorage.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client/src/composables/shortTermStorage.js b/client/src/composables/shortTermStorage.js index 3e34d7226816..8b78cc013737 100644 --- a/client/src/composables/shortTermStorage.js +++ b/client/src/composables/shortTermStorage.js @@ -30,8 +30,13 @@ export function useShortTermStorage() { return prepareObjectDownload(invocationId, "invocations", options); } - function downloadObjectByRequestId(storageRequestId) { + function getDownloadObjectUrl(storageRequestId) { const url = withPrefix(`/api/short_term_storage/${storageRequestId}`); + return url; + } + + function downloadObjectByRequestId(storageRequestId) { + const url = getDownloadObjectUrl(storageRequestId); window.location.assign(url); } @@ -119,5 +124,10 @@ export function useShortTermStorage() { * Whether the download is still being prepared. */ isPreparing: readonly(isPreparing), + /** + * Given a storageRequestId it returns the download URL for that object. + * @param {String} storageRequestId The storage request ID associated to the object to be downloaded + */ + getDownloadObjectUrl, }; } From 1f75b1852f1e9a67f7eac5d3f29784a1d790a3d6 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 10 Mar 2023 10:34:42 +0100 Subject: [PATCH 03/27] Add Copy download link buttons for direct downloads --- .../components/Common/ExportRecordDetails.vue | 24 ++++++++++++++++--- .../components/Common/ExportRecordTable.vue | 13 +++++++++- .../History/Export/HistoryExport.vue | 20 +++++++++++++++- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/client/src/components/Common/ExportRecordDetails.vue b/client/src/components/Common/ExportRecordDetails.vue index 8aa2e7e0cf75..0516de46b05b 100644 --- a/client/src/components/Common/ExportRecordDetails.vue +++ b/client/src/components/Common/ExportRecordDetails.vue @@ -4,10 +4,16 @@ import { BAlert, BCard, BCardTitle } from "bootstrap-vue"; import LoadingSpan from "components/LoadingSpan"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { library } from "@fortawesome/fontawesome-svg-core"; -import { faExclamationCircle, faExclamationTriangle, faCheckCircle, faClock } from "@fortawesome/free-solid-svg-icons"; +import { + faExclamationCircle, + faExclamationTriangle, + faCheckCircle, + faClock, + faLink, +} from "@fortawesome/free-solid-svg-icons"; import { ExportRecordModel } from "./models/exportRecordModel"; -library.add(faExclamationCircle, faExclamationTriangle, faCheckCircle, faClock); +library.add(faExclamationCircle, faExclamationTriangle, faCheckCircle, faClock, faLink); const props = defineProps({ record: { @@ -28,7 +34,7 @@ const props = defineProps({ }, }); -const emit = defineEmits(["onReimport", "onDownload", "onActionMessageDismissed"]); +const emit = defineEmits(["onReimport", "onDownload", "onCopyDownloadLink", "onActionMessageDismissed"]); const title = computed(() => (props.record.isReady ? `Exported` : `Export started`)); const preparingMessage = computed( @@ -43,6 +49,10 @@ function downloadObject() { emit("onDownload", props.record); } +function copyDownloadLink() { + emit("onCopyDownloadLink", props.record); +} + function onMessageDismissed() { emit("onActionMessageDismissed"); } @@ -113,6 +123,14 @@ function onMessageDismissed() { @click="downloadObject"> Download + + +