2 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/04a072e98658/ Changeset: 04a072e98658 Branch: next-stable User: carlfeberhard Date: 2014-11-25 19:22:08+00:00 Summary: Sanitize tag output in tagging_common and user.tags_used; protect against closing tags in bootstrapped JSON (http://benalpert.com/2012/08/03/preventing-xss-json.html); minor fixes Affected #: 8 files diff -r c53f747732a115c7ec6ed3e192bb059d12266865 -r 04a072e98658bb4a386726ece90b8efc7f6a5f69 lib/galaxy/tags/tag_handler.py --- a/lib/galaxy/tags/tag_handler.py +++ b/lib/galaxy/tags/tag_handler.py @@ -1,5 +1,7 @@ -import re, logging -from sqlalchemy.sql.expression import func, and_ +import re +import logging +from sqlalchemy.sql.expression import func +from sqlalchemy.sql.expression import and_ from sqlalchemy.sql import select log = logging.getLogger( __name__ ) @@ -25,12 +27,15 @@ self.key_value_separators = "=:" # Initialize with known classes - add to this in subclasses. self.item_tag_assoc_info = {} + def get_tag_assoc_class( self, item_class ): """Returns tag association class for item class.""" return self.item_tag_assoc_info[item_class.__name__].tag_assoc_class + def get_id_col_in_item_tag_assoc_table( self, item_class ): """Returns item id column in class' item-tag association table.""" return self.item_tag_assoc_info[item_class.__name__].item_id_col + def get_community_tags( self, trans, item=None, limit=None ): """Returns community tags for an item.""" # Get item-tag association class. @@ -58,6 +63,7 @@ tag_id = row[0] community_tags.append( self.get_tag_by_id( trans, tag_id ) ) return community_tags + def get_tool_tags( self, trans ): result_set = trans.sa_session.execute( select( columns=[ trans.app.model.ToolTagAssociation.table.c.tag_id ], from_obj=trans.app.model.ToolTagAssociation.table ).distinct() ) @@ -67,6 +73,7 @@ tag_id = row[0] tags.append( self.get_tag_by_id( trans, tag_id ) ) return tags + def remove_item_tag( self, trans, user, item, tag_name ): """Remove a tag from an item.""" # Get item tag association. @@ -78,6 +85,7 @@ item.tags.remove( item_tag_assoc ) return True return False + def delete_item_tags( self, trans, user, item ): """Delete tags from an item.""" # Delete item-tag associations. @@ -85,6 +93,7 @@ trans.sa_session.delete( tag ) # Delete tags from item. del item.tags[:] + def item_has_tag( self, trans, user, item, tag ): """Returns true if item is has a given tag.""" # Get tag name. @@ -97,6 +106,7 @@ if item_tag_assoc: return True return False + def apply_item_tag( self, trans, user, item, name, value=None ): # Use lowercase name for searching/creating tag. lc_name = name.lower() @@ -124,6 +134,7 @@ item_tag_assoc.user_value = value item_tag_assoc.value = lc_value return item_tag_assoc + def apply_item_tags( self, trans, user, item, tags_str ): """Apply tags to an item.""" # Parse tags. @@ -131,6 +142,7 @@ # Apply each tag. for name, value in parsed_tags.items(): self.apply_item_tag( trans, user, item, name, value ) + def get_tags_str( self, tags ): """Build a string from an item's tags.""" # Return empty string if there are no tags. @@ -144,14 +156,17 @@ tag_str += ":" + tag.user_value tags_str_list.append( tag_str ) return ", ".join( tags_str_list ) + def get_tag_by_id( self, trans, tag_id ): """Get a Tag object from a tag id.""" return trans.sa_session.query( trans.app.model.Tag ).filter_by( id=tag_id ).first() + def get_tag_by_name( self, trans, tag_name ): """Get a Tag object from a tag name (string).""" if tag_name: return trans.sa_session.query( trans.app.model.Tag ).filter_by( name=tag_name.lower() ).first() return None + def _create_tag( self, trans, tag_str ): """Create a Tag object from a tag string.""" tag_hierarchy = tag_str.split( self.hierarchy_separator ) @@ -169,6 +184,7 @@ parent_tag = tag tag_prefix = tag.name + self.hierarchy_separator return tag + def _get_or_create_tag( self, trans, tag_str ): """Get or create a Tag object from a tag string.""" # Scrub tag; if tag is None after being scrubbed, return None. @@ -181,6 +197,7 @@ if tag is None: tag = self._create_tag( trans, scrubbed_tag_str ) return tag + def _get_item_tag_assoc( self, user, item, tag_name ): """ Return ItemTagAssociation object for a user, item, and tag string; returns None if there is @@ -191,6 +208,7 @@ if ( item_tag_assoc.user == user ) and ( item_tag_assoc.user_tname == scrubbed_tag_name ): return item_tag_assoc return None + def parse_tags( self, tag_str ): """ Returns a list of raw (tag-name, value) pairs derived from a string; method scrubs tag names and values as well. @@ -210,6 +228,7 @@ scrubbed_value = self._scrub_tag_value( nv_pair[1] ) name_value_pairs[scrubbed_name] = scrubbed_value return name_value_pairs + def _scrub_tag_value( self, value ): """Scrub a tag value.""" # Gracefully handle None: @@ -219,6 +238,7 @@ reg_exp = re.compile( '\s' ) scrubbed_value = re.sub( reg_exp, "", value ) return scrubbed_value + def _scrub_tag_name( self, name ): """Scrub a tag name.""" # Gracefully handle None: @@ -234,12 +254,14 @@ if len( scrubbed_name ) < self.min_tag_len or len( scrubbed_name ) > self.max_tag_len: return None return scrubbed_name + def _scrub_tag_name_list( self, tag_name_list ): """Scrub a tag name list.""" scrubbed_tag_list = list() for tag in tag_name_list: scrubbed_tag_list.append( self._scrub_tag_name( tag ) ) return scrubbed_tag_list + def _get_name_value_pair( self, tag_str ): """Get name, value pair from a tag string.""" # Use regular expression to parse name, value. @@ -250,6 +272,7 @@ name_value_pair.append( None ) return name_value_pair + class GalaxyTagHandler( TagHandler ): def __init__( self ): from galaxy import model @@ -271,6 +294,7 @@ model.VisualizationTagAssociation, model.VisualizationTagAssociation.table.c.visualization_id ) + class CommunityTagHandler( TagHandler ): def __init__( self ): from galaxy.webapps.tool_shed import model diff -r c53f747732a115c7ec6ed3e192bb059d12266865 -r 04a072e98658bb4a386726ece90b8efc7f6a5f69 lib/galaxy/util/json.py --- a/lib/galaxy/util/json.py +++ b/lib/galaxy/util/json.py @@ -52,7 +52,7 @@ return val -def safe_dumps(*args, **kwargs): +def safe_dumps( *args, **kwargs ): """ This is a wrapper around dumps that encodes Infinity and NaN values. It's a fairly rare case (which will be low in request volume). Basically, we tell @@ -60,10 +60,12 @@ re-encoding. """ try: - dumped = json.dumps(*args, allow_nan=False, **kwargs) + dumped = json.dumps( *args, allow_nan=False, **kwargs ) except ValueError: - obj = swap_inf_nan(copy.deepcopy(args[0])) - dumped = json.dumps(obj, allow_nan=False, **kwargs) + obj = swap_inf_nan( copy.deepcopy( args[0] ) ) + dumped = json.dumps( obj, allow_nan=False, **kwargs ) + if kwargs.get( 'escape_closing_tags', True ): + return dumped.replace( '</', '<\\/' ) return dumped diff -r c53f747732a115c7ec6ed3e192bb059d12266865 -r 04a072e98658bb4a386726ece90b8efc7f6a5f69 lib/galaxy/util/validation.py --- a/lib/galaxy/util/validation.py +++ b/lib/galaxy/util/validation.py @@ -8,8 +8,8 @@ def validate_and_sanitize_basestring( key, val ): if not isinstance( val, basestring ): - raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s' - % ( key, str( type( val ) ) ) ) + raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s' + % ( key, str( type( val ) ) ) ) return unicode( sanitize_html( val, 'utf-8', 'text/html' ), 'utf-8' ) diff -r c53f747732a115c7ec6ed3e192bb059d12266865 -r 04a072e98658bb4a386726ece90b8efc7f6a5f69 lib/galaxy/web/framework/helpers/__init__.py --- a/lib/galaxy/web/framework/helpers/__init__.py +++ b/lib/galaxy/web/framework/helpers/__init__.py @@ -111,4 +111,3 @@ Returns true if input is a boolean and true or is a string and looks like a true value. """ return val == True or val in [ 'True', 'true', 'T', 't' ] - diff -r c53f747732a115c7ec6ed3e192bb059d12266865 -r 04a072e98658bb4a386726ece90b8efc7f6a5f69 lib/galaxy/webapps/galaxy/controllers/tag.py --- a/lib/galaxy/webapps/galaxy/controllers/tag.py +++ b/lib/galaxy/webapps/galaxy/controllers/tag.py @@ -64,7 +64,7 @@ trans.log_action( user, unicode( "untag" ), context, params ) # Retag an item. All previous tags are deleted and new tags are applied. - #@web.expose + @web.expose @web.require_login( "Apply a new set of tags to an item; previous tags are deleted." ) def retag_async( self, trans, item_id=None, item_class=None, new_tags=None ): """ @@ -73,7 +73,7 @@ # Apply tags. item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) ) user = trans.user - self.get_tag_handler( trans ).delete_item_tags( trans, item ) + self.get_tag_handler( trans ).delete_item_tags( trans, user, item ) self.get_tag_handler( trans ).apply_item_tags( trans, user, item, new_tags.encode( 'utf-8' ) ) trans.sa_session.flush() diff -r c53f747732a115c7ec6ed3e192bb059d12266865 -r 04a072e98658bb4a386726ece90b8efc7f6a5f69 templates/galaxy_client_app.mako --- a/templates/galaxy_client_app.mako +++ b/templates/galaxy_client_app.mako @@ -15,7 +15,7 @@ //TODO: global... %for key in kwargs: ( window.bootstrapped = window.bootstrapped || {} )[ '${key}' ] = ( - ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) )} ); + ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) ).replace( '</', '<\\/' ) } ); %endfor define( 'bootstrapped-data', function(){ return window.bootstrapped; @@ -76,11 +76,17 @@ user_dict = trans.user.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id, 'total_disk_usage': float } ) user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans ) + user_dict[ 'is_admin' ] = trans.user_is_admin() # tags used users_api_controller = trans.webapp.api_controllers[ 'users' ] - user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user ) - user_dict[ 'is_admin' ] = trans.user_is_admin() + tags_used = [] + for tag in users_api_controller.get_user_tags_used( trans, user=trans.user ): + tag = tag | h + if tag: + tags_used.append( tag ) + user_dict[ 'tags_used' ] = tags_used + return user_dict usage = 0 diff -r c53f747732a115c7ec6ed3e192bb059d12266865 -r 04a072e98658bb4a386726ece90b8efc7f6a5f69 templates/tagging_common.mako --- a/templates/tagging_common.mako +++ b/templates/tagging_common.mako @@ -19,7 +19,7 @@ ## Render HTML for a list of tags. <%def name="render_tagging_element_html(elt_id=None, tags=None, editable=True, use_toggle_link=True, input_size='15', in_form=False, tag_type='individual', render_add_tag_button=True)"> ## Useful attributes. - <% + <% num_tags = len( tags ) %><div class="tag-element" @@ -50,6 +50,7 @@ elif isinstance( tag, ItemTagAssociation ): tag_name = tag.user_tname tag_value = tag.user_value + ## Convert tag name, value to unicode. if isinstance( tag_name, str ): tag_name = unicode( escape( tag_name ), 'utf-8' ) @@ -61,7 +62,7 @@ tag_str = tag_name %><span class="tag-button"> - <span class="tag-name">${tag_str}</span> + <span class="tag-name">${tag_str | h}</span> %if editable: <img class="delete-tag-img" src="${h.url_for('/static/images/delete_tag_icon_gray.png')}"/> %endif @@ -186,10 +187,11 @@ ## Build dict of tag name, values. tag_names_and_values = dict() for tag in item_tags: - tag_name = tag.user_tname + tag_name = escape( tag.user_tname ) tag_value = "" if tag.value is not None: - tag_value = tag.user_value + tag_value = escape( tag.user_value ) + ## Tag names and values may be string or unicode object. if isinstance( tag_name, str ): tag_names_and_values[unicode(tag_name, 'utf-8')] = unicode(tag_value, 'utf-8') diff -r c53f747732a115c7ec6ed3e192bb059d12266865 -r 04a072e98658bb4a386726ece90b8efc7f6a5f69 templates/webapps/galaxy/galaxy.masthead.mako --- a/templates/webapps/galaxy/galaxy.masthead.mako +++ b/templates/webapps/galaxy/galaxy.masthead.mako @@ -1,32 +1,4 @@ -## get user data -<%def name="get_user_json()"> -<% - """Bootstrapping user API JSON""" - #TODO: move into common location (poss. BaseController) - if trans.user: - user_dict = trans.user.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id, - 'total_disk_usage': float } ) - user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans ) - users_api_controller = trans.webapp.api_controllers[ 'users' ] - user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user ) - user_dict[ 'is_admin' ] = trans.user_is_admin() - else: - usage = 0 - percent = None - try: - usage = trans.app.quota_agent.get_usage( trans, history=trans.history ) - percent = trans.app.quota_agent.get_percent( trans=trans, usage=usage ) - except AssertionError, assertion: - # no history for quota_agent.get_usage assertion - pass - user_dict = { - 'total_disk_usage' : int( usage ), - 'nice_total_disk_usage' : util.nice_size( usage ), - 'quota_percent' : percent - } - return user_dict -%> -</%def> +<%namespace file="/galaxy_client_app.mako" import="get_user_json" /> ## masthead head generator <%def name="load(active_view = None)"> @@ -87,7 +59,7 @@ ], function( mod_masthead, mod_menu, mod_modal, mod_frame, GalaxyUpload, user, quotameter ){ if( !Galaxy.currUser ){ // this doesn't need to wait for the page being readied - Galaxy.currUser = new user.User(${ h.dumps( get_user_json(), indent=2 ) }); + Galaxy.currUser = new user.User(${ h.dumps( masthead_config[ 'user' ][ 'json' ], indent=2 ) }); } $(function() { https://bitbucket.org/galaxy/galaxy-central/commits/123b9f6a67cc/ Changeset: 123b9f6a67cc User: carlfeberhard Date: 2014-11-25 19:22:27+00:00 Summary: merge Affected #: 8 files diff -r c0a41931fcfc00b52423667d33910eeb59cf5ac6 -r 123b9f6a67cce32f205103ee2d2a4f6ca72f6901 lib/galaxy/tags/tag_handler.py --- a/lib/galaxy/tags/tag_handler.py +++ b/lib/galaxy/tags/tag_handler.py @@ -1,5 +1,7 @@ -import re, logging -from sqlalchemy.sql.expression import func, and_ +import re +import logging +from sqlalchemy.sql.expression import func +from sqlalchemy.sql.expression import and_ from sqlalchemy.sql import select log = logging.getLogger( __name__ ) @@ -25,12 +27,15 @@ self.key_value_separators = "=:" # Initialize with known classes - add to this in subclasses. self.item_tag_assoc_info = {} + def get_tag_assoc_class( self, item_class ): """Returns tag association class for item class.""" return self.item_tag_assoc_info[item_class.__name__].tag_assoc_class + def get_id_col_in_item_tag_assoc_table( self, item_class ): """Returns item id column in class' item-tag association table.""" return self.item_tag_assoc_info[item_class.__name__].item_id_col + def get_community_tags( self, trans, item=None, limit=None ): """Returns community tags for an item.""" # Get item-tag association class. @@ -58,6 +63,7 @@ tag_id = row[0] community_tags.append( self.get_tag_by_id( trans, tag_id ) ) return community_tags + def get_tool_tags( self, trans ): result_set = trans.sa_session.execute( select( columns=[ trans.app.model.ToolTagAssociation.table.c.tag_id ], from_obj=trans.app.model.ToolTagAssociation.table ).distinct() ) @@ -67,6 +73,7 @@ tag_id = row[0] tags.append( self.get_tag_by_id( trans, tag_id ) ) return tags + def remove_item_tag( self, trans, user, item, tag_name ): """Remove a tag from an item.""" # Get item tag association. @@ -78,6 +85,7 @@ item.tags.remove( item_tag_assoc ) return True return False + def delete_item_tags( self, trans, user, item ): """Delete tags from an item.""" # Delete item-tag associations. @@ -85,6 +93,7 @@ trans.sa_session.delete( tag ) # Delete tags from item. del item.tags[:] + def item_has_tag( self, trans, user, item, tag ): """Returns true if item is has a given tag.""" # Get tag name. @@ -97,6 +106,7 @@ if item_tag_assoc: return True return False + def apply_item_tag( self, trans, user, item, name, value=None ): # Use lowercase name for searching/creating tag. lc_name = name.lower() @@ -124,6 +134,7 @@ item_tag_assoc.user_value = value item_tag_assoc.value = lc_value return item_tag_assoc + def apply_item_tags( self, trans, user, item, tags_str ): """Apply tags to an item.""" # Parse tags. @@ -131,6 +142,7 @@ # Apply each tag. for name, value in parsed_tags.items(): self.apply_item_tag( trans, user, item, name, value ) + def get_tags_str( self, tags ): """Build a string from an item's tags.""" # Return empty string if there are no tags. @@ -144,14 +156,17 @@ tag_str += ":" + tag.user_value tags_str_list.append( tag_str ) return ", ".join( tags_str_list ) + def get_tag_by_id( self, trans, tag_id ): """Get a Tag object from a tag id.""" return trans.sa_session.query( trans.app.model.Tag ).filter_by( id=tag_id ).first() + def get_tag_by_name( self, trans, tag_name ): """Get a Tag object from a tag name (string).""" if tag_name: return trans.sa_session.query( trans.app.model.Tag ).filter_by( name=tag_name.lower() ).first() return None + def _create_tag( self, trans, tag_str ): """Create a Tag object from a tag string.""" tag_hierarchy = tag_str.split( self.hierarchy_separator ) @@ -169,6 +184,7 @@ parent_tag = tag tag_prefix = tag.name + self.hierarchy_separator return tag + def _get_or_create_tag( self, trans, tag_str ): """Get or create a Tag object from a tag string.""" # Scrub tag; if tag is None after being scrubbed, return None. @@ -181,6 +197,7 @@ if tag is None: tag = self._create_tag( trans, scrubbed_tag_str ) return tag + def _get_item_tag_assoc( self, user, item, tag_name ): """ Return ItemTagAssociation object for a user, item, and tag string; returns None if there is @@ -191,6 +208,7 @@ if ( item_tag_assoc.user == user ) and ( item_tag_assoc.user_tname == scrubbed_tag_name ): return item_tag_assoc return None + def parse_tags( self, tag_str ): """ Returns a list of raw (tag-name, value) pairs derived from a string; method scrubs tag names and values as well. @@ -210,6 +228,7 @@ scrubbed_value = self._scrub_tag_value( nv_pair[1] ) name_value_pairs[scrubbed_name] = scrubbed_value return name_value_pairs + def _scrub_tag_value( self, value ): """Scrub a tag value.""" # Gracefully handle None: @@ -219,6 +238,7 @@ reg_exp = re.compile( '\s' ) scrubbed_value = re.sub( reg_exp, "", value ) return scrubbed_value + def _scrub_tag_name( self, name ): """Scrub a tag name.""" # Gracefully handle None: @@ -234,12 +254,14 @@ if len( scrubbed_name ) < self.min_tag_len or len( scrubbed_name ) > self.max_tag_len: return None return scrubbed_name + def _scrub_tag_name_list( self, tag_name_list ): """Scrub a tag name list.""" scrubbed_tag_list = list() for tag in tag_name_list: scrubbed_tag_list.append( self._scrub_tag_name( tag ) ) return scrubbed_tag_list + def _get_name_value_pair( self, tag_str ): """Get name, value pair from a tag string.""" # Use regular expression to parse name, value. @@ -250,6 +272,7 @@ name_value_pair.append( None ) return name_value_pair + class GalaxyTagHandler( TagHandler ): def __init__( self ): from galaxy import model @@ -271,6 +294,7 @@ model.VisualizationTagAssociation, model.VisualizationTagAssociation.table.c.visualization_id ) + class CommunityTagHandler( TagHandler ): def __init__( self ): from galaxy.webapps.tool_shed import model diff -r c0a41931fcfc00b52423667d33910eeb59cf5ac6 -r 123b9f6a67cce32f205103ee2d2a4f6ca72f6901 lib/galaxy/util/json.py --- a/lib/galaxy/util/json.py +++ b/lib/galaxy/util/json.py @@ -52,7 +52,7 @@ return val -def safe_dumps(*args, **kwargs): +def safe_dumps( *args, **kwargs ): """ This is a wrapper around dumps that encodes Infinity and NaN values. It's a fairly rare case (which will be low in request volume). Basically, we tell @@ -60,10 +60,12 @@ re-encoding. """ try: - dumped = json.dumps(*args, allow_nan=False, **kwargs) + dumped = json.dumps( *args, allow_nan=False, **kwargs ) except ValueError: - obj = swap_inf_nan(copy.deepcopy(args[0])) - dumped = json.dumps(obj, allow_nan=False, **kwargs) + obj = swap_inf_nan( copy.deepcopy( args[0] ) ) + dumped = json.dumps( obj, allow_nan=False, **kwargs ) + if kwargs.get( 'escape_closing_tags', True ): + return dumped.replace( '</', '<\\/' ) return dumped diff -r c0a41931fcfc00b52423667d33910eeb59cf5ac6 -r 123b9f6a67cce32f205103ee2d2a4f6ca72f6901 lib/galaxy/util/validation.py --- a/lib/galaxy/util/validation.py +++ b/lib/galaxy/util/validation.py @@ -8,8 +8,8 @@ def validate_and_sanitize_basestring( key, val ): if not isinstance( val, basestring ): - raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s' - % ( key, str( type( val ) ) ) ) + raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s' + % ( key, str( type( val ) ) ) ) return unicode( sanitize_html( val, 'utf-8', 'text/html' ), 'utf-8' ) diff -r c0a41931fcfc00b52423667d33910eeb59cf5ac6 -r 123b9f6a67cce32f205103ee2d2a4f6ca72f6901 lib/galaxy/web/framework/helpers/__init__.py --- a/lib/galaxy/web/framework/helpers/__init__.py +++ b/lib/galaxy/web/framework/helpers/__init__.py @@ -111,4 +111,3 @@ Returns true if input is a boolean and true or is a string and looks like a true value. """ return val == True or val in [ 'True', 'true', 'T', 't' ] - diff -r c0a41931fcfc00b52423667d33910eeb59cf5ac6 -r 123b9f6a67cce32f205103ee2d2a4f6ca72f6901 lib/galaxy/webapps/galaxy/controllers/tag.py --- a/lib/galaxy/webapps/galaxy/controllers/tag.py +++ b/lib/galaxy/webapps/galaxy/controllers/tag.py @@ -64,7 +64,7 @@ trans.log_action( user, unicode( "untag" ), context, params ) # Retag an item. All previous tags are deleted and new tags are applied. - #@web.expose + @web.expose @web.require_login( "Apply a new set of tags to an item; previous tags are deleted." ) def retag_async( self, trans, item_id=None, item_class=None, new_tags=None ): """ @@ -73,7 +73,7 @@ # Apply tags. item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) ) user = trans.user - self.get_tag_handler( trans ).delete_item_tags( trans, item ) + self.get_tag_handler( trans ).delete_item_tags( trans, user, item ) self.get_tag_handler( trans ).apply_item_tags( trans, user, item, new_tags.encode( 'utf-8' ) ) trans.sa_session.flush() diff -r c0a41931fcfc00b52423667d33910eeb59cf5ac6 -r 123b9f6a67cce32f205103ee2d2a4f6ca72f6901 templates/galaxy_client_app.mako --- a/templates/galaxy_client_app.mako +++ b/templates/galaxy_client_app.mako @@ -15,7 +15,7 @@ //TODO: global... %for key in kwargs: ( window.bootstrapped = window.bootstrapped || {} )[ '${key}' ] = ( - ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) )} ); + ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) ).replace( '</', '<\\/' ) } ); %endfor define( 'bootstrapped-data', function(){ return window.bootstrapped; @@ -76,11 +76,17 @@ user_dict = trans.user.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id, 'total_disk_usage': float } ) user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans ) + user_dict[ 'is_admin' ] = trans.user_is_admin() # tags used users_api_controller = trans.webapp.api_controllers[ 'users' ] - user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user ) - user_dict[ 'is_admin' ] = trans.user_is_admin() + tags_used = [] + for tag in users_api_controller.get_user_tags_used( trans, user=trans.user ): + tag = tag | h + if tag: + tags_used.append( tag ) + user_dict[ 'tags_used' ] = tags_used + return user_dict usage = 0 diff -r c0a41931fcfc00b52423667d33910eeb59cf5ac6 -r 123b9f6a67cce32f205103ee2d2a4f6ca72f6901 templates/tagging_common.mako --- a/templates/tagging_common.mako +++ b/templates/tagging_common.mako @@ -19,7 +19,7 @@ ## Render HTML for a list of tags. <%def name="render_tagging_element_html(elt_id=None, tags=None, editable=True, use_toggle_link=True, input_size='15', in_form=False, tag_type='individual', render_add_tag_button=True)"> ## Useful attributes. - <% + <% num_tags = len( tags ) %><div class="tag-element" @@ -50,6 +50,7 @@ elif isinstance( tag, ItemTagAssociation ): tag_name = tag.user_tname tag_value = tag.user_value + ## Convert tag name, value to unicode. if isinstance( tag_name, str ): tag_name = unicode( escape( tag_name ), 'utf-8' ) @@ -61,7 +62,7 @@ tag_str = tag_name %><span class="tag-button"> - <span class="tag-name">${tag_str}</span> + <span class="tag-name">${tag_str | h}</span> %if editable: <img class="delete-tag-img" src="${h.url_for('/static/images/delete_tag_icon_gray.png')}"/> %endif @@ -186,10 +187,11 @@ ## Build dict of tag name, values. tag_names_and_values = dict() for tag in item_tags: - tag_name = tag.user_tname + tag_name = escape( tag.user_tname ) tag_value = "" if tag.value is not None: - tag_value = tag.user_value + tag_value = escape( tag.user_value ) + ## Tag names and values may be string or unicode object. if isinstance( tag_name, str ): tag_names_and_values[unicode(tag_name, 'utf-8')] = unicode(tag_value, 'utf-8') diff -r c0a41931fcfc00b52423667d33910eeb59cf5ac6 -r 123b9f6a67cce32f205103ee2d2a4f6ca72f6901 templates/webapps/galaxy/galaxy.masthead.mako --- a/templates/webapps/galaxy/galaxy.masthead.mako +++ b/templates/webapps/galaxy/galaxy.masthead.mako @@ -1,32 +1,4 @@ -## get user data -<%def name="get_user_json()"> -<% - """Bootstrapping user API JSON""" - #TODO: move into common location (poss. BaseController) - if trans.user: - user_dict = trans.user.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id, - 'total_disk_usage': float } ) - user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans ) - users_api_controller = trans.webapp.api_controllers[ 'users' ] - user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user ) - user_dict[ 'is_admin' ] = trans.user_is_admin() - else: - usage = 0 - percent = None - try: - usage = trans.app.quota_agent.get_usage( trans, history=trans.history ) - percent = trans.app.quota_agent.get_percent( trans=trans, usage=usage ) - except AssertionError, assertion: - # no history for quota_agent.get_usage assertion - pass - user_dict = { - 'total_disk_usage' : int( usage ), - 'nice_total_disk_usage' : util.nice_size( usage ), - 'quota_percent' : percent - } - return user_dict -%> -</%def> +<%namespace file="/galaxy_client_app.mako" import="get_user_json" /> ## masthead head generator <%def name="load(active_view = None)"> @@ -87,7 +59,7 @@ ], function( mod_masthead, mod_menu, mod_modal, mod_frame, GalaxyUpload, user, quotameter ){ if( !Galaxy.currUser ){ // this doesn't need to wait for the page being readied - Galaxy.currUser = new user.User(${ h.dumps( get_user_json(), indent=2 ) }); + Galaxy.currUser = new user.User(${ h.dumps( masthead_config[ 'user' ][ 'json' ], indent=2 ) }); } $(function() { Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.