galaxy-dist commit fc1f67023d86: Fixes for building target library and folder SelectFields for transferring sample datasets. All folders are now present in the target folder SelectField. Move security-related methods from the model's User class to the security agent where they belong.
# HG changeset patch -- Bitbucket.org # Project galaxy-dist # URL http://bitbucket.org/galaxy/galaxy-dist/overview # User Greg Von Kuster <greg@bx.psu.edu> # Date 1289574787 18000 # Node ID fc1f67023d86a69ea7229501b093d61748630f4c # Parent dc4af741ffc455c4737aff67c7d7de48c8628392 Fixes for building target library and folder SelectFields for transferring sample datasets. All folders are now present in the target folder SelectField. Move security-related methods from the model's User class to the security agent where they belong. --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -52,40 +52,6 @@ class User( object ): if role not in roles: roles.append( role ) return roles - def accessible_libraries( self, trans, actions ): - # TODO: eliminate this method - instead use - # trans.app.security_agent.get_accessible_libraries(). - # Get all permitted libraries for this user - all_libraries = trans.sa_session.query( trans.app.model.Library ) \ - .filter( trans.app.model.Library.table.c.deleted == False ) \ - .order_by( trans.app.model.Library.name ) - roles = self.all_roles() - actions_to_check = actions - # The libraries dictionary looks like: { library : '1,2' }, library : '3' } - # Its keys are the libraries that should be displayed for the current user and whose values are a - # string of comma-separated folder ids, of the associated folders the should NOT be displayed. - # The folders that should not be displayed may not be a complete list, but it is ultimately passed - # to the calling method to keep from re-checking the same folders when the library / folder - # select lists are rendered. - libraries = {} - for library in all_libraries: - can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( self, roles, library, actions_to_check ) - if can_show: - libraries[ library ] = hidden_folder_ids - return libraries - def accessible_request_types( self, trans ): - active_request_types = trans.sa_session.query( trans.app.model.RequestType ) \ - .filter( trans.app.model.RequestType.table.c.deleted == False ) \ - .order_by( trans.app.model.RequestType.name ) - # Filter active_request_types to those that can be accessed by this user - role_ids = [ r.id for r in self.all_roles() ] - accessible_request_types = set() - for request_type in active_request_types: - for permission in request_type.actions: - if permission.role.id in role_ids: - accessible_request_types.add( request_type ) - accessible_request_types = [ request_type for request_type in accessible_request_types ] - return accessible_request_types class Job( object ): """ --- a/lib/galaxy/web/controllers/requests.py +++ b/lib/galaxy/web/controllers/requests.py @@ -77,7 +77,8 @@ class Requests( BaseController ): kwd[ 'message' ] = message # Allow the user to create a new request only if they have permission to access a # (sequencer configuration) request type. - if len( trans.user.accessible_request_types( trans ) ): + accessible_request_types = trans.app.security_agent.get_accessible_request_types( trans, trans.user ) + if accessible_request_types: self.request_grid.global_actions = [ grids.GridAction( "Create new request", dict( controller='requests_common', action='create_request', cntrller='requests' ) ) ] --- a/lib/galaxy/web/controllers/requests_common.py +++ b/lib/galaxy/web/controllers/requests_common.py @@ -414,7 +414,7 @@ class RequestsCommon( BaseController, Us cntrller=cntrller, id=request_id, editing_samples=editing_samples ) ) - libraries = self.__get_accessible_libraries( trans, request.user ) + libraries = trans.app.security_agent.get_accessible_libraries( trans, request.user ) # Build a list of sample widgets (based on the attributes of each sample) for display. displayable_sample_widgets = self.__get_sample_widgets( trans, request, request.samples, **kwd ) encoded_selected_sample_ids = self.__get_encoded_selected_sample_ids( trans, request, **kwd ) @@ -815,7 +815,7 @@ class RequestsCommon( BaseController, Us else: sample_index = len( displayable_sample_widgets ) if params.get( 'add_sample_button', False ): - libraries = self.__get_accessible_libraries( trans, request.user ) + libraries = trans.app.security_agent.get_accessible_libraries( trans, request.user ) num_samples_to_add = int( params.get( 'num_sample_to_copy', 1 ) ) # See if the user has selected a sample to copy. copy_sample_index = int( params.get( 'copy_sample_index', -1 ) ) @@ -1214,20 +1214,14 @@ class RequestsCommon( BaseController, Us else: folder = None return library, folder + def __get_active_folders( self, library ): + """Return all of the active folders for the received library""" + root_folder = library.root_folder + active_folders = [ root_folder ] + for folder in root_folder.active_folders: + active_folders.append( folder ) + return active_folders # ===== Methods for handling form definition widgets ===== - def __get_accessible_libraries( self, trans, user ): - # Return a dictionary whose keys are libraries that user can - # access and whose values are empty string ''. This is because - # methods expect the dictionary instead of a simple list because - # this method replaces the deprecated model.User.accessible_libraries() - # method. TODO: fix methods that call this method to expect the list - # returne dby trans.app.securoty_agent.get_accessible_libraries() and - # then eliminate this method. - accessible_libraries = trans.app.security_agent.get_accessible_libraries( trans, user ) - accessible_libraries_dict = odict() - for library in accessible_libraries: - accessible_libraries_dict[ library ] = '' - return accessible_libraries_dict def __get_request_widgets( self, trans, id ): """Get the widgets for the request""" request = trans.sa_session.query( trans.model.Request ).get( id ) @@ -1275,7 +1269,7 @@ class RequestsCommon( BaseController, Us # Build the list of widgets which will be used to render each sample row on the request page if not request: return sample_widgets - libraries = self.__get_accessible_libraries( trans, request.user ) + libraries = trans.app.security_agent.get_accessible_libraries( trans, request.user ) # Build the list if sample widgets, populating the values from kwd. for index, sample in enumerate( samples ): id_index = index + 1 @@ -1361,7 +1355,7 @@ class RequestsCommon( BaseController, Us copy_sample_index_select_field.add_option( sample_dict[ 'name' ], index ) return copy_sample_index_select_field def __build_request_type_id_select_field( self, trans, selected_value='none' ): - accessible_request_types = trans.user.accessible_request_types( trans ) + accessible_request_types = trans.app.security_agent.get_accessible_request_types( trans, trans.user ) return build_select_field( trans, accessible_request_types, 'name', 'request_type_id', selected_value=selected_value, refresh_on_change=True ) def __build_user_id_select_field( self, trans, selected_value='none' ): active_users = trans.sa_session.query( trans.model.User ) \ @@ -1388,11 +1382,9 @@ class RequestsCommon( BaseController, Us def __build_library_and_folder_select_fields( self, trans, user, sample_index, libraries, sample=None, library_id=None, folder_id=None, **kwd ): # Create the library_id SelectField for a specific sample. The received libraries param is a list of all the libraries # accessible to the current user, and we add them as options to the library_select_field. If the user has selected an - # existing library then display all the accessible folders of the selected library in the folder_select_field. - # - # The libraries dictionary looks like: { library : '1,2' }, library : '3' }. Its keys are the libraries that - # should be displayed for the current user and its values are strings of comma-separated folder ids that should - # NOT be displayed. + # existing library then display all the folders of the selected library in the folder_select_field. Library folders do + # not have ACCESS permissions associated with them (only LIBRARY_ADD, LIBRARY_MODIFY, LIBRARY_MANAGE), so all folders will + # be present in the folder_select_field for each library selected. params = util.Params( kwd ) library_select_field_name= "sample_%i_library_id" % sample_index folder_select_field_name = "sample_%i_folder_id" % sample_index @@ -1401,15 +1393,11 @@ class RequestsCommon( BaseController, Us if not folder_id: folder_id = params.get( folder_select_field_name, None ) selected_library = None - selected_hidden_folder_ids = [] - showable_folders = [] if library_id not in [ None, 'none' ]: - # If we have a selected library, get the list of it's folders that are not accessible to the current user - for library, hidden_folder_ids in libraries.items(): + for library in libraries: encoded_id = trans.security.encode_id( library.id ) if encoded_id == str( library_id ): selected_library = library - selected_hidden_folder_ids = hidden_folder_ids.split( ',' ) break elif sample and sample.library and library_id == 'none': # The user previously selected a library but is now resetting the selection to 'none' @@ -1417,21 +1405,17 @@ class RequestsCommon( BaseController, Us elif sample and sample.library: library_id = trans.security.encode_id( sample.library.id ) selected_library = sample.library - # sample_%i_library_id SelectField with refresh on change enabled + # Build the sample_%i_library_id SelectField with refresh on change enabled library_select_field = build_select_field( trans, - libraries.keys(), + libraries, 'name', library_select_field_name, initial_value='none', selected_value=str( library_id ).lower(), refresh_on_change=True ) - # Get all accessible folders for the selected library, if one is indeed selected + # Get all folders for the selected library, if one is indeed selected if selected_library: - showable_folders = trans.app.security_agent.get_showable_folders( user, - user.all_roles(), - selected_library, - [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ], - selected_hidden_folder_ids ) + folders = self.__get_active_folders( selected_library ) if folder_id: selected_folder_id = folder_id elif sample and sample.folder: @@ -1440,11 +1424,12 @@ class RequestsCommon( BaseController, Us selected_folder_id = trans.security.encode_id( selected_library.root_folder.id ) else: selected_folder_id = 'none' + folders = [] # TODO: Change the name of the library root folder to "Library root" to clarify to the # user that it is the root folder. We probably should just change this in the Library code, # and update the data in the db. folder_select_field = build_select_field( trans, - showable_folders, + folders, 'name', folder_select_field_name, initial_value='none', --- a/templates/webapps/galaxy/base_panels.mako +++ b/templates/webapps/galaxy/base_panels.mako @@ -84,7 +84,7 @@ [ 'Find Samples', h.url_for( controller='/requests', action='find_samples_index' ) ], [ 'Help', app.config.get( "lims_doc_url", "http://main.g2.bx.psu.edu/u/rkchak/p/sts" ), "galaxy_main" ] ] - tab( "lab", "Lab", None, menu_options=menu_options, visible=( trans.user and ( trans.user.requests or trans.user.accessible_request_types( trans ) ) ) ) + tab( "lab", "Lab", None, menu_options=menu_options, visible=( trans.user and ( trans.user.requests or trans.app.security_agent.get_accessible_request_types( trans, trans.user ) ) ) ) %> ## Visualization menu. --- a/lib/galaxy/security/__init__.py +++ b/lib/galaxy/security/__init__.py @@ -60,6 +60,8 @@ class RBACAgent: raise "Unimplemented Method" def get_private_user_role( self, user ): raise "Unimplemented Method" + def get_accessible_request_types( self, trans, user ): + raise "Unimplemented Method" def user_set_default_permissions( self, user, permissions={}, history=False, dataset=False ): raise "Unimplemented Method" def history_set_default_permissions( self, history, permissions=None, dataset=False, bypass_manage_permission=False ): @@ -76,6 +78,8 @@ class RBACAgent: raise "Unimplemented Method" def get_accessible_libraries( self, trans, user ): raise "Unimplemented Method" + def get_permitted_libraries( self, trans, user, actions ): + raise "Unimplemented Method" def folder_is_public( self, library ): raise "Unimplemented Method" def make_folder_public( self, folder, count=0 ): @@ -247,7 +251,7 @@ class GalaxyRBACAgent( RBACAgent ): def can_access_library( self, roles, library ): return self.library_is_public( library ) or self.allow_action( roles, self.permitted_actions.LIBRARY_ACCESS, library ) def get_accessible_libraries( self, trans, user ): - """Return all data libraries that user can access""" + """Return all data libraries that the received user can access""" accessible_libraries = [] current_user_role_ids = [ role.id for role in user.all_roles() ] library_access_action = self.permitted_actions.LIBRARY_ACCESS.action @@ -499,6 +503,20 @@ class GalaxyRBACAgent( RBACAgent ): else: permissions[ action ] = [ item_permission.role ] return permissions + def get_accessible_request_types( self, trans, user ): + """Return all ReqquestTypes that the received user has permission to access.""" + active_request_types = trans.sa_session.query( trans.app.model.RequestType ) \ + .filter( trans.app.model.RequestType.table.c.deleted == False ) \ + .order_by( trans.app.model.RequestType.name ) + # Filter active_request_types to those that can be accessed by the received user + role_ids = [ r.id for r in user.all_roles() ] + accessible_request_types = set() + for request_type in active_request_types: + for permission in request_type.actions: + if permission.role.id in role_ids: + accessible_request_types.add( request_type ) + accessible_request_types = [ request_type for request_type in accessible_request_types ] + return accessible_request_types def copy_dataset_permissions( self, src, dst ): if not isinstance( src, self.model.Dataset ): src = src.dataset @@ -731,6 +749,34 @@ class GalaxyRBACAgent( RBACAgent ): else: raise 'Invalid class (%s) specified for target_library_item (%s)' % \ ( target_library_item.__class__, target_library_item.__class__.__name__ ) + def get_permitted_libraries( self, trans, user, actions ): + """ + This method is historical (it is not currently used), but may be useful again at some + point. It returns a dictionary whose keys are library objects and whose values are a + comma-separated string of folder ids. This method works with the show_library_item() + method below, and it returns libraries for which the received user has permission to + perform the received actions. Here is an example call to this method to return all + libraries for which the received user has LIBRARY_ADD permission: + libraries = trans.app.security_agent.get_permitted_libraries( trans, user, + [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] ) + """ + all_libraries = trans.sa_session.query( trans.app.model.Library ) \ + .filter( trans.app.model.Library.table.c.deleted == False ) \ + .order_by( trans.app.model.Library.name ) + roles = user.all_roles() + actions_to_check = actions + # The libraries dictionary looks like: { library : '1,2' }, library : '3' } + # Its keys are the libraries that should be displayed for the current user and whose values are a + # string of comma-separated folder ids, of the associated folders the should NOT be displayed. + # The folders that should not be displayed may not be a complete list, but it is ultimately passed + # to the calling method to keep from re-checking the same folders when the library / folder + # select lists are rendered. + libraries = {} + for library in all_libraries: + can_show, hidden_folder_ids = self.show_library_item( self, roles, library, actions_to_check ) + if can_show: + libraries[ library ] = hidden_folder_ids + return libraries def show_library_item( self, user, roles, library_item, actions_to_check, hidden_folder_ids='' ): """ This method must be sent an instance of Library() or LibraryFolder(). Recursive execution produces a
participants (1)
-
commits-noreply@bitbucket.org