From d10f740cff8e3520383c004a16830700b2789c9f Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Thu, 23 Feb 2017 10:56:00 -0500 Subject: [PATCH 01/15] The user controller functions for changing information were ripped out before providing a way for admin functionality to use the new javascript stuff. Seems nontrivial, so this puts the endpoint back temporarily until the adminjs rewrite which can include the new functionality. --- lib/galaxy/webapps/galaxy/controllers/user.py | 192 ++++++++++++++++++ .../webapps/galaxy/user/manage_info.mako | 95 +++++++++ 2 files changed, 287 insertions(+) create mode 100644 templates/webapps/galaxy/user/manage_info.mako diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index c69eb8765e0..ed34ef8093b 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -1190,3 +1190,195 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat message=message, display_top=kwd.get('redirect_home', False) ) + + @web.expose + @web.require_admin + def edit_info( self, trans, cntrller, **kwd ): + """ + Edit user information = username, email or password. + """ + params = util.Params( kwd ) + is_admin = cntrller == 'admin' and trans.user_is_admin() + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + user_id = params.get( 'user_id', None ) + if user_id and is_admin: + user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) ) + elif user_id and ( not trans.user or trans.user.id != trans.security.decode_id( user_id ) ): + message = 'Invalid user id' + status = 'error' + user = None + else: + user = trans.user + if user and params.get( 'login_info_button', False ): + # Editing email and username + email = util.restore_text( params.get( 'email', '' ) ) + username = util.restore_text( params.get( 'username', '' ) ).lower() + + # Validate the new values for email and username + message = validate_email( trans, email, user ) + if not message and username: + message = validate_publicname( trans, username, user ) + if message: + status = 'error' + else: + if ( user.email != email ): + # The user's private role name must match the user's login ( email ) + private_role = trans.app.security_agent.get_private_user_role( user ) + private_role.name = email + private_role.description = 'Private role for ' + email + # Change the email itself + user.email = email + trans.sa_session.add_all( ( user, private_role ) ) + trans.sa_session.flush() + if trans.webapp.name == 'galaxy' and trans.app.config.user_activation_on: + user.active = False + trans.sa_session.add( user ) + trans.sa_session.flush() + is_activation_sent = self.send_verification_email( trans, user.email, user.username ) + if is_activation_sent: + message = 'The login information has been updated with the changes.
Verification email has been sent to your new email address. Please verify it by clicking the activation link in the email.
Please check your spam/trash folder in case you cannot find the message.' + else: + message = 'Unable to send activation email, please contact your local Galaxy administrator.' + if trans.app.config.error_email_to is not None: + message += ' Contact: %s' % trans.app.config.error_email_to + if ( user.username != username ): + user.username = username + trans.sa_session.add( user ) + trans.sa_session.flush() + message = 'The login information has been updated with the changes.' + elif user and params.get( 'edit_user_info_button', False ): + # Edit user information - webapp MUST BE 'galaxy' + user_type_fd_id = params.get( 'user_type_fd_id', 'none' ) + if user_type_fd_id not in [ 'none' ]: + user_type_form_definition = trans.sa_session.query( trans.app.model.FormDefinition ).get( trans.security.decode_id( user_type_fd_id ) ) + elif user.values: + user_type_form_definition = user.values.form_definition + else: + # User was created before any of the user_info forms were created + user_type_form_definition = None + if user_type_form_definition: + values = self.get_form_values( trans, user, user_type_form_definition, **kwd ) + else: + values = {} + flush_needed = False + if user.values: + # Editing the user info of an existing user with existing user info + user.values.content = values + trans.sa_session.add( user.values ) + flush_needed = True + elif values: + form_values = trans.model.FormValues( user_type_form_definition, values ) + trans.sa_session.add( form_values ) + user.values = form_values + flush_needed = True + if flush_needed: + trans.sa_session.add( user ) + trans.sa_session.flush() + message = "The user information has been updated with the changes." + if user and trans.webapp.name == 'galaxy' and is_admin: + kwd[ 'user_id' ] = trans.security.encode_id( user.id ) + kwd[ 'id' ] = user_id + if message: + kwd[ 'message' ] = util.sanitize_text( message ) + if status: + kwd[ 'status' ] = status + return trans.response.send_redirect( web.url_for( controller='user', + action='manage_user_info', + cntrller=cntrller, + **kwd ) ) + + @web.expose + @web.require_admin + def manage_user_info( self, trans, cntrller, **kwd ): + '''TEMPORARY ENDPOINT - added back to support admin-level user info + editing prior to adminjs. This is code that was prematurely removed + from the user controller when the user-side admin functionality was + replaced. Manage a user's login, password, public username, type, + addresses, etc.''' + + def __get_user_type_form_definition( trans, user=None, **kwd ): + params = util.Params( kwd ) + if user and user.values: + user_type_fd_id = trans.security.encode_id( user.values.form_definition.id ) + else: + user_type_fd_id = params.get( 'user_type_fd_id', 'none' ) + if user_type_fd_id not in [ 'none' ]: + user_type_form_definition = trans.sa_session.query( trans.app.model.FormDefinition ).get( trans.security.decode_id( user_type_fd_id ) ) + else: + user_type_form_definition = None + return user_type_form_definition + + def __get_widgets( trans, user_type_form_definition, user=None, **kwd ): + widgets = [] + if user_type_form_definition: + if user: + if user.values: + widgets = user_type_form_definition.get_widgets( user=user, + contents=user.values.content, + **kwd ) + else: + widgets = user_type_form_definition.get_widgets( None, contents={}, **kwd ) + else: + widgets = user_type_form_definition.get_widgets( None, contents={}, **kwd ) + return widgets + + def __build_user_type_fd_id_select_field( trans, selected_value ): + from galaxy.web.form_builder import build_select_field + # Get all the user information forms + user_info_forms = self.get_all_forms( trans, + filter=dict( deleted=False ), + form_type=trans.model.FormDefinition.types.USER_INFO ) + return build_select_field( trans, + objs=user_info_forms, + label_attr='name', + select_field_name='user_type_fd_id', + initial_value='none', + selected_value=selected_value, + refresh_on_change=True ) + + params = util.Params( kwd ) + user_id = params.get( 'id', None ) + if user_id: + user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) ) + else: + user = trans.user + if not user: + raise AssertionError("The user id (%s) is not valid" % str( user_id )) + email = util.restore_text( params.get( 'email', user.email ) ) + username = util.restore_text( params.get( 'username', '' ) ) + if not username: + username = user.username + message = escape( util.restore_text( params.get( 'message', '' ) ) ) + status = params.get( 'status', 'done' ) + user_type_form_definition = __get_user_type_form_definition( trans, user=user, **kwd ) + user_type_fd_id = params.get( 'user_type_fd_id', 'none' ) + if user_type_fd_id == 'none' and user_type_form_definition is not None: + user_type_fd_id = trans.security.encode_id( user_type_form_definition.id ) + user_type_fd_id_select_field = __build_user_type_fd_id_select_field( trans, selected_value=user_type_fd_id ) + widgets = __get_widgets( trans, user_type_form_definition, user=user, **kwd ) + # user's addresses + show_filter = util.restore_text( params.get( 'show_filter', 'Active' ) ) + if show_filter == 'All': + addresses = [address for address in user.addresses] + elif show_filter == 'Deleted': + addresses = [address for address in user.addresses if address.deleted] + else: + addresses = [address for address in user.addresses if not address.deleted] + user_info_forms = self.get_all_forms( trans, + filter=dict( deleted=False ), + form_type=trans.app.model.FormDefinition.types.USER_INFO ) + return trans.fill_template( '/webapps/galaxy/user/manage_info.mako', + cntrller=cntrller, + user=user, + email=email, + username=username, + user_type_fd_id_select_field=user_type_fd_id_select_field, + user_info_forms=user_info_forms, + user_type_form_definition=user_type_form_definition, + user_type_fd_id=user_type_fd_id, + widgets=widgets, + addresses=addresses, + show_filter=show_filter, + message=message, + status=status ) diff --git a/templates/webapps/galaxy/user/manage_info.mako b/templates/webapps/galaxy/user/manage_info.mako new file mode 100644 index 00000000000..8b1a747b662 --- /dev/null +++ b/templates/webapps/galaxy/user/manage_info.mako @@ -0,0 +1,95 @@ +<%inherit file="/base.mako"/> +<%namespace file="/user/info.mako" import="render_user_info" /> +<%namespace file="/message.mako" import="render_msg" /> + +%if message: + ${render_msg( message, status )} +%endif + +${render_user_info()} + +%if user.values or user_info_forms: +

+
+
+
User information
+ %if user_type_fd_id_select_field and len( user_type_fd_id_select_field.options ) >= 1: +
+ + ${user_type_fd_id_select_field.get_html()} +
+ %else: + + %endif + %for field in widgets: +
+ + ${field['widget'].get_html()} +
+ ${field['helptext']} +
+
+
+ %endfor +
+ +
+
+
+

+%endif + +

+ +

+
+
User Addresses
+
+ %if user.addresses: +
+
+ %for i, filter in enumerate( ['Active', 'Deleted', 'All'] ): + %if i > 0: + | + %endif + %if show_filter == filter: + ${filter} + %else: + ${filter} + %endif + %endfor +
+
+ + + %for index, address in enumerate(addresses): + + + + %endfor + +
+
+ + ${address.get_html()} +
+
+ +
+
+ %endif +
+ +
+
+
+
From 6f3c8c7447e9a71c580ef9307395cd5dcd314915 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Thu, 23 Feb 2017 12:24:08 -0500 Subject: [PATCH 02/15] This template inherited field never worked apparently, but nobody noticed. This correctly sets the is_admin flag here. --- lib/galaxy/webapps/galaxy/controllers/user.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index ed34ef8093b..93013886660 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -1372,6 +1372,7 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat cntrller=cntrller, user=user, email=email, + is_admin=True, username=username, user_type_fd_id_select_field=user_type_fd_id_select_field, user_info_forms=user_info_forms, From 4be00d3058396ed30da4f6f0958ad6fa989249cb Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Thu, 23 Feb 2017 12:33:34 -0500 Subject: [PATCH 03/15] Strip out unnecessary user address editing. --- .../webapps/galaxy/user/manage_info.mako | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/templates/webapps/galaxy/user/manage_info.mako b/templates/webapps/galaxy/user/manage_info.mako index 8b1a747b662..0342174cc52 100644 --- a/templates/webapps/galaxy/user/manage_info.mako +++ b/templates/webapps/galaxy/user/manage_info.mako @@ -38,58 +38,3 @@ ${render_user_info()}

%endif - -

- -

-
-
User Addresses
-
- %if user.addresses: -
-
- %for i, filter in enumerate( ['Active', 'Deleted', 'All'] ): - %if i > 0: - | - %endif - %if show_filter == filter: - ${filter} - %else: - ${filter} - %endif - %endfor -
-
- - - %for index, address in enumerate(addresses): - - - - %endfor - -
-
- - ${address.get_html()} -
-
- -
-
- %endif -
- -
-
-
-
From 456acf0b84004c85c94d3129f0a89af9be2d5452 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Thu, 23 Feb 2017 12:59:08 -0500 Subject: [PATCH 04/15] Update docstring to explicitly mention this as a temporary endpoint. --- lib/galaxy/webapps/galaxy/controllers/user.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index 93013886660..f4219bcd52b 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -1195,6 +1195,14 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat @web.require_admin def edit_info( self, trans, cntrller, **kwd ): """ + TEMPORARY ENDPOINT - added back to support admin-level user info + editing prior to adminjs. This is code that was prematurely removed + from the user controller when the user-side admin functionality was + replaced. + + The method manage_user_info, which follows this, should also be removed + at that time. + Edit user information = username, email or password. """ params = util.Params( kwd ) @@ -1294,7 +1302,12 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat '''TEMPORARY ENDPOINT - added back to support admin-level user info editing prior to adminjs. This is code that was prematurely removed from the user controller when the user-side admin functionality was - replaced. Manage a user's login, password, public username, type, + replaced. + + When this is removed, templates/webapps/galaxy/user/manage_info.mako + should go as well. + + Manage a user's login, password, public username, type, addresses, etc.''' def __get_user_type_form_definition( trans, user=None, **kwd ): From b46ac475a93fbf0da71272861677a00a3877b91b Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Thu, 23 Feb 2017 13:01:11 -0500 Subject: [PATCH 05/15] Fix verbiage in temporary method. --- lib/galaxy/webapps/galaxy/controllers/user.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index f4219bcd52b..b5819d48c7c 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -1197,7 +1197,7 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat """ TEMPORARY ENDPOINT - added back to support admin-level user info editing prior to adminjs. This is code that was prematurely removed - from the user controller when the user-side admin functionality was + from the user controller when the user-side editing functionality was replaced. The method manage_user_info, which follows this, should also be removed @@ -1301,7 +1301,7 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat def manage_user_info( self, trans, cntrller, **kwd ): '''TEMPORARY ENDPOINT - added back to support admin-level user info editing prior to adminjs. This is code that was prematurely removed - from the user controller when the user-side admin functionality was + from the user controller when the user-side editing functionality was replaced. When this is removed, templates/webapps/galaxy/user/manage_info.mako From 0636053901545a26662ed8f42a15bb67407f2231 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Fri, 24 Feb 2017 10:53:29 -0500 Subject: [PATCH 06/15] Use pgcalc when possible --- lib/galaxy/webapps/galaxy/controllers/user.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index b5819d48c7c..d21c64d9951 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -17,6 +17,7 @@ from galaxy import model from galaxy import util from galaxy import web from galaxy.exceptions import ObjectInvalid +from galaxy.model.util import pgcalc from galaxy.security.validate_user_input import (transform_publicname, validate_email, validate_password, @@ -626,7 +627,11 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat refresh_frames = [ 'masthead', 'history' ] # Recalculate user disk usage. if trans.user: - trans.user.calculate_disk_usage() + if trans.sa_session.get_bind().dialect.name not in ( 'postgres', 'postgresql' ): + new = trans.user.calculate_disk_usage() + else: + new = pgcalc(trans.sa_session, trans.user.id) + trans.user.set_disk_usage(new) # Since logging an event requires a session, we'll log prior to ending the session trans.log_event( "User logged out" ) else: From 895351cdf8e8867452d28dffb89a2067eabfadb3 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Fri, 24 Feb 2017 12:34:42 -0500 Subject: [PATCH 07/15] initial working async recalc --- lib/galaxy/queue_worker.py | 34 ++++++++++++++++++- lib/galaxy/webapps/galaxy/controllers/user.py | 13 ++++--- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/lib/galaxy/queue_worker.py b/lib/galaxy/queue_worker.py index abbde5ed55d..c71facbd0df 100644 --- a/lib/galaxy/queue_worker.py +++ b/lib/galaxy/queue_worker.py @@ -9,6 +9,7 @@ import time import galaxy.queues from galaxy import util +from galaxy.model.util import pgcalc from kombu import Connection from kombu.mixins import ConsumerMixin @@ -18,6 +19,20 @@ logging.getLogger('kombu').setLevel(logging.WARNING) log = logging.getLogger(__name__) +def queue_async_task(app, task, kwargs={}): + log.info("Queuing async task %s." % task) + payload = {'task': task, + 'kwargs': kwargs} + try: + c = Connection(app.config.amqp_internal_connection) + with producers[c].acquire(block=True) as producer: + producer.publish(payload, exchange=galaxy.queues.galaxy_exchange, + declare=[galaxy.queues.galaxy_exchange].append(galaxy.queues.control_queue_from_config(app.config)), + routing_key='control') + except Exception: + log.exception("Error queueing async task: %s." % payload) + + def send_control_task(app, task, noop_self=False, kwargs={}): log.info("Sending %s control task." % task) payload = {'task': task, @@ -112,6 +127,22 @@ def reload_sanitize_whitelist(app): app.config.reload_sanitize_whitelist() +def recalculate_user_disk_usage(app, **kwargs): + user_id = kwargs.get('user_id', None) + sa_session = app.model.context + if user_id: + # user = sa_session.query( app.model.User ).get( trans.security.decode_id( user_id ) ) + user = sa_session.query( app.model.User ).get( user_id ) + if user: + if sa_session.get_bind().dialect.name not in ( 'postgres', 'postgresql' ): + new = user.calculate_disk_usage() + else: + new = pgcalc(sa_session, user.id) + user.set_disk_usage(new) + sa_session.add(user) + sa_session.flush() + + def reload_tool_data_tables(app, **kwargs): params = util.Params(kwargs) log.debug("Executing tool data table reload for %s" % params.get('table_names', 'all tables')) @@ -135,7 +166,8 @@ control_message_to_task = { 'create_panel_section': create_panel_section, 'reload_display_application': reload_display_application, 'reload_tool_data_tables': reload_tool_data_tables, 'admin_job_lock': admin_job_lock, - 'reload_sanitize_whitelist': reload_sanitize_whitelist} + 'reload_sanitize_whitelist': reload_sanitize_whitelist, + 'recalculate_user_disk_usage': recalculate_user_disk_usage} class GalaxyQueueWorker(ConsumerMixin, threading.Thread): diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index d21c64d9951..d81987e6cf2 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -17,7 +17,7 @@ from galaxy import model from galaxy import util from galaxy import web from galaxy.exceptions import ObjectInvalid -from galaxy.model.util import pgcalc +from galaxy.queue_worker import queue_async_task from galaxy.security.validate_user_input import (transform_publicname, validate_email, validate_password, @@ -625,13 +625,12 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat refresh_frames = [ 'masthead', 'history', 'tools' ] else: refresh_frames = [ 'masthead', 'history' ] - # Recalculate user disk usage. if trans.user: - if trans.sa_session.get_bind().dialect.name not in ( 'postgres', 'postgresql' ): - new = trans.user.calculate_disk_usage() - else: - new = pgcalc(trans.sa_session, trans.user.id) - trans.user.set_disk_usage(new) + # Send a queue recalculation + queue_async_task(trans.app, + 'recalculate_user_disk_usage', + # {'user_id': trans.security.encode_id(trans.user.id)}) + {'user_id': trans.user.id}) # Since logging an event requires a session, we'll log prior to ending the session trans.log_event( "User logged out" ) else: From 45d75e3da55e43a4444c1a7982e1ea31e1aa5cb7 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Fri, 24 Feb 2017 12:37:46 -0500 Subject: [PATCH 08/15] Encode userid in messages. --- lib/galaxy/queue_worker.py | 3 +-- lib/galaxy/webapps/galaxy/controllers/user.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/galaxy/queue_worker.py b/lib/galaxy/queue_worker.py index c71facbd0df..9aece940d5f 100644 --- a/lib/galaxy/queue_worker.py +++ b/lib/galaxy/queue_worker.py @@ -131,8 +131,7 @@ def recalculate_user_disk_usage(app, **kwargs): user_id = kwargs.get('user_id', None) sa_session = app.model.context if user_id: - # user = sa_session.query( app.model.User ).get( trans.security.decode_id( user_id ) ) - user = sa_session.query( app.model.User ).get( user_id ) + user = sa_session.query( app.model.User ).get( app.security.decode_id( user_id ) ) if user: if sa_session.get_bind().dialect.name not in ( 'postgres', 'postgresql' ): new = user.calculate_disk_usage() diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index d81987e6cf2..abac211a64e 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -629,8 +629,7 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat # Send a queue recalculation queue_async_task(trans.app, 'recalculate_user_disk_usage', - # {'user_id': trans.security.encode_id(trans.user.id)}) - {'user_id': trans.user.id}) + {'user_id': trans.security.encode_id(trans.user.id)}) # Since logging an event requires a session, we'll log prior to ending the session trans.log_event( "User logged out" ) else: From c373bf27e79e48bc2e8ba983e9f08abde16db4df Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Fri, 24 Feb 2017 14:23:22 -0500 Subject: [PATCH 09/15] Change handling of declare in queue_async_task --- lib/galaxy/queue_worker.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/queue_worker.py b/lib/galaxy/queue_worker.py index 9aece940d5f..2917351d680 100644 --- a/lib/galaxy/queue_worker.py +++ b/lib/galaxy/queue_worker.py @@ -26,8 +26,9 @@ def queue_async_task(app, task, kwargs={}): try: c = Connection(app.config.amqp_internal_connection) with producers[c].acquire(block=True) as producer: - producer.publish(payload, exchange=galaxy.queues.galaxy_exchange, - declare=[galaxy.queues.galaxy_exchange].append(galaxy.queues.control_queue_from_config(app.config)), + producer.publish(payload, + exchange=galaxy.queues.galaxy_exchange, + declare=[galaxy.queues.galaxy_exchange] + [galaxy.queues.control_queue_from_config(app.config)], routing_key='control') except Exception: log.exception("Error queueing async task: %s." % payload) From 00b1591f05af4743d8b16b7d1bbbbc99a3974adb Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Fri, 24 Feb 2017 12:40:01 -0800 Subject: [PATCH 10/15] Fix inline doc --- lib/galaxy/webapps/galaxy/controllers/user.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index abac211a64e..1817b036289 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -626,10 +626,11 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat else: refresh_frames = [ 'masthead', 'history' ] if trans.user: - # Send a queue recalculation - queue_async_task(trans.app, - 'recalculate_user_disk_usage', - {'user_id': trans.security.encode_id(trans.user.id)}) + # Queue a quota recalculation (async) task -- this takes a + # while sometimes, so we don't want to block on logout. + queue_async_task( trans.app, + 'recalculate_user_disk_usage', + {'user_id': trans.security.encode_id(trans.user.id)} ) # Since logging an event requires a session, we'll log prior to ending the session trans.log_event( "User logged out" ) else: From 5a5dbb97f1e04dfe15fbf71c441eb50ae4b70b11 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Sat, 25 Feb 2017 10:49:42 -0500 Subject: [PATCH 11/15] improve 17.01 get galaxy release notes --- doc/source/releases/17.01_announce.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/source/releases/17.01_announce.rst b/doc/source/releases/17.01_announce.rst index 97ae359e2a9..199dbbd68f4 100644 --- a/doc/source/releases/17.01_announce.rst +++ b/doc/source/releases/17.01_announce.rst @@ -29,15 +29,17 @@ Highlights Thanks to `@abretaud `__, `@ashvark `__, `@jvolkening `__, and `@mvdbeek `__. Implemented in `Pull Request 3145`_, `PullRequest 3510`_ and `PullRequest 3514`_. -`Github `__ -=========================================================== +Get Galaxy +========== -New Galaxy repository +The code lives at `Github `__ and you should have `Git `__ to obtain it. + +To get a new Galaxy repository run: .. code-block:: shell $ git clone -b release_17.01 https://github.com/galaxyproject/galaxy.git -Update of existing Galaxy repository +To update an existing Galaxy repository run: .. code-block:: shell $ git checkout release_17.01 && git pull --ff-only origin release_17.01 From 53c00df805e7ae7e509c08374bc941d31d20000d Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Sat, 25 Feb 2017 14:32:13 -0800 Subject: [PATCH 12/15] Rename send_local_controL_task, add at least a tiny bit of documentation. --- lib/galaxy/queue_worker.py | 11 ++++++++++- lib/galaxy/webapps/galaxy/controllers/user.py | 8 ++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/galaxy/queue_worker.py b/lib/galaxy/queue_worker.py index 2917351d680..0ca7b928d77 100644 --- a/lib/galaxy/queue_worker.py +++ b/lib/galaxy/queue_worker.py @@ -19,7 +19,11 @@ logging.getLogger('kombu').setLevel(logging.WARNING) log = logging.getLogger(__name__) -def queue_async_task(app, task, kwargs={}): +def send_local_control_task(app, task, kwargs={}): + """ + This sends a message to the process-local control worker, which is useful + for one-time asynchronous tasks like recalculating user disk usage. + """ log.info("Queuing async task %s." % task) payload = {'task': task, 'kwargs': kwargs} @@ -35,6 +39,11 @@ def queue_async_task(app, task, kwargs={}): def send_control_task(app, task, noop_self=False, kwargs={}): + """ + This sends a control task out to all processes, useful for things like + reloading a data table, which needs to happen individually in all + processes. + """ log.info("Sending %s control task." % task) payload = {'task': task, 'kwargs': kwargs} diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index 1817b036289..471b20dee7c 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -17,7 +17,7 @@ from galaxy import model from galaxy import util from galaxy import web from galaxy.exceptions import ObjectInvalid -from galaxy.queue_worker import queue_async_task +from galaxy.queue_worker import send_local_control_task from galaxy.security.validate_user_input import (transform_publicname, validate_email, validate_password, @@ -628,9 +628,9 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat if trans.user: # Queue a quota recalculation (async) task -- this takes a # while sometimes, so we don't want to block on logout. - queue_async_task( trans.app, - 'recalculate_user_disk_usage', - {'user_id': trans.security.encode_id(trans.user.id)} ) + send_local_control_task( trans.app, + 'recalculate_user_disk_usage', + {'user_id': trans.security.encode_id(trans.user.id)} ) # Since logging an event requires a session, we'll log prior to ending the session trans.log_event( "User logged out" ) else: From 0997348a1c0a450986d376a96af024c73d4c7f37 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Tue, 28 Feb 2017 16:03:47 -0500 Subject: [PATCH 13/15] fix tool search idnex building for tools with / in id and not from TS --- lib/galaxy/tools/search/__init__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/galaxy/tools/search/__init__.py b/lib/galaxy/tools/search/__init__.py index 2e30f5d7845..19a53225437 100644 --- a/lib/galaxy/tools/search/__init__.py +++ b/lib/galaxy/tools/search/__init__.py @@ -49,8 +49,9 @@ class ToolBoxSearch( object ): self.build_index( index_help ) def build_index( self, index_help=True ): - # Works around https://bitbucket.org/mchaput/whoosh/issues/391/race-conditions-with-temp-storage + """Prepare search index for tools loaded in toolbox.""" RamStorage.temp_storage = _temp_storage + # Works around https://bitbucket.org/mchaput/whoosh/issues/391/race-conditions-with-temp-storage self.storage = RamStorage() self.index = self.storage.create_index( self.schema ) writer = self.index.writer() @@ -66,16 +67,15 @@ class ToolBoxSearch( object ): "section": to_unicode( tool.get_panel_section()[1] if len( tool.get_panel_section() ) == 2 else '' ), "help": to_unicode( "" ) } - # Hyphens are wildcards in Whoosh causing bad things if tool.name.find( '-' ) != -1: + # Hyphens are wildcards in Whoosh causing bad things add_doc_kwds['name'] = (' ').join( [ token.text for token in self.rex( to_unicode( tool.name ) ) ] ) else: add_doc_kwds['name'] = to_unicode( tool.name ) - # We do not want to search Tool Shed or version parts - # of the long ids - if id.find( '/' ) != -1: - slash_indexes = [ m.start() for m in re.finditer( '/', id ) ] - id_stub = id[ ( slash_indexes[1] + 1 ): slash_indexes[4] ] + if tool.guid: + # Crate a stub consisting of owner, repo, and tool from guid + slash_indexes = [ m.start() for m in re.finditer( '/', tool.guid ) ] + id_stub = tool.guid[ ( slash_indexes[1] + 1 ): slash_indexes[4] ] add_doc_kwds['stub'] = (' ').join( [ token.text for token in self.rex( to_unicode( id_stub ) ) ] ) else: add_doc_kwds['stub'] = to_unicode( id ) From c11cb3dd4572e7a4f1f814a31a45477f9ecd5ae9 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Tue, 28 Feb 2017 16:13:13 -0500 Subject: [PATCH 14/15] fix typo spotted by :beer: :eyes: --- lib/galaxy/tools/search/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/tools/search/__init__.py b/lib/galaxy/tools/search/__init__.py index 19a53225437..489bc4d125f 100644 --- a/lib/galaxy/tools/search/__init__.py +++ b/lib/galaxy/tools/search/__init__.py @@ -73,7 +73,7 @@ class ToolBoxSearch( object ): else: add_doc_kwds['name'] = to_unicode( tool.name ) if tool.guid: - # Crate a stub consisting of owner, repo, and tool from guid + # Create a stub consisting of owner, repo, and tool from guid slash_indexes = [ m.start() for m in re.finditer( '/', tool.guid ) ] id_stub = tool.guid[ ( slash_indexes[1] + 1 ): slash_indexes[4] ] add_doc_kwds['stub'] = (' ').join( [ token.text for token in self.rex( to_unicode( id_stub ) ) ] ) From 169b45b138685164010043be95cefe8148c6f713 Mon Sep 17 00:00:00 2001 From: guerler Date: Tue, 28 Feb 2017 17:24:20 -0500 Subject: [PATCH 15/15] Fix step name display for 17.01 --- lib/galaxy/managers/workflows.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/managers/workflows.py b/lib/galaxy/managers/workflows.py index 9b771998f34..bf99eb8be2f 100644 --- a/lib/galaxy/managers/workflows.py +++ b/lib/galaxy/managers/workflows.py @@ -398,8 +398,12 @@ class WorkflowContentsManager(UsesAnnotations): step_model["name"] = step_title(step, step_model.get("name")) else: inputs = step.module.get_runtime_inputs( connections=step.output_connections ) + step_name = step.module.name + if hasattr( step, 'tool_inputs' ): + if isinstance( step.tool_inputs, dict ): + step_name = step.tool_inputs.get( 'name' ) or step_name step_model = { - 'name' : step_title(step, step.module.name), + 'name' : step_title(step, step_name), 'inputs' : [ input.to_dict( trans ) for input in inputs.itervalues() ] } step_model[ 'step_type' ] = step.type