3 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/99dad50eb440/ Changeset: 99dad50eb440 User: jmchilton Date: 2013-04-20 08:33:57 Summary: Implement dynamic toolbox filters. Overview: Right now these filters are implemented via python code, but a higher level configuration mechanism could be implemented on top of this one easily. Added the well documented file lib/galaxy/tools/filters/examples.py.sample that outlines the implementations of some possible filters and how to configure them in universe_wsgi.ini. Implementation: Refactored Toolbox.to_dict and remove Tool._is_hidden_for_user, moving and unifying all filter building functionality into tools/filters/__init.py. Implemented new dynamic filters for tools, labels, and sections. Multiple such filters can be specified by giving module (relative to galaxy.tools.filters) and function names for each as comma seperated list to the respective options tool_filters, tool_label_filters, and tool_section_filters in universe_wsgi.ini. Explicit example lines to add to universe_wsgi.ini can be found in examples.py.sample (described above). WARNING: This mechanism only controls what tools are visible to the user. I imagine a savy user could call any tool by building custom requests or utilizing the API, to truely block users from accessing certain tools I recommend using the dynamic job runners. Affected #: 4 files diff -r 8d72c9adccf92f8a1971ec7d9b622de43cbd6f48 -r 99dad50eb44062d66d41f609afac00d23cbf4899 lib/galaxy/config.py --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -64,6 +64,9 @@ tcf = kwargs[ 'tool_config_files' ] else: tcf = 'tool_conf.xml' + self.tool_filters = listify( kwargs.get( "tool_filters", [] ) ) + self.tool_label_filters = listify( kwargs.get( "tool_label_filters", [] ) ) + self.tool_section_filters = listify( kwargs.get( "tool_section_filters", [] ) ) self.tool_configs = [ resolve_path( p, self.root ) for p in listify( tcf ) ] self.tool_data_table_config_path = resolve_path( kwargs.get( 'tool_data_table_config_path', 'tool_data_table_conf.xml' ), self.root ) self.shed_tool_data_table_config = resolve_path( kwargs.get( 'shed_tool_data_table_config', 'shed_tool_data_table_conf.xml' ), self.root ) diff -r 8d72c9adccf92f8a1971ec7d9b622de43cbd6f48 -r 99dad50eb44062d66d41f609afac00d23cbf4899 lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -47,6 +47,7 @@ from galaxy.tools.parameters.input_translation import ToolInputTranslator from galaxy.tools.parameters.output import ToolOutputActionGroup from galaxy.tools.parameters.validation import LateValidationError +from galaxy.tools.filters import FilterFactory from galaxy.tools.test import ToolTestBuilder from galaxy.util import listify, parse_xml, rst_to_html, string_as_bool, string_to_object, xml_text, xml_to_string from galaxy.util.bunch import Bunch @@ -119,6 +120,7 @@ # (e.g., shed_tool_conf.xml) files include the tool_path attribute within the <toolbox> tag. self.tool_root_dir = tool_root_dir self.app = app + self.filter_factory = FilterFactory( self ) self.init_dependency_manager() config_filenames = listify( config_filenames ) for config_filename in config_filenames: @@ -679,76 +681,19 @@ """ return self.app.model.context - def to_dict( self, trans, in_panel=True, trackster=False ): - - def filter_for_panel( item, filters ): - """ - Filters tool panel elements so that only those that are compatible - with provided filters are kept. - """ - def _apply_filter( filter_item, filter_list ): - for filter_method in filter_list: - if not filter_method( filter_item ): - return False - return True - if isinstance( item, Tool ): - if _apply_filter( item, filters[ 'tool' ] ): - return item - elif isinstance( item, ToolSectionLabel ): - if _apply_filter( item, filters[ 'label' ] ): - return item - elif isinstance( item, ToolSection ): - # Filter section item-by-item. Only show a label if there are - # non-filtered tools below it. - - if _apply_filter( item, filters[ 'section' ] ): - cur_label_key = None - tools_under_label = False - filtered_elems = item.elems.copy() - for key, section_item in item.elems.items(): - if isinstance( section_item, Tool ): - # Filter tool. - if _apply_filter( section_item, filters[ 'tool' ] ): - tools_under_label = True - else: - del filtered_elems[ key ] - elif isinstance( section_item, ToolSectionLabel ): - # If there is a label and it does not have tools, - # remove it. - if ( cur_label_key and not tools_under_label ) or not _apply_filter( section_item, filters[ 'label' ] ): - del filtered_elems[ cur_label_key ] - - # Reset attributes for new label. - cur_label_key = key - tools_under_label = False - - - # Handle last label. - if cur_label_key and not tools_under_label: - del filtered_elems[ cur_label_key ] - - # Only return section if there are elements. - if len( filtered_elems ) != 0: - copy = item.copy() - copy.elems = filtered_elems - return copy - - return None - + def to_dict( self, trans, in_panel=True, **kwds ): # # Dictify toolbox. # - + context = Bunch( toolbox=self, trans=trans, **kwds ) if in_panel: panel_elts = [ val for val in self.tool_panel.itervalues() ] - # Filter if necessary. - filters = dict( tool=[ lambda x: not x._is_hidden_for_user( trans.user ) ], section=[], label=[] ) #hidden tools filter - if trackster: - filters[ 'tool' ].append( lambda x: x.trackster_conf ) # If tool has a trackster config, it can be used in Trackster. + filters = self.filter_factory.build_filters( trans, **kwds ) + filtered_panel_elts = [] for index, elt in enumerate( panel_elts ): - elt = filter_for_panel( elt, filters ) + elt = _filter_for_panel( elt, filters, context ) if elt: filtered_panel_elts.append( elt ) panel_elts = filtered_panel_elts @@ -759,13 +704,68 @@ rval.append( elt.to_dict( trans, for_link=True ) ) else: tools = [] - for id, tool in self.app.toolbox.tools_by_id.items(): + for id, tool in self.toolbox.tools_by_id.items(): tools.append( tool.to_dict( trans ) ) rval = tools return rval +def _filter_for_panel( item, filters, context ): + """ + Filters tool panel elements so that only those that are compatible + with provided filters are kept. + """ + def _apply_filter( filter_item, filter_list ): + for filter_method in filter_list: + if not filter_method( context, filter_item ): + return False + return True + if isinstance( item, Tool ): + if _apply_filter( item, filters[ 'tool' ] ): + return item + elif isinstance( item, ToolSectionLabel ): + if _apply_filter( item, filters[ 'label' ] ): + return item + elif isinstance( item, ToolSection ): + # Filter section item-by-item. Only show a label if there are + # non-filtered tools below it. + + if _apply_filter( item, filters[ 'section' ] ): + cur_label_key = None + tools_under_label = False + filtered_elems = item.elems.copy() + for key, section_item in item.elems.items(): + if isinstance( section_item, Tool ): + # Filter tool. + if _apply_filter( section_item, filters[ 'tool' ] ): + tools_under_label = True + else: + del filtered_elems[ key ] + elif isinstance( section_item, ToolSectionLabel ): + # If there is a label and it does not have tools, + # remove it. + if ( cur_label_key and not tools_under_label ) or not _apply_filter( section_item, filters[ 'label' ] ): + del filtered_elems[ cur_label_key ] + + # Reset attributes for new label. + cur_label_key = key + tools_under_label = False + + # Handle last label. + if cur_label_key and not tools_under_label: + del filtered_elems[ cur_label_key ] + + # Only return section if there are elements. + if len( filtered_elems ) != 0: + copy = item.copy() + copy.elems = filtered_elems + return copy + + return None + + + class ToolSection( object ): """ A group of tools with similar type/purpose that will be displayed as a @@ -2897,11 +2897,6 @@ self.sa_session.flush() return primary_datasets - def _is_hidden_for_user( self, user ): - if self.hidden or ( not user and self.require_login ): - return True - return False - def to_dict( self, trans, for_link=False, for_display=False ): """ Returns dict of tool. """ diff -r 8d72c9adccf92f8a1971ec7d9b622de43cbd6f48 -r 99dad50eb44062d66d41f609afac00d23cbf4899 lib/galaxy/tools/filters/__init__.py --- /dev/null +++ b/lib/galaxy/tools/filters/__init__.py @@ -0,0 +1,67 @@ + + +class FilterFactory( object ): + """ + An instance of this class is responsible for filtering the list + of tools presented to a given user in a given context. + """ + + def __init__( self, toolbox ): + self.toolbox = toolbox + + # Prepopulate dict containing filters that are always checked, + # other filters that get checked depending on context (e.g. coming from + # trackster or no user found are added in build filters). + self.default_filters = dict( tool=[ _not_hidden ], section=[], label=[] ) + # Add dynamic filters to these default filters. + config = toolbox.app.config + self.__init_filters( "tool", config.tool_filters ) + self.__init_filters( "section", config.tool_section_filters ) + self.__init_filters( "label", config.tool_label_filters ) + + def build_filters( self, trans, **kwds ): + """ + Build list of filters to check tools against given current context. + """ + filters = self.default_filters.copy() + + if not trans.user: + filters[ "tool" ].append( _requires_login ) + + if kwds.get( "trackster", False ): + filters[ "tool" ].append( _has_trackster_conf ) + + return filters + + def __init_filters( self, key, filters ): + for filter in filters: + filter_function = self.__build_filter_function( filter ) + self.default_filters[ key ].append( filter_function ) + + def __build_filter_function( self, filter_name ): + """Obtain python function (importing a submodule if needed) + corresponding to filter_name. + """ + if ":" in filter_name: + # Should be a submodule of filters (e.g. examples:restrict_development_tools) + (module_name, function_name) = filter_name.rsplit(":", 1) + module = __import__( module_name, globals() ) + function = getattr( module, function_name ) + else: + # No module found, just load a function from this file or + # one that has be explicitly imported. + function = getattr( globals(), filter_name ) + return function + + +## Stock Filter Functions +def _not_hidden( context, tool ): + return not tool.hidden + + +def _requires_login( context, tool ): + return not tool.require_login + + +def _has_trackster_conf( context, tool ): + return tool.trackster_conf diff -r 8d72c9adccf92f8a1971ec7d9b622de43cbd6f48 -r 99dad50eb44062d66d41f609afac00d23cbf4899 lib/galaxy/tools/filters/examples.py.sample --- /dev/null +++ b/lib/galaxy/tools/filters/examples.py.sample @@ -0,0 +1,87 @@ +import logging +log = logging.getLogger( __name__ ) + + +def restrict_upload_to_admins( context, tool ): + """ + This tool filter will hide the upload tool from all users except admin + users. This can be enabled by renaming this file to examples.py and adding + the following to the ``app:main`` section of ``universe_wsgi.ini``: + + tool_filters = examples:restrict_upload_to_admins + """ + if tool.name == "Upload File": + return context.trans.user_is_admin() + return True + + +def disable_gatk( context, tool ): + """ + This tool filter will disable all gatk tools when enabled. This can be + enabled by renaming this file to examples.py and adding the following to the + ``app:main`` section of ``universe_wsgi.ini``: + + tool_filters = examples:disable_gatk + """ + return not any( [ requirement.name == "gatk" for requirement in tool.requirements ] ) + + +def explicit_user_mapping( context, section ): + """ + This tool section filter uses an explicit mapping to describe what users can view + which tool sections. Anonymous users will only be able to view the "Get Data" + tool section (with id getext). This can be enabled by renaming this file to + examples.py and adding the following to the ``app:main`` section of + ``universe_wsgi.ini``: + + tool_section_filters = examples:explicit_user_mapping + """ + users_sections = { + None: [ "getext" ], + "bob@example.com": [ "getext", "textutil", "filter" ], + "mary@example.com": [ "getext", "textutil", "filter", "ngs" ], + } + user = context.trans.user + email = user and user.email + valid_sections = users_sections.get( email, [] ) + return section.id in valid_sections + + +DEVELOPERS = [ "mary@example.com" ] + + +def restrict_development_tools( context, tool ): + """ + This tool filter will disable all tools with the string alpha appearing in + the version for all users except those explicitly appearing in the DEVELOPERS list + defined above. This can be enabled by renaming this file to examples.py and + adding the following to the ``app:main`` section of ``universe_wsgi.ini``: + + tool_filters = examples:restrict_development_tools + """ + version = tool.version + user = context.trans.user + email = user and user.email + return "alpha" not in version or email in DEVELOPERS + + +def per_host_tool_sections( context, section ): + """ + This tool section filter results in different sections being display based on + the URL the user is making the request to. This could allow a single Galaxy instance + to seem like several different instances hosting different tools based on the URL used + to access the Galxy. This can be enabled by renaming this file to examples.py and adding + the following to the ``app:main`` section of ``universe_wsgi.ini``: + + tool_section_filters = examples:per_host_tool_sections + """ + host = context.trans.request.host + # Core tools used by all virtual hosts. + valid_sections = [ "getext", "textutil", "filter" ] + if "ngs.galaxy.example.com" in host: + valid_sections += [ "ngs" ] + elif "microarray.galaxy.example.com" in host: + valid_sections += [ "microarray" ] + elif "proteomics.galaxy.example.com" in host: + valid_sections += [ "proteomics" ] + return section.id in valid_sections https://bitbucket.org/galaxy/galaxy-central/commits/94a81104e8f4/ Changeset: 94a81104e8f4 User: jmchilton Date: 2013-04-20 18:10:23 Summary: Dynamic Toolbox Filtering: Allow whitespace around commas between filters in configuration file. Affected #: 1 file diff -r 99dad50eb44062d66d41f609afac00d23cbf4899 -r 94a81104e8f442d1c40e5b6b681ffdd8c684d963 lib/galaxy/tools/filters/__init__.py --- a/lib/galaxy/tools/filters/__init__.py +++ b/lib/galaxy/tools/filters/__init__.py @@ -45,12 +45,12 @@ if ":" in filter_name: # Should be a submodule of filters (e.g. examples:restrict_development_tools) (module_name, function_name) = filter_name.rsplit(":", 1) - module = __import__( module_name, globals() ) - function = getattr( module, function_name ) + module = __import__( module_name.strip(), globals() ) + function = getattr( module, function_name.strip() ) else: # No module found, just load a function from this file or # one that has be explicitly imported. - function = getattr( globals(), filter_name ) + function = getattr( globals(), filter_name.strip() ) return function https://bitbucket.org/galaxy/galaxy-central/commits/b509d742abb8/ Changeset: b509d742abb8 User: dannon Date: 2013-06-13 21:23:52 Summary: Merged in jmchilton/galaxy-central-multi-input-tool-fixes-2 (pull request #160) Implement dynamic toolbox filters. Affected #: 4 files diff -r 75aa82cbcaedbaa471f9f44ee19b0e201f8bb55b -r b509d742abb83380ed03e9c01780ab9a8ed184bc lib/galaxy/config.py --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -64,6 +64,9 @@ tcf = kwargs[ 'tool_config_files' ] else: tcf = 'tool_conf.xml' + self.tool_filters = listify( kwargs.get( "tool_filters", [] ) ) + self.tool_label_filters = listify( kwargs.get( "tool_label_filters", [] ) ) + self.tool_section_filters = listify( kwargs.get( "tool_section_filters", [] ) ) self.tool_configs = [ resolve_path( p, self.root ) for p in listify( tcf ) ] self.shed_tool_data_path = kwargs.get( "shed_tool_data_path", None ) if self.shed_tool_data_path: diff -r 75aa82cbcaedbaa471f9f44ee19b0e201f8bb55b -r b509d742abb83380ed03e9c01780ab9a8ed184bc lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -48,6 +48,7 @@ from galaxy.tools.parameters.input_translation import ToolInputTranslator from galaxy.tools.parameters.output import ToolOutputActionGroup from galaxy.tools.parameters.validation import LateValidationError +from galaxy.tools.filters import FilterFactory from galaxy.tools.test import ToolTestBuilder from galaxy.util import listify, parse_xml, rst_to_html, string_as_bool, string_to_object, xml_text, xml_to_string from galaxy.util.bunch import Bunch @@ -120,6 +121,7 @@ # (e.g., shed_tool_conf.xml) files include the tool_path attribute within the <toolbox> tag. self.tool_root_dir = tool_root_dir self.app = app + self.filter_factory = FilterFactory( self ) self.init_dependency_manager() config_filenames = listify( config_filenames ) for config_filename in config_filenames: @@ -680,76 +682,19 @@ """ return self.app.model.context - def to_dict( self, trans, in_panel=True, trackster=False ): - - def filter_for_panel( item, filters ): - """ - Filters tool panel elements so that only those that are compatible - with provided filters are kept. - """ - def _apply_filter( filter_item, filter_list ): - for filter_method in filter_list: - if not filter_method( filter_item ): - return False - return True - if isinstance( item, Tool ): - if _apply_filter( item, filters[ 'tool' ] ): - return item - elif isinstance( item, ToolSectionLabel ): - if _apply_filter( item, filters[ 'label' ] ): - return item - elif isinstance( item, ToolSection ): - # Filter section item-by-item. Only show a label if there are - # non-filtered tools below it. - - if _apply_filter( item, filters[ 'section' ] ): - cur_label_key = None - tools_under_label = False - filtered_elems = item.elems.copy() - for key, section_item in item.elems.items(): - if isinstance( section_item, Tool ): - # Filter tool. - if _apply_filter( section_item, filters[ 'tool' ] ): - tools_under_label = True - else: - del filtered_elems[ key ] - elif isinstance( section_item, ToolSectionLabel ): - # If there is a label and it does not have tools, - # remove it. - if ( cur_label_key and not tools_under_label ) or not _apply_filter( section_item, filters[ 'label' ] ): - del filtered_elems[ cur_label_key ] - - # Reset attributes for new label. - cur_label_key = key - tools_under_label = False - - - # Handle last label. - if cur_label_key and not tools_under_label: - del filtered_elems[ cur_label_key ] - - # Only return section if there are elements. - if len( filtered_elems ) != 0: - copy = item.copy() - copy.elems = filtered_elems - return copy - - return None - + def to_dict( self, trans, in_panel=True, **kwds ): # # Dictify toolbox. # - + context = Bunch( toolbox=self, trans=trans, **kwds ) if in_panel: panel_elts = [ val for val in self.tool_panel.itervalues() ] - # Filter if necessary. - filters = dict( tool=[ lambda x: not x._is_hidden_for_user( trans.user ) ], section=[], label=[] ) #hidden tools filter - if trackster: - filters[ 'tool' ].append( lambda x: x.trackster_conf ) # If tool has a trackster config, it can be used in Trackster. + filters = self.filter_factory.build_filters( trans, **kwds ) + filtered_panel_elts = [] for index, elt in enumerate( panel_elts ): - elt = filter_for_panel( elt, filters ) + elt = _filter_for_panel( elt, filters, context ) if elt: filtered_panel_elts.append( elt ) panel_elts = filtered_panel_elts @@ -760,13 +705,68 @@ rval.append( elt.to_dict( trans, for_link=True ) ) else: tools = [] - for id, tool in self.app.toolbox.tools_by_id.items(): + for id, tool in self.toolbox.tools_by_id.items(): tools.append( tool.to_dict( trans ) ) rval = tools return rval +def _filter_for_panel( item, filters, context ): + """ + Filters tool panel elements so that only those that are compatible + with provided filters are kept. + """ + def _apply_filter( filter_item, filter_list ): + for filter_method in filter_list: + if not filter_method( context, filter_item ): + return False + return True + if isinstance( item, Tool ): + if _apply_filter( item, filters[ 'tool' ] ): + return item + elif isinstance( item, ToolSectionLabel ): + if _apply_filter( item, filters[ 'label' ] ): + return item + elif isinstance( item, ToolSection ): + # Filter section item-by-item. Only show a label if there are + # non-filtered tools below it. + + if _apply_filter( item, filters[ 'section' ] ): + cur_label_key = None + tools_under_label = False + filtered_elems = item.elems.copy() + for key, section_item in item.elems.items(): + if isinstance( section_item, Tool ): + # Filter tool. + if _apply_filter( section_item, filters[ 'tool' ] ): + tools_under_label = True + else: + del filtered_elems[ key ] + elif isinstance( section_item, ToolSectionLabel ): + # If there is a label and it does not have tools, + # remove it. + if ( cur_label_key and not tools_under_label ) or not _apply_filter( section_item, filters[ 'label' ] ): + del filtered_elems[ cur_label_key ] + + # Reset attributes for new label. + cur_label_key = key + tools_under_label = False + + # Handle last label. + if cur_label_key and not tools_under_label: + del filtered_elems[ cur_label_key ] + + # Only return section if there are elements. + if len( filtered_elems ) != 0: + copy = item.copy() + copy.elems = filtered_elems + return copy + + return None + + + class ToolSection( object ): """ A group of tools with similar type/purpose that will be displayed as a @@ -2914,11 +2914,6 @@ self.sa_session.flush() return primary_datasets - def _is_hidden_for_user( self, user ): - if self.hidden or ( not user and self.require_login ): - return True - return False - def to_dict( self, trans, for_link=False, for_display=False ): """ Returns dict of tool. """ diff -r 75aa82cbcaedbaa471f9f44ee19b0e201f8bb55b -r b509d742abb83380ed03e9c01780ab9a8ed184bc lib/galaxy/tools/filters/__init__.py --- /dev/null +++ b/lib/galaxy/tools/filters/__init__.py @@ -0,0 +1,67 @@ + + +class FilterFactory( object ): + """ + An instance of this class is responsible for filtering the list + of tools presented to a given user in a given context. + """ + + def __init__( self, toolbox ): + self.toolbox = toolbox + + # Prepopulate dict containing filters that are always checked, + # other filters that get checked depending on context (e.g. coming from + # trackster or no user found are added in build filters). + self.default_filters = dict( tool=[ _not_hidden ], section=[], label=[] ) + # Add dynamic filters to these default filters. + config = toolbox.app.config + self.__init_filters( "tool", config.tool_filters ) + self.__init_filters( "section", config.tool_section_filters ) + self.__init_filters( "label", config.tool_label_filters ) + + def build_filters( self, trans, **kwds ): + """ + Build list of filters to check tools against given current context. + """ + filters = self.default_filters.copy() + + if not trans.user: + filters[ "tool" ].append( _requires_login ) + + if kwds.get( "trackster", False ): + filters[ "tool" ].append( _has_trackster_conf ) + + return filters + + def __init_filters( self, key, filters ): + for filter in filters: + filter_function = self.__build_filter_function( filter ) + self.default_filters[ key ].append( filter_function ) + + def __build_filter_function( self, filter_name ): + """Obtain python function (importing a submodule if needed) + corresponding to filter_name. + """ + if ":" in filter_name: + # Should be a submodule of filters (e.g. examples:restrict_development_tools) + (module_name, function_name) = filter_name.rsplit(":", 1) + module = __import__( module_name.strip(), globals() ) + function = getattr( module, function_name.strip() ) + else: + # No module found, just load a function from this file or + # one that has be explicitly imported. + function = getattr( globals(), filter_name.strip() ) + return function + + +## Stock Filter Functions +def _not_hidden( context, tool ): + return not tool.hidden + + +def _requires_login( context, tool ): + return not tool.require_login + + +def _has_trackster_conf( context, tool ): + return tool.trackster_conf diff -r 75aa82cbcaedbaa471f9f44ee19b0e201f8bb55b -r b509d742abb83380ed03e9c01780ab9a8ed184bc lib/galaxy/tools/filters/examples.py.sample --- /dev/null +++ b/lib/galaxy/tools/filters/examples.py.sample @@ -0,0 +1,87 @@ +import logging +log = logging.getLogger( __name__ ) + + +def restrict_upload_to_admins( context, tool ): + """ + This tool filter will hide the upload tool from all users except admin + users. This can be enabled by renaming this file to examples.py and adding + the following to the ``app:main`` section of ``universe_wsgi.ini``: + + tool_filters = examples:restrict_upload_to_admins + """ + if tool.name == "Upload File": + return context.trans.user_is_admin() + return True + + +def disable_gatk( context, tool ): + """ + This tool filter will disable all gatk tools when enabled. This can be + enabled by renaming this file to examples.py and adding the following to the + ``app:main`` section of ``universe_wsgi.ini``: + + tool_filters = examples:disable_gatk + """ + return not any( [ requirement.name == "gatk" for requirement in tool.requirements ] ) + + +def explicit_user_mapping( context, section ): + """ + This tool section filter uses an explicit mapping to describe what users can view + which tool sections. Anonymous users will only be able to view the "Get Data" + tool section (with id getext). This can be enabled by renaming this file to + examples.py and adding the following to the ``app:main`` section of + ``universe_wsgi.ini``: + + tool_section_filters = examples:explicit_user_mapping + """ + users_sections = { + None: [ "getext" ], + "bob@example.com": [ "getext", "textutil", "filter" ], + "mary@example.com": [ "getext", "textutil", "filter", "ngs" ], + } + user = context.trans.user + email = user and user.email + valid_sections = users_sections.get( email, [] ) + return section.id in valid_sections + + +DEVELOPERS = [ "mary@example.com" ] + + +def restrict_development_tools( context, tool ): + """ + This tool filter will disable all tools with the string alpha appearing in + the version for all users except those explicitly appearing in the DEVELOPERS list + defined above. This can be enabled by renaming this file to examples.py and + adding the following to the ``app:main`` section of ``universe_wsgi.ini``: + + tool_filters = examples:restrict_development_tools + """ + version = tool.version + user = context.trans.user + email = user and user.email + return "alpha" not in version or email in DEVELOPERS + + +def per_host_tool_sections( context, section ): + """ + This tool section filter results in different sections being display based on + the URL the user is making the request to. This could allow a single Galaxy instance + to seem like several different instances hosting different tools based on the URL used + to access the Galxy. This can be enabled by renaming this file to examples.py and adding + the following to the ``app:main`` section of ``universe_wsgi.ini``: + + tool_section_filters = examples:per_host_tool_sections + """ + host = context.trans.request.host + # Core tools used by all virtual hosts. + valid_sections = [ "getext", "textutil", "filter" ] + if "ngs.galaxy.example.com" in host: + valid_sections += [ "ngs" ] + elif "microarray.galaxy.example.com" in host: + valid_sections += [ "microarray" ] + elif "proteomics.galaxy.example.com" in host: + valid_sections += [ "proteomics" ] + return section.id in valid_sections 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.