From f69daa48f2d2d674941f888950b7bf2c0df08753 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Wed, 30 Sep 2020 12:15:51 +0200 Subject: [PATCH 01/19] Handle resend_activation_email gracefully without session Bots keep hitting this and are causing https://sentry.galaxyproject.org/sentry/main/issues/298051/: ``` AttributeError: 'NoneType' object has no attribute 'email' File "galaxy/web/framework/middleware/sentry.py", line 43, in __call__ iterable = self.application(environ, start_response) File "/cvmfs/main.galaxyproject.org/venv/lib/python3.6/site-packages/paste/recursive.py", line 85, in __call__ return self.application(environ, start_response) File "galaxy/web/framework/middleware/statsd.py", line 33, in __call__ req = self.application(environ, start_response) File "/cvmfs/main.galaxyproject.org/venv/lib/python3.6/site-packages/paste/httpexceptions.py", line 640, in __call__ return self.application(environ, start_response) File "galaxy/web/framework/base.py", line 141, in __call__ return self.handle_request(environ, start_response) File "galaxy/web/framework/base.py", line 220, in handle_request body = method(trans, **kwargs) File "galaxy/webapps/galaxy/controllers/user.py", line 191, in resend_verification message, status = self.resend_activation_email(trans, None, None) File "galaxy/webapps/galaxy/controllers/user.py", line 204, in resend_activation_email email = trans.user.email ``` --- lib/galaxy/webapps/galaxy/controllers/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index 4eefb7eb315..58007f20bc0 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -200,7 +200,7 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesApiKeysMixin): """ if email is None: # User is coming from outside registration form, load email from trans if not trans.user: - trans.show_error_message("No session found, cannot send activation email.") + return "No session found, cannot send activation email.", None email = trans.user.email if username is None: # User is coming from outside registration form, load email from trans username = trans.user.username From a0e467f95f966552ef9c3c61693a04e88f8182fe Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Wed, 30 Sep 2020 12:23:28 +0200 Subject: [PATCH 02/19] Strip trailing ``/`` from tool_id Might be happening on redirect (that didn't happen for a quick test with the ENA, but I don't think this hurts). Fixes https://sentry.galaxyproject.org/sentry/main/issues/266808/: ``` data_source_redirect called with tool id 'ebi_sra_main/' but no such tool exists ``` --- lib/galaxy/webapps/galaxy/controllers/tool_runner.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/galaxy/webapps/galaxy/controllers/tool_runner.py b/lib/galaxy/webapps/galaxy/controllers/tool_runner.py index d7df059f86e..51f77266c40 100644 --- a/lib/galaxy/webapps/galaxy/controllers/tool_runner.py +++ b/lib/galaxy/webapps/galaxy/controllers/tool_runner.py @@ -47,6 +47,9 @@ class ToolRunner(BaseUIController): # tool id not available, redirect to main page if tool_id is None: return trans.response.send_redirect(url_for(controller='root', action='welcome')) + if tool_id.endswith('/'): + # Probably caused by a redirect + tool_id = tool_id[:-1] tool = self.__get_tool(tool_id) # tool id is not matching, display an error if not tool: From 177cb604d3868fb8c12ceec8c4dd408d6500440a Mon Sep 17 00:00:00 2001 From: Simon Bray Date: Tue, 29 Sep 2020 19:21:47 +0200 Subject: [PATCH 03/19] allow copying datasets rather than uploading in StagingInterface --- lib/galaxy/tool_util/client/staging.py | 10 ++++++++++ lib/galaxy/tool_util/cwl/util.py | 14 ++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/tool_util/client/staging.py b/lib/galaxy/tool_util/client/staging.py index 895ad810b43..edbd9dc142b 100644 --- a/lib/galaxy/tool_util/client/staging.py +++ b/lib/galaxy/tool_util/client/staging.py @@ -200,6 +200,15 @@ class StagingInterace(object): payload["files_0|url_paste"] = content return self._tools_post(payload) + # To be used when datasets are already available and can be copied instead of uploaded + def copy_func(dataset_id): + copy_payload = { + 'content': dataset_id, + 'source': 'hda', + 'type': 'dataset' + } + return self._post('histories/{}/contents'.format(history_id), payload=copy_payload) + def create_collection_func(element_identifiers, collection_type): payload = { "name": "dataset collection", @@ -230,6 +239,7 @@ class StagingInterace(object): job, job_dir, upload, + copy_func, create_collection_func, tool_or_workflow, ) diff --git a/lib/galaxy/tool_util/cwl/util.py b/lib/galaxy/tool_util/cwl/util.py index 990636db2c4..827eceef3d7 100644 --- a/lib/galaxy/tool_util/cwl/util.py +++ b/lib/galaxy/tool_util/cwl/util.py @@ -84,7 +84,7 @@ def path_or_uri_to_uri(path_or_uri): def galactic_job_json( - job, test_data_directory, upload_func, collection_create_func, tool_or_workflow="workflow" + job, test_data_directory, upload_func, copy_func, collection_create_func, tool_or_workflow="workflow" ): """Adapt a CWL job object to the Galaxy API. @@ -145,6 +145,7 @@ def galactic_job_json( is_file = item_class == "File" is_directory = item_class == "Directory" is_collection = item_class == "Collection" # Galaxy extension. + is_galaxy_id = item_class == "GalaxyID" # Galaxy dataset/collection ID. if force_to_file: if is_file: @@ -167,6 +168,8 @@ def galactic_job_json( return replacement_directory(value) elif is_collection: return replacement_collection(value) + elif is_galaxy_id: + return replacement_galaxy_id(value) else: return replacement_record(value) @@ -287,6 +290,12 @@ def galactic_job_json( hdca_id = collection["id"] return {"src": "hdca", "id": hdca_id} + def replacement_galaxy_id(value): + response = copy_func(value['location']) + target = FileLiteralTarget(contents=None) + datasets.append((response, target)) + return {"src": "hda", "id": value['location']} + def replacement_record(value): collection_element_identifiers = [] for record_key, record_value in value.items(): @@ -328,9 +337,10 @@ def _ensure_file_exists(file_path): class FileLiteralTarget: - def __init__(self, contents, **kwargs): + def __init__(self, contents, path=None, **kwargs): self.contents = contents self.properties = kwargs + self.path = path def __str__(self): return "FileLiteralTarget[path={}] with {}".format(self.path, self.properties) From cb14ce8b60707fc5552ce92e13469fe09607d081 Mon Sep 17 00:00:00 2001 From: Simon Bray Date: Wed, 30 Sep 2020 10:47:58 +0200 Subject: [PATCH 04/19] remove copy_func, appears unnecessary --- lib/galaxy/tool_util/client/staging.py | 10 ---------- lib/galaxy/tool_util/cwl/util.py | 17 +++++++++-------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/lib/galaxy/tool_util/client/staging.py b/lib/galaxy/tool_util/client/staging.py index edbd9dc142b..895ad810b43 100644 --- a/lib/galaxy/tool_util/client/staging.py +++ b/lib/galaxy/tool_util/client/staging.py @@ -200,15 +200,6 @@ class StagingInterace(object): payload["files_0|url_paste"] = content return self._tools_post(payload) - # To be used when datasets are already available and can be copied instead of uploaded - def copy_func(dataset_id): - copy_payload = { - 'content': dataset_id, - 'source': 'hda', - 'type': 'dataset' - } - return self._post('histories/{}/contents'.format(history_id), payload=copy_payload) - def create_collection_func(element_identifiers, collection_type): payload = { "name": "dataset collection", @@ -239,7 +230,6 @@ class StagingInterace(object): job, job_dir, upload, - copy_func, create_collection_func, tool_or_workflow, ) diff --git a/lib/galaxy/tool_util/cwl/util.py b/lib/galaxy/tool_util/cwl/util.py index 827eceef3d7..427deb0f074 100644 --- a/lib/galaxy/tool_util/cwl/util.py +++ b/lib/galaxy/tool_util/cwl/util.py @@ -84,7 +84,7 @@ def path_or_uri_to_uri(path_or_uri): def galactic_job_json( - job, test_data_directory, upload_func, copy_func, collection_create_func, tool_or_workflow="workflow" + job, test_data_directory, upload_func, collection_create_func, tool_or_workflow="workflow" ): """Adapt a CWL job object to the Galaxy API. @@ -145,7 +145,7 @@ def galactic_job_json( is_file = item_class == "File" is_directory = item_class == "Directory" is_collection = item_class == "Collection" # Galaxy extension. - is_galaxy_id = item_class == "GalaxyID" # Galaxy dataset/collection ID. + # is_galaxy_id = item_class == "GalaxyID" # Galaxy dataset/collection ID. if force_to_file: if is_file: @@ -168,12 +168,14 @@ def galactic_job_json( return replacement_directory(value) elif is_collection: return replacement_collection(value) - elif is_galaxy_id: - return replacement_galaxy_id(value) + # elif is_galaxy_id: + # return replacement_galaxy_id(value) else: return replacement_record(value) def replacement_file(value): + if value.get('galaxy_id'): + return replacement_galaxy_id(value) file_path = value.get("location", None) or value.get("path", None) # format to match output definitions in tool, where did filetype come from? filetype = value.get("filetype", None) or value.get("format", None) @@ -281,6 +283,8 @@ def galactic_job_json( return collection_element_identifiers def replacement_collection(value): + if value.get('galaxy_id'): + return replacement_galaxy_id(value) assert "collection_type" in value collection_type = value["collection_type"] elements = to_elements(value, collection_type) @@ -291,10 +295,7 @@ def galactic_job_json( return {"src": "hdca", "id": hdca_id} def replacement_galaxy_id(value): - response = copy_func(value['location']) - target = FileLiteralTarget(contents=None) - datasets.append((response, target)) - return {"src": "hda", "id": value['location']} + return {"src": "hda", "id": value['galaxy_id']} def replacement_record(value): collection_element_identifiers = [] From 7dceabe22c0eeaf5429ed23ea9c76890fb881d06 Mon Sep 17 00:00:00 2001 From: Simon Bray Date: Wed, 30 Sep 2020 14:25:22 +0200 Subject: [PATCH 05/19] tidy --- lib/galaxy/tool_util/cwl/util.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/galaxy/tool_util/cwl/util.py b/lib/galaxy/tool_util/cwl/util.py index 427deb0f074..a4605653f18 100644 --- a/lib/galaxy/tool_util/cwl/util.py +++ b/lib/galaxy/tool_util/cwl/util.py @@ -145,7 +145,6 @@ def galactic_job_json( is_file = item_class == "File" is_directory = item_class == "Directory" is_collection = item_class == "Collection" # Galaxy extension. - # is_galaxy_id = item_class == "GalaxyID" # Galaxy dataset/collection ID. if force_to_file: if is_file: @@ -168,14 +167,12 @@ def galactic_job_json( return replacement_directory(value) elif is_collection: return replacement_collection(value) - # elif is_galaxy_id: - # return replacement_galaxy_id(value) else: return replacement_record(value) def replacement_file(value): if value.get('galaxy_id'): - return replacement_galaxy_id(value) + return {"src": "hda", "id": value['galaxy_id']} file_path = value.get("location", None) or value.get("path", None) # format to match output definitions in tool, where did filetype come from? filetype = value.get("filetype", None) or value.get("format", None) @@ -284,7 +281,7 @@ def galactic_job_json( def replacement_collection(value): if value.get('galaxy_id'): - return replacement_galaxy_id(value) + return {"src": "hdca", "id": value['galaxy_id']} assert "collection_type" in value collection_type = value["collection_type"] elements = to_elements(value, collection_type) @@ -294,9 +291,6 @@ def galactic_job_json( hdca_id = collection["id"] return {"src": "hdca", "id": hdca_id} - def replacement_galaxy_id(value): - return {"src": "hda", "id": value['galaxy_id']} - def replacement_record(value): collection_element_identifiers = [] for record_key, record_value in value.items(): From 276d8dce229d1ddb7b312c77aee19857caebb58e Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Wed, 30 Sep 2020 16:26:49 -0400 Subject: [PATCH 06/19] Pin pytest < 6.1 for now (backport) --- packages/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/test.sh b/packages/test.sh index 2f7a62af826..c7f702fb6ea 100755 --- a/packages/test.sh +++ b/packages/test.sh @@ -14,7 +14,7 @@ TEST_ENV_DIR=${TEST_ENV_DIR:-$(mktemp -d -t gxpkgtestenvXXXXXX)} virtualenv -p "$TEST_PYTHON" "$TEST_ENV_DIR" . "${TEST_ENV_DIR}/bin/activate" -pip install pytest +pip install "pytest<6.1" # ensure ordered by dependency dag PACKAGE_DIRS=( From 5ad534295300119653d8a988716ae3d89b18ea35 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Sat, 19 Sep 2020 15:38:09 -0400 Subject: [PATCH 07/19] Logout fix (logout when deleting account) and refactoring to use this single method everywhere we process logout in the client. It should probably live elsewhere. --- .../User/ExternalIdentities/ExternalIdentities.vue | 4 ++-- client/src/components/User/UserPreferences.vue | 9 +++------ client/src/layout/menu.js | 4 ++-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/client/src/components/User/ExternalIdentities/ExternalIdentities.vue b/client/src/components/User/ExternalIdentities/ExternalIdentities.vue index c4002bfeefc..d638749afa6 100644 --- a/client/src/components/User/ExternalIdentities/ExternalIdentities.vue +++ b/client/src/components/User/ExternalIdentities/ExternalIdentities.vue @@ -89,7 +89,7 @@ import Vue from "vue"; import BootstrapVue from "bootstrap-vue"; import { getGalaxyInstance } from "app"; import svc from "./service"; -import { logoutClick } from "layout/menu"; +import { userLogout } from "layout/menu"; import ExternalLogin from "components/User/ExternalIdentities/ExternalLogin.vue"; Vue.use(BootstrapVue); @@ -180,7 +180,7 @@ export default { disconnectAndReset() { // Disconnects the user's final ext id and logouts of current session this.disconnectID(); - logoutClick(); + userLogout(); }, removeItem(item) { this.items = this.items.filter((o) => o != item); diff --git a/client/src/components/User/UserPreferences.vue b/client/src/components/User/UserPreferences.vue index 8521aab0e53..339d91f65f4 100644 --- a/client/src/components/User/UserPreferences.vue +++ b/client/src/components/User/UserPreferences.vue @@ -88,6 +88,7 @@ import _l from "utils/localization"; import axios from "axios"; import QueryStringParsing from "utils/query-string-parsing"; import { getUserPreferencesModel } from "components/User/UserPreferencesModel"; +import { userLogout } from "layout/menu"; import "@fortawesome/fontawesome-svg-core"; Vue.use(BootstrapVue); @@ -217,11 +218,7 @@ export default { Cancel: function () { Galaxy.modal.hide(); }, - "Sign out": function () { - window.location.href = `${getAppRoot()}user/logout?session_csrf_token=${ - Galaxy.session_csrf_token - }`; - }, + "Sign out": userLogout, }, }); }, @@ -257,7 +254,7 @@ export default { return false; } } - window.location.href = `${getAppRoot()}user/logout?session_csrf_token=${Galaxy.session_csrf_token}`; + userLogout(); } else { this.nameState = false; return false; diff --git a/client/src/layout/menu.js b/client/src/layout/menu.js index 48a864e7f6a..149ba0b022e 100644 --- a/client/src/layout/menu.js +++ b/client/src/layout/menu.js @@ -3,7 +3,7 @@ import { getGalaxyInstance } from "app"; import _l from "utils/localization"; import { CommunicationServerView } from "layout/communication-server-view"; -export function logoutClick() { +export function userLogout() { const galaxy = getGalaxyInstance(); const session_csrf_token = galaxy.session_csrf_token; const url = `${galaxy.root}user/logout?session_csrf_token=${session_csrf_token}`; @@ -244,7 +244,7 @@ export function fetchMenu(options = {}) { { title: _l("Logout"), divider: true, - onclick: logoutClick, + onclick: userLogout, }, { title: _l("Datasets"), From 657dbb1a1341ab8a8e5ddea5e18656ac283a34a9 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Sat, 19 Sep 2020 15:45:41 -0400 Subject: [PATCH 08/19] Support logoutAll, fix bug in userPreferences where we said it was a full session logout, but it was only terminating the current one. --- client/src/components/User/UserPreferences.vue | 6 +++--- client/src/layout/menu.js | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/client/src/components/User/UserPreferences.vue b/client/src/components/User/UserPreferences.vue index 339d91f65f4..00891336ae9 100644 --- a/client/src/components/User/UserPreferences.vue +++ b/client/src/components/User/UserPreferences.vue @@ -88,7 +88,7 @@ import _l from "utils/localization"; import axios from "axios"; import QueryStringParsing from "utils/query-string-parsing"; import { getUserPreferencesModel } from "components/User/UserPreferencesModel"; -import { userLogout } from "layout/menu"; +import { userLogoutAll } from "layout/menu"; import "@fortawesome/fontawesome-svg-core"; Vue.use(BootstrapVue); @@ -218,7 +218,7 @@ export default { Cancel: function () { Galaxy.modal.hide(); }, - "Sign out": userLogout, + "Sign out": userLogoutAll, }, }); }, @@ -254,7 +254,7 @@ export default { return false; } } - userLogout(); + userLogoutAll(); } else { this.nameState = false; return false; diff --git a/client/src/layout/menu.js b/client/src/layout/menu.js index 149ba0b022e..fe541d94d03 100644 --- a/client/src/layout/menu.js +++ b/client/src/layout/menu.js @@ -3,10 +3,14 @@ import { getGalaxyInstance } from "app"; import _l from "utils/localization"; import { CommunicationServerView } from "layout/communication-server-view"; -export function userLogout() { +export function userLogoutAll() { + return userLogout(true); +} + +export function userLogout(logoutAll = false) { const galaxy = getGalaxyInstance(); const session_csrf_token = galaxy.session_csrf_token; - const url = `${galaxy.root}user/logout?session_csrf_token=${session_csrf_token}`; + const url = `${galaxy.root}user/logout?session_csrf_token=${session_csrf_token}&logoutAll=${logoutAll}`; axios .get(url) .then(() => { From 9d2cc0da698d34580f93f8e5209962dc93e11eb7 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Sat, 19 Sep 2020 15:51:39 -0400 Subject: [PATCH 09/19] Fix python snake_case arg construction --- client/src/layout/menu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/layout/menu.js b/client/src/layout/menu.js index fe541d94d03..db7a5c8fd17 100644 --- a/client/src/layout/menu.js +++ b/client/src/layout/menu.js @@ -10,7 +10,7 @@ export function userLogoutAll() { export function userLogout(logoutAll = false) { const galaxy = getGalaxyInstance(); const session_csrf_token = galaxy.session_csrf_token; - const url = `${galaxy.root}user/logout?session_csrf_token=${session_csrf_token}&logoutAll=${logoutAll}`; + const url = `${galaxy.root}user/logout?session_csrf_token=${session_csrf_token}&logout_all=${logoutAll}`; axios .get(url) .then(() => { From 399939fdf855d751e47a518930d0153cb8c1f549 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Wed, 30 Sep 2020 23:27:37 -0400 Subject: [PATCH 10/19] Clientside-only user logout (currently only useful for after deletion; we generally want to invalidate the session as well) --- .../src/components/User/UserPreferences.vue | 4 +-- client/src/layout/menu.js | 27 +++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/client/src/components/User/UserPreferences.vue b/client/src/components/User/UserPreferences.vue index 00891336ae9..88631d32201 100644 --- a/client/src/components/User/UserPreferences.vue +++ b/client/src/components/User/UserPreferences.vue @@ -88,7 +88,7 @@ import _l from "utils/localization"; import axios from "axios"; import QueryStringParsing from "utils/query-string-parsing"; import { getUserPreferencesModel } from "components/User/UserPreferencesModel"; -import { userLogoutAll } from "layout/menu"; +import { userLogoutAll, userLogoutClient } from "layout/menu"; import "@fortawesome/fontawesome-svg-core"; Vue.use(BootstrapVue); @@ -254,7 +254,7 @@ export default { return false; } } - userLogoutAll(); + userLogoutClient(); } else { this.nameState = false; return false; diff --git a/client/src/layout/menu.js b/client/src/layout/menu.js index db7a5c8fd17..9c9802da72f 100644 --- a/client/src/layout/menu.js +++ b/client/src/layout/menu.js @@ -3,10 +3,12 @@ import { getGalaxyInstance } from "app"; import _l from "utils/localization"; import { CommunicationServerView } from "layout/communication-server-view"; -export function userLogoutAll() { - return userLogout(true); -} +const POST_LOGOUT_URL = "root/login?is_logout_redirect=true"; +/** + * Handles user logout. Invalidates the current session, checks to see if we + * need to log out of OIDC too, and goes to our POST_LOGOUT_URL (or some other + * configured redirect). */ export function userLogout(logoutAll = false) { const galaxy = getGalaxyInstance(); const session_csrf_token = galaxy.session_csrf_token; @@ -25,14 +27,29 @@ export function userLogout(logoutAll = false) { } }) .then((response) => { - if (response.data && response.data.redirect_uri) { + if (response.data?.redirect_uri) { window.top.location.href = response.data.redirect_uri; } else { - window.top.location.href = `${galaxy.root}root/login?is_logout_redirect=true`; + window.top.location.href = `${galaxy.root}${POST_LOGOUT_URL}`; } }); } +/** User logout with 'log out all sessions' flag set. This will invalidate all + * active sessions a user might have. */ +export function userLogoutAll() { + return userLogout(true); +} + +/** Purely clientside logout, dumps session and redirects without invalidating + * serverside. Currently only used when marking an account deleted -- any + * subsequent navigation after the deletion API request would fail otherwise */ +export function userLogoutClient() { + const galaxy = getGalaxyInstance(); + galaxy.user?.clearSessionStorage(); + window.top.location.href = `${galaxy.root}${POST_LOGOUT_URL}`; +} + export function fetchMenu(options = {}) { const Galaxy = getGalaxyInstance(); const menu = []; From ca529da26cadd0a9196d11e89496fb9b894ed9b5 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Wed, 30 Sep 2020 23:28:40 -0400 Subject: [PATCH 11/19] Simplification, no need to grab Galaxy and userId given the component props --- client/src/components/User/UserPreferences.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/src/components/User/UserPreferences.vue b/client/src/components/User/UserPreferences.vue index 88631d32201..fde374718ac 100644 --- a/client/src/components/User/UserPreferences.vue +++ b/client/src/components/User/UserPreferences.vue @@ -238,15 +238,13 @@ export default { this.handleSubmit(); }, async handleSubmit() { - const Galaxy = getGalaxyInstance(); - const userId = Galaxy.user.id; if (!this.checkFormValidity()) { return false; } if (this.email === this.name) { this.nameState = true; try { - await axios.delete(`${getAppRoot()}api/users/${userId}`); + await axios.delete(`${getAppRoot()}api/users/${this.userId}`); } catch (e) { if (e.response.status === 403) { this.deleteError = From 3780f54f75c829d1cacbabb0f7f14e1bf2f4cde9 Mon Sep 17 00:00:00 2001 From: Simon Bray <32272674+simonbray@users.noreply.github.com> Date: Thu, 1 Oct 2020 09:13:05 +0200 Subject: [PATCH 12/19] remove path attribute from FileLiteralTarget class Co-authored-by: Nicola Soranzo --- lib/galaxy/tool_util/cwl/util.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/tool_util/cwl/util.py b/lib/galaxy/tool_util/cwl/util.py index a4605653f18..f8fcc038e4c 100644 --- a/lib/galaxy/tool_util/cwl/util.py +++ b/lib/galaxy/tool_util/cwl/util.py @@ -332,13 +332,12 @@ def _ensure_file_exists(file_path): class FileLiteralTarget: - def __init__(self, contents, path=None, **kwargs): + def __init__(self, contents, **kwargs): self.contents = contents self.properties = kwargs - self.path = path def __str__(self): - return "FileLiteralTarget[path={}] with {}".format(self.path, self.properties) + return "FileLiteralTarget[contents={}] with {}".format(self.contents, self.properties) class FileUploadTarget: From 1b4d0bf07b92d8925d09785dd81fa15207232f02 Mon Sep 17 00:00:00 2001 From: Daniel Blankenberg Date: Mon, 21 Sep 2020 10:38:06 -0400 Subject: [PATCH 13/19] enable validation of ITs --- lib/galaxy/tools/repositories.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/galaxy/tools/repositories.py b/lib/galaxy/tools/repositories.py index 6852574cf3b..a843a18e725 100644 --- a/lib/galaxy/tools/repositories.py +++ b/lib/galaxy/tools/repositories.py @@ -29,6 +29,7 @@ class ValidationContext: self.temporary_path = tempfile.mkdtemp(prefix='tool_validation_') self.config.tool_data_table_config = os.path.join(self.temporary_path, 'tool_data_table_conf.xml') self.config.shed_tool_data_table_config = os.path.join(self.temporary_path, 'shed_tool_data_table_conf.xml') + self.config.interactivetools_enable = True self.tool_data_tables = tool_data_tables self.tool_shed_registry = Bunch(tool_sheds={}) self.datatypes_registry = registry From 5c00766d86c86f648e90c435b6605335c410546b Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Thu, 1 Oct 2020 14:00:35 -0400 Subject: [PATCH 14/19] Use block elements for labels to handle wrapping indentation --- .../scripts/components/Panels/Common/ToolSection.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/galaxy/scripts/components/Panels/Common/ToolSection.vue b/client/galaxy/scripts/components/Panels/Common/ToolSection.vue index 69e8377ffe4..aa0b82f5e2f 100644 --- a/client/galaxy/scripts/components/Panels/Common/ToolSection.vue +++ b/client/galaxy/scripts/components/Panels/Common/ToolSection.vue @@ -12,9 +12,9 @@