From 384a165aab2d579ee4c2dceba61f21c42c8c2dc4 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Thu, 19 Apr 2018 12:35:25 +0200 Subject: [PATCH 1/8] Allow schema to validate --- lib/galaxy/webapps/galaxy/config_schema.yml | 99 ++++++++++----------- 1 file changed, 48 insertions(+), 51 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/config_schema.yml b/lib/galaxy/webapps/galaxy/config_schema.yml index edb3fd1720f..5bc7b1de92e 100644 --- a/lib/galaxy/webapps/galaxy/config_schema.yml +++ b/lib/galaxy/webapps/galaxy/config_schema.yml @@ -45,7 +45,7 @@ mapping: cookie_path: type: str - default: null + default: '' required: false desc: | If proxy-prefix is enabled and you're running more than one Galaxy instance @@ -109,7 +109,7 @@ mapping: database_template: type: str - default: null + default: '' required: false desc: | If auto-creating a postgres database on startup - it can be based on an existing @@ -332,7 +332,7 @@ mapping: watch_tools: type: str - default: false + default: 'false' required: false desc: | Set to True to enable monitoring of tools and tool directories @@ -359,7 +359,7 @@ mapping: containers_resolvers_config_file: type: str - default: null + default: '' required: false desc: | Container resolvers configuration (beta). Setup a file describing container @@ -455,7 +455,7 @@ mapping: watch_tool_data_dir: type: str - default: false + default: 'false' required: false desc: | Set to True to enable monitoring of the tool_data and shed_tool_data_path @@ -607,7 +607,7 @@ mapping: Number of checks to execute if check_job_script_integrity is enabled. check_job_script_integrity_sleep: - type: str + type: float default: .25 required: false desc: | @@ -674,7 +674,7 @@ mapping: smtp_server: type: str - default: null + default: '' required: false desc: | Galaxy sends mail for various things: subscribing users to the mailing list @@ -685,7 +685,7 @@ mapping: smtp_username: type: str - default: null + default: '' required: false desc: | If your SMTP server requires a username and password, you can provide them @@ -694,7 +694,7 @@ mapping: smtp_password: type: str - default: null + default: '' required: false desc: | If your SMTP server requires a username and password, you can provide them @@ -719,7 +719,7 @@ mapping: error_email_to: type: str - default: null + default: '' required: false desc: | Datasets in an error state include a link to report the error. Those reports @@ -729,7 +729,7 @@ mapping: email_from: type: str - default: null + default: '' required: false desc: | Email address to use in the 'From' field when sending emails for @@ -813,7 +813,7 @@ mapping: ga_code: type: str - default: null + default: '' required: false desc: | You can enter tracking code here to track visitor's behavior @@ -865,7 +865,7 @@ mapping: message_box_content: type: str - default: null + default: '' required: false desc: | Show a message box under the masthead. @@ -879,7 +879,7 @@ mapping: brand: type: str - default: null + default: '' required: false desc: | Append "/{brand}" to the "Galaxy" text in the masthead. @@ -955,21 +955,21 @@ mapping: biostar_url: type: str - default: null + default: '' required: false desc: | Enable integration with a custom Biostar instance. biostar_key_name: type: str - default: null + default: '' required: false desc: | Enable integration with a custom Biostar instance. biostar_key: type: str - default: null + default: '' required: false desc: | Enable integration with a custom Biostar instance. @@ -1026,7 +1026,7 @@ mapping: terms_url: type: str - default: null + default: '' required: false desc: | The URL linked by the "Terms and Conditions" link in the "Help" menu, as well @@ -1140,7 +1140,7 @@ mapping: nginx_x_accel_redirect_base: type: str - default: null + default: '' required: false desc: | The same download handling can be done by nginx using X-Accel-Redirect. This @@ -1172,7 +1172,7 @@ mapping: nginx_upload_store: type: str - default: null + default: '' required: false desc: | nginx can also handle file uploads (user-to-Galaxy) via nginx_upload_module. @@ -1182,7 +1182,7 @@ mapping: nginx_upload_path: type: str - default: null + default: '' required: false desc: | This value overrides the action set on the file upload form, e.g. the web @@ -1191,7 +1191,7 @@ mapping: nginx_upload_job_files_store: type: str - default: null + default: '' required: false desc: | Galaxy can also use nginx_upload_module to receive files staged out upon job @@ -1201,7 +1201,7 @@ mapping: nginx_upload_job_files_path: type: str - default: null + default: '' required: false desc: | Galaxy can also use nginx_upload_module to receive files staged out upon job @@ -1307,7 +1307,7 @@ mapping: dynamic_proxy_golang_api_key: type: str - default: null + default: '' required: false desc: | The golang proxy uses a RESTful HTTP API for communication with Galaxy @@ -1332,15 +1332,6 @@ mapping: https://docs.python.org/2/library/logging.html#logging-levels A custom debug level of "TRACE" is available for even more verbosity. - logging: - type: map - default: galaxy.config.LOGGING_CONFIG_DEFAULT - desc: | - Controls where and how the server logs messages. If unset, the default is to log all messages to standard - output at the level defined by the `log_level` configuration option. Configuration is described in the - documentation at: - https://docs.galaxyproject.org/en/master/admin/config_logging.html - database_engine_option_echo: type: bool default: false @@ -1427,7 +1418,7 @@ mapping: allowed_origin_hostnames: type: str - default: null + default: '' required: false desc: | Return a Access-Control-Allow-Origin response header that matches the Origin @@ -1524,7 +1515,7 @@ mapping: sentry_dsn: type: str - default: null + default: '' required: false desc: | Log to Sentry @@ -1605,7 +1596,7 @@ mapping: library_import_dir: type: str - default: null + default: '' required: false desc: | Add an option to the library upload form which allows administrators to @@ -1613,7 +1604,7 @@ mapping: user_library_import_dir: type: str - default: null + default: '' required: false desc: | Add an option to the library upload form which allows authorized @@ -1632,7 +1623,7 @@ mapping: user_library_import_symlink_whitelist: type: str - default: null + default: '' required: false desc: | For security reasons, users may not import any files that actually lie @@ -1686,7 +1677,7 @@ mapping: tool_name_boost: type: float - default: 9 + default: 9.0 required: false desc: | Boosts are used to customize this instance's toolbox search. @@ -1696,7 +1687,7 @@ mapping: tool_section_boost: type: float - default: 3 + default: 3.0 required: false desc: | Boosts are used to customize this instance's toolbox search. @@ -1706,7 +1697,7 @@ mapping: tool_description_boost: type: float - default: 2 + default: 2.0 required: false desc: | Boosts are used to customize this instance's toolbox search. @@ -1716,7 +1707,7 @@ mapping: tool_label_boost: type: float - default: 1 + default: 1.0 required: false desc: | Boosts are used to customize this instance's toolbox search. @@ -1726,7 +1717,7 @@ mapping: tool_stub_boost: type: float - default: 5 + default: 5.0 required: false desc: | Boosts are used to customize this instance's toolbox search. @@ -1800,7 +1791,7 @@ mapping: remote_user_maildomain: type: str - default: null + default: '' required: false desc: | If use_remote_user is enabled and your external authentication @@ -1832,7 +1823,7 @@ mapping: remote_user_logout_href: type: str - default: null + default: '' required: false desc: | If use_remote_user is enabled, you can set this to a URL that will log your @@ -1859,7 +1850,7 @@ mapping: admin_users: type: str - default: null + default: '' required: false desc: | Administrative users - set this to a comma-separated list of valid Galaxy @@ -2065,7 +2056,7 @@ mapping: invocation to schedule indefinitely. The default corresponds to 1 month. maximum_workflow_jobs_per_scheduling_iteration: - type: str + type: int default: -1 required: false desc: | @@ -2117,7 +2108,7 @@ mapping: api_allow_run_as: type: str - default: null + default: '' required: false desc: | Optional list of email addresses of API users who can make calls on behalf of @@ -2163,7 +2154,7 @@ mapping: ftp_upload_dir: type: str - default: null + default: '' required: false desc: | Enable Galaxy's "Upload via FTP" interface. You'll need to install and @@ -2174,7 +2165,7 @@ mapping: ftp_upload_site: type: str - default: null + default: '' required: false desc: | This should be the hostname of your FTP server, which will be provided to @@ -2454,7 +2445,7 @@ mapping: environment_setup_file: type: str - default: null + default: '' required: false desc: | File to source to set up the environment when running jobs. By default, the @@ -2587,3 +2578,9 @@ mapping: desc: | persistent_communication_rooms is a comma-separated list of rooms that should be always available. + use_pbkdf2: + type: bool + default: false + required: false + desc: | + asdf From 0b95898ccf68b8497dff9f322b44abc5668dfce6 Mon Sep 17 00:00:00 2001 From: E Rasche Date: Tue, 1 May 2018 17:24:43 +0200 Subject: [PATCH 2/8] Document pbkdf2 --- lib/galaxy/webapps/galaxy/config_schema.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/config_schema.yml b/lib/galaxy/webapps/galaxy/config_schema.yml index 5bc7b1de92e..c51609e60e1 100644 --- a/lib/galaxy/webapps/galaxy/config_schema.yml +++ b/lib/galaxy/webapps/galaxy/config_schema.yml @@ -2580,7 +2580,9 @@ mapping: use_pbkdf2: type: bool - default: false + default: true required: false desc: | - asdf + Allow disabling pbkdf2 hashing of passwords for legacy situations. + This should normally be left enabled unless there is a specific + reason to disable it. From 7eb0be96cf3dba5099f28fd001c5f2b87ddacf38 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Mon, 30 Jul 2018 12:25:03 -0400 Subject: [PATCH 3/8] Restore log_destination = stdout configuration option. Implementation in 17.09 was here https://github.com/galaxyproject/galaxy/blob/release_17.09/lib/galaxy/config.py#L910. This option set to stdout is used by the test framework output Galaxy logs to stdout. As far as I can tell log_destination was removed in 18.01 and the effect was to sort of default to stdout - but when we fixed log_destination for files and backported recently https://github.com/galaxyproject/galaxy/commit/bc95f2563601635cfa1daa686b3d5c4e3ebb51ea - test output became written to a file called "stdout". This commit should restore the 17.09 behavior for both files and stdout configuration of this logging. --- lib/galaxy/config.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/config.py b/lib/galaxy/config.py index 9458f3d572c..a6d5424643b 100644 --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -662,7 +662,16 @@ class Configuration(object): self.containers_conf = parse_containers_config(self.containers_config_file) - if kwargs.get("log_destination", None): + log_destination = kwargs.get("log_destination", None) + if log_destination == "stdout": + LOGGING_CONFIG_DEFAULT['handlers']['console'] = { + 'class': 'logging.StreamHandler', + 'formatter': 'stack', + 'level': 'DEBUG', + 'stream': 'ext://sys.stdout', + 'filters': ['stack'] + } + elif log_destination: LOGGING_CONFIG_DEFAULT['handlers']['console'] = { 'class': 'logging.FileHandler', 'formatter': 'stack', From 272c6b071d5c5db526cb3da8cc174dd4785a0d6e Mon Sep 17 00:00:00 2001 From: John Chilton Date: Tue, 31 Jul 2018 09:29:29 -0400 Subject: [PATCH 4/8] Test case to clarify workflow API a bit in simple cases. --- test/api/test_workflows.py | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/test/api/test_workflows.py b/test/api/test_workflows.py index 10aaebf2a8f..0e6bab5436d 100644 --- a/test/api/test_workflows.py +++ b/test/api/test_workflows.py @@ -2868,15 +2868,37 @@ steps: invocation_id = usage["id"] usage_details = self._invocation_details(workflow_id, invocation_id) # Assert some high-level things about the structure of data returned. - self._assert_has_keys(usage_details, "inputs", "steps") + self._assert_has_keys(usage_details, "inputs", "steps", "workflow_id") + + # stored_workflow vs workflow thing makes following state false. + # assert usage_details["workflow_id"] == workflow_id + + # Wait for the invocation to be fully scheduled, so we have details on all steps. + self._wait_for_invocation_state(workflow_id, invocation_id, 'scheduled') + usage_details = self._invocation_details(workflow_id, invocation_id) + invocation_steps = usage_details["steps"] - for step in invocation_steps: - self._assert_has_keys(step, "workflow_step_id", "order_index", "id") - an_invocation_step = invocation_steps[0] - step_id = an_invocation_step["id"] - step_response = self._get("workflows/%s/usage/%s/steps/%s" % (workflow_id, invocation_id, step_id)) - self._assert_status_code_is(step_response, 200) - self._assert_has_keys(step_response.json(), "id", "order_index") + invocation_input_step, invocation_tool_step = None, None + for invocation_step in invocation_steps: + self._assert_has_keys(invocation_step, "workflow_step_id", "order_index", "id") + order_index = invocation_step["order_index"] + assert order_index in [0, 1, 2], order_index + if order_index == 0: + invocation_input_step = invocation_step + elif order_index == 2: + invocation_tool_step = invocation_step + + # Tool steps have non-null job_ids (deprecated though they may be) + assert invocation_input_step.get("job_id", None) is None + job_id = invocation_tool_step.get("job_id", None) + assert job_id is not None + + invocation_tool_step_id = invocation_tool_step["id"] + invocation_tool_step_response = self._get("workflows/%s/invocations/%s/steps/%s" % (workflow_id, invocation_id, invocation_tool_step_id)) + self._assert_status_code_is(invocation_tool_step_response, 200) + self._assert_has_keys(invocation_tool_step_response.json(), "id", "order_index", "job_id") + + assert invocation_tool_step_response.json()["job_id"] == job_id @skip_without_tool("cat1") def test_invocations_accessible_imported_workflow(self): From 9874e5db0cbf1967a90d3ad74820af1790602981 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Tue, 31 Jul 2018 09:49:59 -0400 Subject: [PATCH 5/8] Allow uniform access to job state for WorkflowInvocationSteps. Use the concept of job_source_type and job_source_id used by IDs to summarize the state and list out individual jobs in the response as a shortcut. This information used to be readily accessible before 18.01. --- lib/galaxy/model/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 6e5b8206d5a..5aa0d60fbaa 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -4326,6 +4326,10 @@ class WorkflowInvocationStep(object, Dictifiable): # Following no longer makes sense... # rval['state'] = self.job.state if self.job is not None else None if view == 'element': + jobs = [] + for job in self.jobs: + jobs.append(job.to_dict()) + outputs = {} for output_assoc in self.output_datasets: name = output_assoc.output_name @@ -4345,6 +4349,7 @@ class WorkflowInvocationStep(object, Dictifiable): rval['outputs'] = outputs rval['output_collections'] = output_collections + rval['jobs'] = jobs return rval From b878835ea388cc7ea15c0bf9d56738732d44b8e2 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Tue, 31 Jul 2018 16:55:49 -0400 Subject: [PATCH 6/8] Add a legacy_job_state mode to restore 17.09 workflow invocation behavior. --- lib/galaxy/model/__init__.py | 16 ++++- lib/galaxy/webapps/galaxy/api/workflows.py | 24 ++++++- test/api/test_workflows.py | 75 +++++++++++++++++++++- 3 files changed, 108 insertions(+), 7 deletions(-) diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 5aa0d60fbaa..43c74e9f4b8 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -4185,7 +4185,7 @@ class WorkflowInvocation(object, UsesCreateAndUpdateTime, Dictifiable): else: raise Exception("Unknown output type encountered") - def to_dict(self, view='collection', value_mapper=None, step_details=False): + def to_dict(self, view='collection', value_mapper=None, step_details=False, legacy_job_state=False): rval = super(WorkflowInvocation, self).to_dict(view=view, value_mapper=value_mapper) if view == 'element': steps = [] @@ -4194,7 +4194,19 @@ class WorkflowInvocation(object, UsesCreateAndUpdateTime, Dictifiable): v = step.to_dict(view='element') else: v = step.to_dict(view='collection') - steps.append(v) + if legacy_job_state: + step_jobs = step.jobs + if step_jobs: + for step_job in step_jobs: + v_clone = v.copy() + v_clone["state"] = step_job.state + v_clone["job_id"] = step_job.id + steps.append(v_clone) + else: + v["state"] = None + steps.append(v) + else: + steps.append(v) rval['steps'] = steps inputs = {} diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 3d006f09a5d..0f50d19b7ff 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -690,12 +690,30 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesAnn :param invocation_id: the invocation id (required) :type invocation_id: str + :param step_details: fetch details about individual invocation steps + and populate a steps attribute in the resulting + dictionary. Defaults to false. + :type step_details: bool + + :param legacy_job_state: If step_details is rrue, and this is set to true + populate the invocation step state with the job state + instead of the invocation step state. This will also + produce one step per job in mapping jobs to mimic the + older behavior with respect to collections. Partially + scheduled steps may provide incomplete information + and the listed steps outputs are the mapped over + step outputs but the individual job outputs + when this is set - at least for now. + :type legacy_job_state: bool + :raises: exceptions.MessageException, exceptions.ObjectNotFound """ decoded_workflow_invocation_id = self.decode_id(invocation_id) workflow_invocation = self.workflow_manager.get_invocation(trans, decoded_workflow_invocation_id) if workflow_invocation: - return self.__encode_invocation(trans, workflow_invocation, step_details=kwd.get('step_details', False)) + step_details = util.string_as_bool(kwd.get('step_details', 'False')) + legacy_job_state = util.string_as_bool(kwd.get('legacy_job_state', 'False')) + return self.__encode_invocation(trans, workflow_invocation, step_details=step_details, legacy_job_state=legacy_job_state) return None @expose_api @@ -785,9 +803,9 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesAnn def __get_stored_workflow(self, trans, workflow_id): return self.workflow_manager.get_stored_workflow(trans, workflow_id) - def __encode_invocation(self, trans, invocation, view="element", step_details=False): + def __encode_invocation(self, trans, invocation, view="element", step_details=False, legacy_job_state=False): return self.encode_all_ids( trans, - invocation.to_dict(view, step_details=step_details), + invocation.to_dict(view, step_details=step_details, legacy_job_state=legacy_job_state), True ) diff --git a/test/api/test_workflows.py b/test/api/test_workflows.py index 0e6bab5436d..4eebede79a5 100644 --- a/test/api/test_workflows.py +++ b/test/api/test_workflows.py @@ -193,8 +193,8 @@ class BaseWorkflowsApiTestCase(api.ApiTestCase): workflow_inputs = workflow_show_resposne.json()["inputs"] return workflow_inputs - def _invocation_details(self, workflow_id, invocation_id): - invocation_details_response = self._get("workflows/%s/usage/%s" % (workflow_id, invocation_id)) + def _invocation_details(self, workflow_id, invocation_id, **kwds): + invocation_details_response = self._get("workflows/%s/usage/%s" % (workflow_id, invocation_id), data=kwds) self._assert_status_code_is(invocation_details_response, 200) invocation_details = invocation_details_response.json() return invocation_details @@ -2900,6 +2900,77 @@ steps: assert invocation_tool_step_response.json()["job_id"] == job_id + def test_invocation_with_collection_mapping(self): + workflow_id, invocation_id = self._run_mapping_workflow() + + usage_details = self._invocation_details(workflow_id, invocation_id) + # Assert some high-level things about the structure of data returned. + self._assert_has_keys(usage_details, "inputs", "steps", "workflow_id") + + invocation_steps = usage_details["steps"] + invocation_input_step, invocation_tool_step = None, None + for invocation_step in invocation_steps: + self._assert_has_keys(invocation_step, "workflow_step_id", "order_index", "id") + order_index = invocation_step["order_index"] + assert order_index in [0, 1] + if invocation_step["order_index"] == 0: + assert invocation_input_step is None + invocation_input_step = invocation_step + else: + assert invocation_tool_step is None + invocation_tool_step = invocation_step + + # Tool steps have non-null job_ids (deprecated though they may be) + assert invocation_input_step.get("job_id", None) is None + assert invocation_tool_step.get("job_id", None) is None + assert invocation_tool_step["state"] == "scheduled" + + usage_details = self._invocation_details(workflow_id, invocation_id, legacy_job_state="true") + # Assert some high-level things about the structure of data returned. + self._assert_has_keys(usage_details, "inputs", "steps", "workflow_id") + + invocation_steps = usage_details["steps"] + invocation_input_step = None + invocation_tool_steps = [] + for invocation_step in invocation_steps: + self._assert_has_keys(invocation_step, "workflow_step_id", "order_index", "id") + order_index = invocation_step["order_index"] + assert order_index in [0, 1] + if invocation_step["order_index"] == 0: + assert invocation_input_step is None + invocation_input_step = invocation_step + else: + invocation_tool_steps.append(invocation_step) + + assert len(invocation_tool_steps) == 2 + assert invocation_tool_steps[0]["state"] == "ok" + + def _run_mapping_workflow(self): + history_id = self.dataset_populator.new_history() + summary = self._run_jobs(""" +class: GalaxyWorkflow +inputs: + - type: collection + label: input_c +steps: + - label: cat1 + tool_id: cat1 + state: + input1: + $link: input_c +test_data: + input_c: + type: list + elements: + - identifier: i1 + content: "0" + - identifier: i2 + content: "1" +""", history_id=history_id, wait=True, assert_ok=True) + workflow_id = summary.workflow_id + invocation_id = summary.invocation_id + return workflow_id, invocation_id + @skip_without_tool("cat1") def test_invocations_accessible_imported_workflow(self): workflow_id = self.workflow_populator.simple_workflow("test_usage", publish=True) From 3efda23b4fe84f1a61d83aba07186e46c81990ce Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 7 Sep 2018 09:39:09 -0400 Subject: [PATCH 7/8] Restore logging block in galaxy config schema. --- lib/galaxy/webapps/galaxy/config_schema.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/galaxy/webapps/galaxy/config_schema.yml b/lib/galaxy/webapps/galaxy/config_schema.yml index c51609e60e1..7bf8c3e1501 100644 --- a/lib/galaxy/webapps/galaxy/config_schema.yml +++ b/lib/galaxy/webapps/galaxy/config_schema.yml @@ -1332,6 +1332,15 @@ mapping: https://docs.python.org/2/library/logging.html#logging-levels A custom debug level of "TRACE" is available for even more verbosity. + logging: + type: map + allowempty: True + desc: | + Controls where and how the server logs messages. If unset, the default is to log all messages to standard + output at the level defined by the `log_level` configuration option. Configuration is described in the + documentation at: + https://docs.galaxyproject.org/en/master/admin/config_logging.html + database_engine_option_echo: type: bool default: false From 2d9b803025828869c50a70db25fb7654caa17368 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Wed, 26 Sep 2018 12:37:43 +0200 Subject: [PATCH 8/8] Use UserRoleAssociation to get private roles If I understand this correctly this should work even if the user email changes. --- lib/galaxy/security/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/security/__init__.py b/lib/galaxy/security/__init__.py index 654c5d85b58..ef396cc9ad1 100644 --- a/lib/galaxy/security/__init__.py +++ b/lib/galaxy/security/__init__.py @@ -766,7 +766,8 @@ class GalaxyRBACAgent(RBACAgent): def get_private_user_role(self, user, auto_create=False): role = self.sa_session.query(self.model.Role) \ - .filter(and_(self.model.Role.table.c.name == user.email, + .filter(and_(self.model.UserRoleAssociation.table.c.user_id == user.id, + self.model.Role.table.c.id == self.model.UserRoleAssociation.table.c.role_id, self.model.Role.table.c.type == self.model.Role.types.PRIVATE)) \ .first() if not role: