From 00c3f84f40dc997e7e6f27b4e80e8c14ca39ea48 Mon Sep 17 00:00:00 2001 From: Greg Von Kuster Date: Mon, 9 Nov 2009 23:00:55 -0500 Subject: [PATCH] Incorporate latest grid features into managing users, groups and roles from the admin view. --- lib/galaxy/web/controllers/admin.py | 436 +++++++++++++----- .../dataset_security/deleted_groups.mako | 101 ---- .../admin/dataset_security/deleted_roles.mako | 103 ----- .../admin/dataset_security/group/grid.mako | 1 + .../dataset_security/{ => group}/group.mako | 0 .../{ => group}/group_create.mako | 0 .../{ => group}/group_rename.mako | 2 +- templates/admin/dataset_security/groups.mako | 107 ----- .../admin/dataset_security/role/grid.mako | 1 + .../dataset_security/{ => role}/role.mako | 0 .../{ => role}/role_create.mako | 0 .../{ => role}/role_rename.mako | 2 +- templates/admin/dataset_security/roles.mako | 109 ----- templates/admin/user/grid.mako | 225 +-------- templates/grid_base.mako | 11 +- test/base/twilltestcase.py | 32 +- test/functional/test_history_functions.py | 4 +- .../functional/test_security_and_libraries.py | 102 ++-- tool_conf.xml.main | 52 ++- 19 files changed, 460 insertions(+), 828 deletions(-) delete mode 100644 templates/admin/dataset_security/deleted_groups.mako delete mode 100644 templates/admin/dataset_security/deleted_roles.mako create mode 100644 templates/admin/dataset_security/group/grid.mako rename templates/admin/dataset_security/{ => group}/group.mako (100%) rename templates/admin/dataset_security/{ => group}/group_create.mako (100%) rename templates/admin/dataset_security/{ => group}/group_rename.mako (92%) delete mode 100644 templates/admin/dataset_security/groups.mako create mode 100644 templates/admin/dataset_security/role/grid.mako rename templates/admin/dataset_security/{ => role}/role.mako (100%) rename templates/admin/dataset_security/{ => role}/role_create.mako (100%) rename templates/admin/dataset_security/{ => role}/role_rename.mako (94%) delete mode 100644 templates/admin/dataset_security/roles.mako diff --git a/lib/galaxy/web/controllers/admin.py b/lib/galaxy/web/controllers/admin.py index 866aff42ecc..21851e19c80 100644 --- a/lib/galaxy/web/controllers/admin.py +++ b/lib/galaxy/web/controllers/admin.py @@ -2,20 +2,31 @@ import string, sys from datetime import datetime, timedelta from galaxy import util, datatypes from galaxy.web.base.controller import * +from galaxy.util.odict import odict from galaxy.model.orm import * from galaxy.web.framework.helpers import time_ago, iff, grids import logging log = logging.getLogger( __name__ ) +# States for passing messages +SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error" + class UserListGrid( grids.Grid ): - class EmailColumn( grids.GridColumn ): + class EmailColumn( grids.TextColumn ): def get_value( self, trans, grid, user ): return user.email - class UserNameColumn( grids.GridColumn ): + class UserNameColumn( grids.TextColumn ): def get_value( self, trans, grid, user ): if user.username: return user.username return 'not set' + class StatusColumn( grids.GridColumn ): + def get_value( self, trans, grid, user ): + if user.purged: + return "purged" + elif user.deleted: + return "deleted" + return "" class GroupsColumn( grids.GridColumn ): def get_value( self, trans, grid, user ): if user.groups: @@ -36,56 +47,242 @@ class UserListGrid( grids.Grid ): if user.galaxy_sessions: return self.format( user.galaxy_sessions[ 0 ].update_time ) return 'never' + class DeletedColumn( grids.GridColumn ): + def get_accepted_filters( self ): + """ Returns a list of accepted filters for this column. """ + accepted_filter_labels_and_vals = { "active" : "False", "deleted" : "True", "all": "All" } + accepted_filters = [] + for label, val in accepted_filter_labels_and_vals.items(): + args = { self.key: val } + accepted_filters.append( grids.GridColumnFilter( label, args) ) + return accepted_filters + # Grid definition title = "Users" model_class = model.User template='/admin/user/grid.mako' + default_sort_key = "email" columns = [ - EmailColumn( "Email", link=( lambda item: dict( operation="information", id=item.id ) ), attach_popup=True ), - UserNameColumn( "User Name", attach_popup=False ), + EmailColumn( "Email", + key="email", + model_class=model.User, + link=( lambda item: dict( operation="information", id=item.id ) ), + attach_popup=True, + filterable="advanced" ), + UserNameColumn( "User Name", + key="username", + model_class=model.User, + attach_popup=False, + filterable="advanced" ), GroupsColumn( "Groups", attach_popup=False ), RolesColumn( "Roles", attach_popup=False ), ExternalColumn( "External", attach_popup=False ), LastLoginColumn( "Last Login", format=time_ago ), - # Valid for filtering but invisible - grids.GridColumn( "Deleted", key="deleted", visible=False ) + StatusColumn( "Status", attach_popup=False ), + # Columns that are valid for filtering but are not visible. + DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" ) + ] + columns.append( grids.MulticolFilterColumn( "Search", + cols_to_filter=[ columns[0], columns[1] ], + key="free-text-search", + visible=False, + filterable="standard" ) ) + global_actions = [ + grids.GridAction( "Create new user", dict( controller='admin', action='users', operation='create' ) ) ] operations = [ grids.GridOperation( "Manage Roles & Groups", condition=( lambda item: not item.deleted ), allow_multiple=False ) - ] #TODO: enhance to account for trans.app.config.allow_user_deletion here so that we can eliminate these operations if # the setting is False operations.append( grids.GridOperation( "Reset Password", condition=( lambda item: not item.deleted ), allow_multiple=True, allow_popup=False ) ) operations.append( grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ), allow_multiple=True ) ) - operations.append( grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ), allow_multiple=True ) ) - operations.append( grids.GridOperation( "Purge", condition=( lambda item: item.deleted ), allow_multiple=True ) ) + operations.append( grids.GridOperation( "Undelete", condition=( lambda item: item.deleted and not item.purged ), allow_multiple=True ) ) + operations.append( grids.GridOperation( "Purge", condition=( lambda item: item.deleted and not item.purged ), allow_multiple=True ) ) + standard_filters = [ + grids.GridColumnFilter( "Active", args=dict( deleted=False ) ), + grids.GridColumnFilter( "Deleted", args=dict( deleted=True, purged=False ) ), + grids.GridColumnFilter( "Purged", args=dict( purged=True ) ), + grids.GridColumnFilter( "All", args=dict( deleted='All' ) ) + ] + default_filter = dict( email="All", username="All", deleted="False", purged="False" ) + num_rows_per_page = 50 + preserve_state = False + use_paging = True + def get_current_item( self, trans ): + return trans.user + def build_initial_query( self, session ): + return session.query( self.model_class ) + +class RoleListGrid( grids.Grid ): + class NameColumn( grids.TextColumn ): + def get_value( self, trans, grid, role ): + return role.name + class DescriptionColumn( grids.TextColumn ): + def get_value( self, trans, grid, role ): + if role.description: + return role.description + return '' + class TypeColumn( grids.TextColumn ): + def get_value( self, trans, grid, role ): + return role.type + class StatusColumn( grids.GridColumn ): + def get_value( self, trans, grid, role ): + if role.deleted: + return "deleted" + return "" + class DeletedColumn( grids.GridColumn ): + def get_accepted_filters( self ): + """ Returns a list of accepted filters for this column. """ + accepted_filter_labels_and_vals = { "active" : "False", "deleted" : "True", "all": "All" } + accepted_filters = [] + for label, val in accepted_filter_labels_and_vals.items(): + args = { self.key: val } + accepted_filters.append( grids.GridColumnFilter( label, args) ) + return accepted_filters + class GroupsColumn( grids.GridColumn ): + def get_value( self, trans, grid, role ): + if role.groups: + return len( role.groups ) + return 0 + class UsersColumn( grids.GridColumn ): + def get_value( self, trans, grid, role ): + if role.users: + return len( role.users ) + return 0 + + # Grid definition + title = "Roles" + model_class = model.Role + template='/admin/dataset_security/role/grid.mako' + default_sort_key = "name" + columns = [ + NameColumn( "Name", + key="name", + link=( lambda item: dict( controller="admin", action="role", id=item.id ) ), + model_class=model.Role, + attach_popup=True, + filterable="advanced" ), + DescriptionColumn( "Description", + key='description', + model_class=model.Role, + attach_popup=False, + filterable="advanced" ), + TypeColumn( "Type", + key='type', + model_class=model.Role, + attach_popup=False, + filterable="advanced" ), + GroupsColumn( "Groups", attach_popup=False ), + UsersColumn( "Users", attach_popup=False ), + StatusColumn( "Status", attach_popup=False ), + # Columns that are valid for filtering but are not visible. + DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" ) + ] + columns.append( grids.MulticolFilterColumn( "Search", + cols_to_filter=[ columns[0], columns[1], columns[2] ], + key="free-text-search", + visible=False, + filterable="standard" ) ) + global_actions = [ + grids.GridAction( "Add new role", dict( controller='admin', action='roles', operation='create' ) ) + ] + operations = [ grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ), allow_multiple=True ), + grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ), allow_multiple=True ), + grids.GridOperation( "Purge", condition=( lambda item: item.deleted ), allow_multiple=True ) ] standard_filters = [ grids.GridColumnFilter( "Active", args=dict( deleted=False ) ), grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ), grids.GridColumnFilter( "All", args=dict( deleted='All' ) ) ] - default_filter = dict( deleted=False ) + default_filter = dict( name="All", deleted="False", description="All", type="All" ) + num_rows_per_page = 50 + preserve_state = False + use_paging = True def get_current_item( self, trans ): - return trans.user + return None def build_initial_query( self, session ): return session.query( self.model_class ) def apply_default_filter( self, trans, query, **kwargs ): - email_filter = kwargs.get( "email_filter", None ) - if email_filter: - if email_filter == 'all': - return query - else: - return query.filter( or_( trans.app.model.User.table.c.email.like( '%s' % email_filter.lower() + '%' ), - trans.app.model.User.table.c.email.like( '%s' % email_filter.upper() + '%' ) ) ) - elif query.count() > 200: - return query.filter( or_( trans.app.model.User.table.c.email.like( 'A%' ), - trans.app.model.User.table.c.email.like( 'a%' ) ) ) - return query + return query.filter( model.Role.type != model.Role.types.PRIVATE ) + +class GroupListGrid( grids.Grid ): + class NameColumn( grids.TextColumn ): + def get_value( self, trans, grid, group ): + return group.name + class StatusColumn( grids.GridColumn ): + def get_value( self, trans, grid, group ): + if group.deleted: + return "deleted" + return "" + class DeletedColumn( grids.GridColumn ): + def get_accepted_filters( self ): + """ Returns a list of accepted filters for this column. """ + accepted_filter_labels_and_vals = { "active" : "False", "deleted" : "True", "all": "All" } + accepted_filters = [] + for label, val in accepted_filter_labels_and_vals.items(): + args = { self.key: val } + accepted_filters.append( grids.GridColumnFilter( label, args) ) + return accepted_filters + class RolesColumn( grids.GridColumn ): + def get_value( self, trans, grid, group ): + if group.roles: + return len( group.roles ) + return 0 + class UsersColumn( grids.GridColumn ): + def get_value( self, trans, grid, group ): + if group.members: + return len( group.members ) + return 0 + + # Grid definition + title = "Groups" + model_class = model.Group + template='/admin/dataset_security/group/grid.mako' + default_sort_key = "name" + columns = [ + NameColumn( "Name", + key="name", + link=( lambda item: dict( controller="admin", action="group", id=item.id ) ), + model_class=model.Group, + attach_popup=True, + filterable="advanced" ), + UsersColumn( "Users", attach_popup=False ), + RolesColumn( "Roles", attach_popup=False ), + StatusColumn( "Status", attach_popup=False ), + # Columns that are valid for filtering but are not visible. + DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" ) + ] + columns.append( grids.MulticolFilterColumn( "Search", + cols_to_filter=[ columns[0], columns[1], columns[2] ], + key="free-text-search", + visible=False, + filterable="standard" ) ) + global_actions = [ + grids.GridAction( "Add new group", dict( controller='admin', action='groups', operation='create' ) ) + ] + operations = [ grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ), allow_multiple=True ), + grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ), allow_multiple=True ), + grids.GridOperation( "Purge", condition=( lambda item: item.deleted ), allow_multiple=True ) ] + standard_filters = [ + grids.GridColumnFilter( "Active", args=dict( deleted=False ) ), + grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ), + grids.GridColumnFilter( "All", args=dict( deleted='All' ) ) + ] + default_filter = dict( name="All", deleted="False" ) + num_rows_per_page = 50 + preserve_state = False + use_paging = True + def get_current_item( self, trans ): + return None + def build_initial_query( self, session ): + return session.query( self.model_class ) class Admin( BaseController ): user_list_grid = UserListGrid() + role_list_grid = RoleListGrid() + group_list_grid = GroupListGrid() @web.expose @web.require_admin @@ -117,17 +314,23 @@ class Admin( BaseController ): # Galaxy Role Stuff @web.expose @web.require_admin - def roles( self, trans, **kwd ): - params = util.Params( kwd ) - msg = util.restore_text( params.get( 'msg', '' ) ) - messagetype = params.get( 'messagetype', 'done' ) - roles = trans.sa_session.query( trans.app.model.Role ).filter( and_( trans.app.model.Role.table.c.deleted==False, - trans.app.model.Role.table.c.type != trans.app.model.Role.types.PRIVATE ) ) \ - .order_by( trans.app.model.Role.table.c.name ) - return trans.fill_template( '/admin/dataset_security/roles.mako', - roles=roles, - msg=msg, - messagetype=messagetype ) + def roles( self, trans, **kwargs ): + if 'operation' in kwargs: + operation = kwargs['operation'].lower() + if operation == "roles": + return self.role( trans, **kwargs ) + if operation == "create": + return self.create_role( trans, **kwargs ) + if operation == "delete": + return self.mark_role_deleted( trans, **kwargs ) + if operation == "undelete": + return self.undelete_role( trans, **kwargs ) + if operation == "purge": + return self.purge_role( trans, **kwargs ) + if operation == "manage users & groups": + return self.role( trans, **kwargs ) + # Render the list view + return self.role_list_grid( trans, **kwargs ) @web.expose @web.require_admin def create_role( self, trans, **kwd ): @@ -164,7 +367,7 @@ class Admin( BaseController ): ( group.name, role.name, len( in_users ), len( in_groups ) ) else: msg = "Role '%s' has been created with %d associated users and %d associated groups" % ( role.name, len( in_users ), len( in_groups ) ) - trans.response.send_redirect( web.url_for( controller='admin', action='roles', msg=util.sanitize_text( msg ), messagetype='done' ) ) + trans.response.send_redirect( web.url_for( controller='admin', action='roles', message=util.sanitize_text( msg ), status='done' ) ) trans.response.send_redirect( web.url_for( controller='admin', action='create_role', msg=util.sanitize_text( msg ), messagetype='error' ) ) out_users = [] for user in trans.sa_session.query( trans.app.model.User ) \ @@ -176,7 +379,7 @@ class Admin( BaseController ): .filter( trans.app.model.Group.table.c.deleted==False ) \ .order_by( trans.app.model.Group.table.c.name ): out_groups.append( ( group.id, group.name ) ) - return trans.fill_template( '/admin/dataset_security/role_create.mako', + return trans.fill_template( '/admin/dataset_security/role/role_create.mako', in_users=[], out_users=out_users, in_groups=[], @@ -189,7 +392,7 @@ class Admin( BaseController ): params = util.Params( kwd ) msg = util.restore_text( params.get( 'msg', '' ) ) messagetype = params.get( 'messagetype', 'done' ) - role = trans.sa_session.query( trans.app.model.Role ).get( int( params.role_id ) ) + role = get_role( trans, params.id ) if params.get( 'role_members_edit_button', False ): in_users = [ trans.sa_session.query( trans.app.model.User ).get( x ) for x in util.listify( params.in_users ) ] for ura in role.users: @@ -210,7 +413,7 @@ class Admin( BaseController ): trans.app.security_agent.set_entity_role_associations( roles=[ role ], users=in_users, groups=in_groups ) trans.sa_session.refresh( role ) msg = "Role '%s' has been updated with %d associated users and %d associated groups" % ( role.name, len( in_users ), len( in_groups ) ) - trans.response.send_redirect( web.url_for( action='roles', msg=util.sanitize_text( msg ), messagetype=messagetype ) ) + trans.response.send_redirect( web.url_for( action='roles', message=util.sanitize_text( msg ), status=messagetype ) ) elif params.get( 'rename', False ): if params.rename == 'submitted': old_name = role.name @@ -218,17 +421,17 @@ class Admin( BaseController ): new_description = util.restore_text( params.description ) if not new_name: msg = 'Enter a valid name' - return trans.fill_template( '/admin/dataset_security/role_rename.mako', role=role, msg=msg, messagetype='error' ) + return trans.fill_template( '/admin/dataset_security/role/role_rename.mako', role=role, msg=msg, messagetype='error' ) elif trans.sa_session.query( trans.app.model.Role ).filter( trans.app.model.Role.table.c.name==new_name ).first(): msg = 'A role with that name already exists' - return trans.fill_template( '/admin/dataset_security/role_rename.mako', role=role, msg=msg, messagetype='error' ) + return trans.fill_template( '/admin/dataset_security/role/role_rename.mako', role=role, msg=msg, messagetype='error' ) else: role.name = new_name role.description = new_description role.flush() msg = "Role '%s' has been renamed to '%s'" % ( old_name, new_name ) - return trans.response.send_redirect( web.url_for( action='roles', msg=util.sanitize_text( msg ), messagetype='done' ) ) - return trans.fill_template( '/admin/dataset_security/role_rename.mako', role=role, msg=msg, messagetype=messagetype ) + return trans.response.send_redirect( web.url_for( action='roles', message=util.sanitize_text( msg ), status='done' ) ) + return trans.fill_template( '/admin/dataset_security/role/role_rename.mako', role=role, msg=msg, messagetype=messagetype ) in_users = [] out_users = [] in_groups = [] @@ -273,7 +476,7 @@ class Admin( BaseController ): library_dataset_actions[ library ][ folder_path ].append( dp.action ) except: library_dataset_actions[ library ][ folder_path ] = [ dp.action ] - return trans.fill_template( '/admin/dataset_security/role.mako', + return trans.fill_template( '/admin/dataset_security/role/role.mako', role=role, in_users=in_users, out_users=out_users, @@ -286,33 +489,20 @@ class Admin( BaseController ): @web.require_admin def mark_role_deleted( self, trans, **kwd ): params = util.Params( kwd ) - role = trans.sa_session.query( trans.app.model.Role ).get( int( params.role_id ) ) + role = get_role( trans, params.id ) role.deleted = True role.flush() - msg = "Role '%s' has been marked as deleted." % role.name - trans.response.send_redirect( web.url_for( action='roles', msg=util.sanitize_text( msg ), messagetype='done' ) ) - @web.expose - @web.require_admin - def deleted_roles( self, trans, **kwd ): - params = util.Params( kwd ) - msg = util.restore_text( params.get( 'msg', '' ) ) - messagetype = params.get( 'messagetype', 'done' ) - roles = trans.sa_session.query( trans.app.model.Role ) \ - .filter( trans.app.model.Role.table.c.deleted==True ) \ - .order_by( trans.app.model.Role.table.c.name ) - return trans.fill_template( '/admin/dataset_security/deleted_roles.mako', - roles=roles, - msg=msg, - messagetype=messagetype ) + message = "Role '%s' has been marked as deleted." % role.name + trans.response.send_redirect( web.url_for( action='roles', message=util.sanitize_text( message ), status='done' ) ) @web.expose @web.require_admin def undelete_role( self, trans, **kwd ): params = util.Params( kwd ) - role = trans.sa_session.query( trans.app.model.Role ).get( int( params.role_id ) ) + role = get_role( trans, params.id ) role.deleted = False role.flush() - msg = "Role '%s' has been marked as not deleted." % role.name - trans.response.send_redirect( web.url_for( action='roles', msg=util.sanitize_text( msg ), messagetype='done' ) ) + message = "Role '%s' has been marked as not deleted." % role.name + trans.response.send_redirect( web.url_for( action='roles', message=util.sanitize_text( message ), status='done' ) ) @web.expose @web.require_admin def purge_role( self, trans, **kwd ): @@ -324,11 +514,10 @@ class Admin( BaseController ): # - GroupRoleAssociations where role_id == Role.id # - DatasetPermissionss where role_id == Role.id params = util.Params( kwd ) - role = trans.sa_session.query( trans.app.model.Role ).get( int( params.role_id ) ) + role = get_role( trans, params.id ) if not role.deleted: - # We should never reach here, but just in case there is a bug somewhere... - msg = "Role '%s' has not been deleted, so it cannot be purged." % role.name - trans.response.send_redirect( web.url_for( action='roles', msg=util.sanitize_text( msg ), messagetype='error' ) ) + message = "Role '%s' has not been deleted, so it cannot be purged." % role.name + trans.response.send_redirect( web.url_for( action='roles', message=util.sanitize_text( message ), status='error' ) ) # Delete UserRoleAssociations for ura in role.users: user = trans.sa_session.query( trans.app.model.User ).get( ura.user_id ) @@ -353,54 +542,60 @@ class Admin( BaseController ): for dp in role.dataset_actions: trans.sa_session.delete( dp ) dp.flush() - msg = "The following have been purged from the database for role '%s': " % role.name - msg += "DefaultUserPermissions, DefaultHistoryPermissions, UserRoleAssociations, GroupRoleAssociations, DatasetPermissionss." - trans.response.send_redirect( web.url_for( action='deleted_roles', msg=util.sanitize_text( msg ), messagetype='done' ) ) + message = "The following have been purged from the database for role '%s': " % role.name + message += "DefaultUserPermissions, DefaultHistoryPermissions, UserRoleAssociations, GroupRoleAssociations, DatasetPermissionss." + trans.response.send_redirect( web.url_for( action='roles', message=util.sanitize_text( message ), status='done' ) ) # Galaxy Group Stuff @web.expose @web.require_admin - def groups( self, trans, **kwd ): - params = util.Params( kwd ) - msg = util.restore_text( params.get( 'msg', '' ) ) - messagetype = params.get( 'messagetype', 'done' ) - groups = trans.sa_session.query( trans.app.model.Group ) \ - .filter( trans.app.model.Group.table.c.deleted==False ) \ - .order_by( trans.app.model.Group.table.c.name ) - return trans.fill_template( '/admin/dataset_security/groups.mako', - groups=groups, - msg=msg, - messagetype=messagetype ) + def groups( self, trans, **kwargs ): + if 'operation' in kwargs: + operation = kwargs['operation'].lower() + if operation == "groups": + return self.group( trans, **kwargs ) + if operation == "create": + return self.create_group( trans, **kwargs ) + if operation == "delete": + return self.mark_group_deleted( trans, **kwargs ) + if operation == "undelete": + return self.undelete_group( trans, **kwargs ) + if operation == "purge": + return self.purge_group( trans, **kwargs ) + if operation == "manage users & roles": + return self.group( trans, **kwargs ) + # Render the list view + return self.group_list_grid( trans, **kwargs ) @web.expose @web.require_admin def group( self, trans, **kwd ): params = util.Params( kwd ) msg = util.restore_text( params.get( 'msg', '' ) ) messagetype = params.get( 'messagetype', 'done' ) - group = trans.sa_session.query( trans.app.model.Group ).get( int( params.group_id ) ) + group = get_group( trans, params.id ) if params.get( 'group_roles_users_edit_button', False ): in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( x ) for x in util.listify( params.in_roles ) ] in_users = [ trans.sa_session.query( trans.app.model.User ).get( x ) for x in util.listify( params.in_users ) ] trans.app.security_agent.set_entity_group_associations( groups=[ group ], roles=in_roles, users=in_users ) trans.sa_session.refresh( group ) msg += "Group '%s' has been updated with %d associated roles and %d associated users" % ( group.name, len( in_roles ), len( in_users ) ) - trans.response.send_redirect( web.url_for( action='groups', msg=util.sanitize_text( msg ), messagetype=messagetype ) ) + trans.response.send_redirect( web.url_for( action='groups', message=util.sanitize_text( msg ), status=messagetype ) ) if params.get( 'rename', False ): if params.rename == 'submitted': old_name = group.name new_name = util.restore_text( params.name ) if not new_name: msg = 'Enter a valid name' - return trans.fill_template( '/admin/dataset_security/group_rename.mako', group=group, msg=msg, messagetype='error' ) + return trans.fill_template( '/admin/dataset_security/group/group_rename.mako', group=group, msg=msg, messagetype='error' ) elif trans.sa_session.query( trans.app.model.Group ).filter( trans.app.model.Group.table.c.name==new_name ).first(): msg = 'A group with that name already exists' - return trans.fill_template( '/admin/dataset_security/group_rename.mako', group=group, msg=msg, messagetype='error' ) + return trans.fill_template( '/admin/dataset_security/group/group_rename.mako', group=group, msg=msg, messagetype='error' ) else: group.name = new_name group.flush() msg = "Group '%s' has been renamed to '%s'" % ( old_name, new_name ) return trans.response.send_redirect( web.url_for( action='groups', msg=util.sanitize_text( msg ), messagetype='done' ) ) - return trans.fill_template( '/admin/dataset_security/group_rename.mako', group=group, msg=msg, messagetype=messagetype ) + return trans.fill_template( '/admin/dataset_security/group/group_rename.mako', group=group, msg=msg, messagetype=messagetype ) in_roles = [] out_roles = [] in_users = [] @@ -420,7 +615,7 @@ class Admin( BaseController ): else: out_users.append( ( user.id, user.email ) ) msg += 'Group %s is currently associated with %d roles and %d users' % ( group.name, len( in_roles ), len( in_users ) ) - return trans.fill_template( '/admin/dataset_security/group.mako', + return trans.fill_template( '/admin/dataset_security/group/group.mako', group=group, in_roles=in_roles, out_roles=out_roles, @@ -455,7 +650,7 @@ class Admin( BaseController ): gra = trans.app.model.GroupRoleAssociation( group, role ) gra.flush() msg = "Group '%s' has been created with %d associated users and %d associated roles" % ( name, len( in_users ), len( in_roles ) ) - trans.response.send_redirect( web.url_for( controller='admin', action='groups', msg=util.sanitize_text( msg ), messagetype='done' ) ) + trans.response.send_redirect( web.url_for( controller='admin', action='groups', message=util.sanitize_text( msg ), status='done' ) ) trans.response.send_redirect( web.url_for( controller='admin', action='create_group', msg=util.sanitize_text( msg ), messagetype='error' ) ) out_users = [] for user in trans.sa_session.query( trans.app.model.User ) \ @@ -467,7 +662,7 @@ class Admin( BaseController ): .filter( trans.app.model.Role.table.c.deleted==False ) \ .order_by( trans.app.model.Role.table.c.name ): out_roles.append( ( role.id, role.name ) ) - return trans.fill_template( '/admin/dataset_security/group_create.mako', + return trans.fill_template( '/admin/dataset_security/group/group_create.mako', in_users=[], out_users=out_users, in_roles=[], @@ -478,44 +673,31 @@ class Admin( BaseController ): @web.require_admin def mark_group_deleted( self, trans, **kwd ): params = util.Params( kwd ) - group = trans.sa_session.query( trans.app.model.Group ).get( int( params.group_id ) ) + group = get_group( trans, params.id ) group.deleted = True group.flush() msg = "Group '%s' has been marked as deleted." % group.name - trans.response.send_redirect( web.url_for( action='groups', msg=util.sanitize_text( msg ), messagetype='done' ) ) - @web.expose - @web.require_admin - def deleted_groups( self, trans, **kwd ): - params = util.Params( kwd ) - msg = util.restore_text( params.get( 'msg', '' ) ) - messagetype = params.get( 'messagetype', 'done' ) - groups = trans.sa_session.query( trans.app.model.Group ) \ - .filter( trans.app.model.Group.table.c.deleted==True ) \ - .order_by( trans.app.model.Group.table.c.name ) - return trans.fill_template( '/admin/dataset_security/deleted_groups.mako', - groups=groups, - msg=msg, - messagetype=messagetype ) + trans.response.send_redirect( web.url_for( action='groups', message=util.sanitize_text( msg ), status='done' ) ) @web.expose @web.require_admin def undelete_group( self, trans, **kwd ): params = util.Params( kwd ) - group = trans.sa_session.query( trans.app.model.Group ).get( int( params.group_id ) ) + group = get_group( trans, params.id ) group.deleted = False group.flush() msg = "Group '%s' has been marked as not deleted." % group.name - trans.response.send_redirect( web.url_for( action='groups', msg=util.sanitize_text( msg ), messagetype='done' ) ) + trans.response.send_redirect( web.url_for( action='groups', message=util.sanitize_text( msg ), status='done' ) ) @web.expose @web.require_admin def purge_group( self, trans, **kwd ): # This method should only be called for a Group that has previously been deleted. # Purging a deleted Group simply deletes all UserGroupAssociations and GroupRoleAssociations. params = util.Params( kwd ) - group = trans.sa_session.query( trans.app.model.Group ).get( int( params.group_id ) ) + group = get_group( trans, params.id ) if not group.deleted: # We should never reach here, but just in case there is a bug somewhere... msg = "Group '%s' has not been deleted, so it cannot be purged." % group.name - trans.response.send_redirect( web.url_for( action='groups', msg=util.sanitize_text( msg ), messagetype='error' ) ) + trans.response.send_redirect( web.url_for( action='groups', message=util.sanitize_text( msg ), status='error' ) ) # Delete UserGroupAssociations for uga in group.users: trans.sa_session.delete( uga ) @@ -525,8 +707,8 @@ class Admin( BaseController ): trans.sa_session.delete( gra ) gra.flush() # Delete the Group - msg = "The following have been purged from the database for group '%s': UserGroupAssociations, GroupRoleAssociations." % group.name - trans.response.send_redirect( web.url_for( action='deleted_groups', msg=util.sanitize_text( msg ), messagetype='done' ) ) + message = "The following have been purged from the database for group '%s': UserGroupAssociations, GroupRoleAssociations." % group.name + trans.response.send_redirect( web.url_for( action='groups', message=util.sanitize_text( message ), status='done' ) ) # Galaxy User Stuff @web.expose @@ -645,11 +827,12 @@ class Admin( BaseController ): message = "No user ids received for deleting" trans.response.send_redirect( web.url_for( action='users', message=message, status='error' ) ) ids = util.listify( id ) + message = "Deleted %d users: " % len( ids ) for user_id in ids: user = get_user( trans, user_id ) user.deleted = True user.flush() - message = "Deleted %d users" % len( ids ) + message += " %s " % user.email trans.response.send_redirect( web.url_for( action='users', message=util.sanitize_text( message ), status='done' ) ) @web.expose @web.require_admin @@ -660,13 +843,15 @@ class Admin( BaseController ): trans.response.send_redirect( web.url_for( action='users', message=message, status='error' ) ) ids = util.listify( id ) count = 0 + undeleted_users = "" for user_id in ids: user = get_user( trans, user_id ) if user.deleted: user.deleted = False user.flush() count += 1 - message = "Undeleted %d users" % count + undeleted_users += " %s" % user.email + message = "Undeleted %d users: %s" % ( count, undeleted_users ) trans.response.send_redirect( web.url_for( action='users', message=util.sanitize_text( message ), status='done' ) ) @@ -691,6 +876,7 @@ class Admin( BaseController ): message=util.sanitize_text( message ), status='error' ) ) ids = util.listify( id ) + message = "Purged %d users: " % len( ids ) for user_id in ids: user = get_user( trans, user_id ) if not user.deleted: @@ -726,7 +912,7 @@ class Admin( BaseController ): # Purge the user user.purged = True user.flush() - message = "Purged %d users" % len( ids ) + message += "%s " % user.email trans.response.send_redirect( web.url_for( controller='admin', action='users', message=util.sanitize_text( message ), @@ -750,6 +936,8 @@ class Admin( BaseController ): return self.create_new_user( trans, **kwargs ) if operation == "information": return self.user_info( trans, **kwargs ) + if operation == "manage roles & groups": + return self.user( trans, **kwargs ) # Render the list view return self.user_list_grid( trans, **kwargs ) @web.expose @@ -774,6 +962,14 @@ class Admin( BaseController ): admin_view=True, **kwd ) ) @web.expose @web.require_admin + def name_autocomplete_data( self, trans, q=None, limit=None, timestamp=None ): + """Return autocomplete data for user emails""" + ac_data = "" + for user in trans.sa_session.query( User ).filter_by( deleted=False ).filter( func.lower( User.email ).like( q.lower() + "%" ) ): + ac_data = ac_data + user.email + "\n" + return ac_data + @web.expose + @web.require_admin def user( self, trans, **kwd ): user_id = kwd.get( 'id', None ) message = '' @@ -932,5 +1128,21 @@ def get_user( trans, id ): id = trans.security.decode_id( id ) user = trans.sa_session.query( model.User ).get( id ) if not user: - err+msg( "User not found" ) + return trans.show_error_message( "User not found for id (%s)" % str( id ) ) return user +def get_role( trans, id ): + """Get a Role from the database by id.""" + # Load user from database + id = trans.security.decode_id( id ) + role = trans.sa_session.query( model.Role ).get( id ) + if not role: + return trans.show_error_message( "Role not found for id (%s)" % str( id ) ) + return role +def get_group( trans, id ): + """Get a Group from the database by id.""" + # Load user from database + id = trans.security.decode_id( id ) + group = trans.sa_session.query( model.Group ).get( id ) + if not group: + return trans.show_error_message( "Group not found for id (%s)" % str( id ) ) + return group diff --git a/templates/admin/dataset_security/deleted_groups.mako b/templates/admin/dataset_security/deleted_groups.mako deleted file mode 100644 index 63d17241d2d..00000000000 --- a/templates/admin/dataset_security/deleted_groups.mako +++ /dev/null @@ -1,101 +0,0 @@ -<%inherit file="/base.mako"/> -<%namespace file="/message.mako" import="render_msg" /> - -## Render a row -<%def name="render_row( group, ctr, anchored, curr_anchor )"> - %if ctr % 2 == 1: - - %else: - - %endif - - ${group.name} - -
- Undelete - Purge -
- - - ${len( group.members )} - - - ${len( group.roles )} - %if not anchored: - -
top
- %endif - - - - -

Deleted Groups

- -%if msg: - ${render_msg( msg, messagetype )} -%endif - -## TODO: make this a grid - -%if not groups: - There are no deleted Galaxy groups -%else: - - <% - render_quick_find = groups.count() > 200 - ctr = 0 - %> - %if render_quick_find: - <% - anchors = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] - anchor_loc = 0 - anchored = False - curr_anchor = 'A' - %> - - - - %endif - - - - - - %for ctr, group in enumerate( groups ): - %if render_quick_find and not group.name.upper().startswith( curr_anchor ): - <% anchored = False %> - %endif - %if render_quick_find and group.name.upper().startswith( curr_anchor ): - %if not anchored: - ${render_row( group, ctr, anchored, curr_anchor )} - <% anchored = True %> - %else: - ${render_row( group, ctr, anchored, curr_anchor )} - %endif - %elif render_quick_find: - %for anchor in anchors[ anchor_loc: ]: - %if group.name.upper().startswith( anchor ): - %if not anchored: - <% curr_anchor = anchor %> - ${render_row( group, ctr, anchored, curr_anchor )} - <% anchored = True %> - %else: - ${render_row( group, ctr, anchored, curr_anchor )} - %endif - <% - anchor_loc = anchors.index( anchor ) - break - %> - %endif - %endfor - %else: - ${render_row( group, ctr, True, '' )} - %endif - %endfor -
- Jump to letter: - %for a in anchors: - | ${a} - %endfor -
NameUsersRoles
-%endif diff --git a/templates/admin/dataset_security/deleted_roles.mako b/templates/admin/dataset_security/deleted_roles.mako deleted file mode 100644 index 7cfa03b0ed4..00000000000 --- a/templates/admin/dataset_security/deleted_roles.mako +++ /dev/null @@ -1,103 +0,0 @@ -<%inherit file="/base.mako"/> -<%namespace file="/message.mako" import="render_msg" /> - -## Render a row -<%def name="render_row( role, ctr, anchored, curr_anchor )"> - %if ctr % 2 == 1: - - %else: - - %endif - - ${role.name} - -
- Undelete - Purge -
- - ${role.description} - ${role.type} - - ${len( role.users )} - - - ${len( role.groups )} - %if not anchored: - -
top
- %endif - - - - -

Deleted Roles

- -%if msg: - ${render_msg( msg, messagetype )} -%endif - -%if not roles: - There are no deleted Galaxy roles -%else: - - <% - render_quick_find = roles.count() > 200 - ctr = 0 - %> - %if render_quick_find: - <% - anchors = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] - anchor_loc = 0 - anchored = False - curr_anchor = 'A' - %> - - - - %endif - - - - - - - - %for ctr, role in enumerate( roles ): - %if render_quick_find and not role.name.upper().startswith( curr_anchor ): - <% anchored = False %> - %endif - %if render_quick_find and role.name.upper().startswith( curr_anchor ): - %if not anchored: - ${render_row( role, ctr, anchored, curr_anchor )} - <% anchored = True %> - %else: - ${render_row( role, ctr, anchored, curr_anchor )} - %endif - %elif render_quick_find: - %for anchor in anchors[ anchor_loc: ]: - %if role.name.upper().startswith( anchor ): - %if not anchored: - <% curr_anchor = anchor %> - ${render_row( role, ctr, anchored, curr_anchor )} - <% anchored = True %> - %else: - ${render_row( role, ctr, anchored, curr_anchor )} - %endif - <% - anchor_loc = anchors.index( anchor ) - break - %> - %endif - %endfor - %else: - ${render_row( role, ctr, True, '' )} - %endif - %endfor -
- Jump to letter: - %for a in anchors: - | ${a} - %endfor -
NameDescriptionTypeUsersGroups
-%endif diff --git a/templates/admin/dataset_security/group/grid.mako b/templates/admin/dataset_security/group/grid.mako new file mode 100644 index 00000000000..6a41b688c5e --- /dev/null +++ b/templates/admin/dataset_security/group/grid.mako @@ -0,0 +1 @@ +<%inherit file="/grid_base.mako"/> diff --git a/templates/admin/dataset_security/group.mako b/templates/admin/dataset_security/group/group.mako similarity index 100% rename from templates/admin/dataset_security/group.mako rename to templates/admin/dataset_security/group/group.mako diff --git a/templates/admin/dataset_security/group_create.mako b/templates/admin/dataset_security/group/group_create.mako similarity index 100% rename from templates/admin/dataset_security/group_create.mako rename to templates/admin/dataset_security/group/group_create.mako diff --git a/templates/admin/dataset_security/group_rename.mako b/templates/admin/dataset_security/group/group_rename.mako similarity index 92% rename from templates/admin/dataset_security/group_rename.mako rename to templates/admin/dataset_security/group/group_rename.mako index 0e068f3ed3c..60c6b6d406d 100644 --- a/templates/admin/dataset_security/group_rename.mako +++ b/templates/admin/dataset_security/group/group_rename.mako @@ -24,7 +24,7 @@
- +
diff --git a/templates/admin/dataset_security/groups.mako b/templates/admin/dataset_security/groups.mako deleted file mode 100644 index 3551e5f051b..00000000000 --- a/templates/admin/dataset_security/groups.mako +++ /dev/null @@ -1,107 +0,0 @@ -<%inherit file="/base.mako"/> -<%namespace file="/message.mako" import="render_msg" /> - -## Render a row -<%def name="render_row( group, ctr, anchored, curr_anchor )"> - %if ctr % 2 == 1: - - %else: - - %endif - - ${group.name} - -
- Rename this group - Change associated users and roles - Mark group deleted -
- - - ${len( group.members )} - - - ${len( group.roles )} - %if not anchored: - -
top
- %endif - - - - -

Groups

- - - -%if msg: - ${render_msg( msg, messagetype )} -%endif - -## TODO: make this a grid - -%if not groups: - There are no Galaxy groups -%else: - - <% - render_quick_find = groups.count() > 200 - ctr = 0 - %> - %if render_quick_find: - <% - anchors = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] - anchor_loc = 0 - anchored = False - curr_anchor = 'A' - %> - - - - %endif - - - - - - %for ctr, group in enumerate( groups ): - %if render_quick_find and not group.name.upper().startswith( curr_anchor ): - <% anchored = False %> - %endif - %if render_quick_find and group.name.upper().startswith( curr_anchor ): - %if not anchored: - ${render_row( group, ctr, anchored, curr_anchor )} - <% anchored = True %> - %else: - ${render_row( group, ctr, anchored, curr_anchor )} - %endif - %elif render_quick_find: - %for anchor in anchors[ anchor_loc: ]: - %if group.name.upper().startswith( anchor ): - %if not anchored: - <% curr_anchor = anchor %> - ${render_row( group, ctr, anchored, curr_anchor )} - <% anchored = True %> - %else: - ${render_row( group, ctr, anchored, curr_anchor )} - %endif - <% - anchor_loc = anchors.index( anchor ) - break - %> - %endif - %endfor - %else: - ${render_row( group, ctr, True, '' )} - %endif - %endfor -
- Jump to letter: - %for a in anchors: - | ${a} - %endfor -
NameUsersRoles
-%endif diff --git a/templates/admin/dataset_security/role/grid.mako b/templates/admin/dataset_security/role/grid.mako new file mode 100644 index 00000000000..6a41b688c5e --- /dev/null +++ b/templates/admin/dataset_security/role/grid.mako @@ -0,0 +1 @@ +<%inherit file="/grid_base.mako"/> diff --git a/templates/admin/dataset_security/role.mako b/templates/admin/dataset_security/role/role.mako similarity index 100% rename from templates/admin/dataset_security/role.mako rename to templates/admin/dataset_security/role/role.mako diff --git a/templates/admin/dataset_security/role_create.mako b/templates/admin/dataset_security/role/role_create.mako similarity index 100% rename from templates/admin/dataset_security/role_create.mako rename to templates/admin/dataset_security/role/role_create.mako diff --git a/templates/admin/dataset_security/role_rename.mako b/templates/admin/dataset_security/role/role_rename.mako similarity index 94% rename from templates/admin/dataset_security/role_rename.mako rename to templates/admin/dataset_security/role/role_rename.mako index d70844d6f55..e17265c35da 100644 --- a/templates/admin/dataset_security/role_rename.mako +++ b/templates/admin/dataset_security/role/role_rename.mako @@ -31,7 +31,7 @@
- +
diff --git a/templates/admin/dataset_security/roles.mako b/templates/admin/dataset_security/roles.mako deleted file mode 100644 index 5acf31ad278..00000000000 --- a/templates/admin/dataset_security/roles.mako +++ /dev/null @@ -1,109 +0,0 @@ -<%inherit file="/base.mako"/> -<%namespace file="/message.mako" import="render_msg" /> - -## Render a row -<%def name="render_row( role, ctr, anchored, curr_anchor )"> - %if ctr % 2 == 1: - - %else: - - %endif - - ${role.name} - -
- Rename this role - Change associated users and groups - Mark role deleted -
- - ${role.description} - ${role.type} - - ${len( role.users )} - - - ${len( role.groups )} - %if not anchored: - -
top
- %endif - - - - -

Roles

- - - -%if msg: - ${render_msg( msg, messagetype )} -%endif - -%if not roles: - There are no non-private Galaxy roles -%else: - - <% - render_quick_find = roles.count() > 200 - ctr = 0 - %> - %if render_quick_find: - <% - anchors = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] - anchor_loc = 0 - anchored = False - curr_anchor = 'A' - %> - - - - %endif - - - - - - - - %for ctr, role in enumerate( roles ): - %if render_quick_find and not role.name.upper().startswith( curr_anchor ): - <% anchored = False %> - %endif - %if render_quick_find and role.name.upper().startswith( curr_anchor ): - %if not anchored: - ${render_row( role, ctr, anchored, curr_anchor )} - <% anchored = True %> - %else: - ${render_row( role, ctr, anchored, curr_anchor )} - %endif - %elif render_quick_find: - %for anchor in anchors[ anchor_loc: ]: - %if role.name.upper().startswith( anchor ): - %if not anchored: - <% curr_anchor = anchor %> - ${render_row( role, ctr, anchored, curr_anchor )} - <% anchored = True %> - %else: - ${render_row( role, ctr, anchored, curr_anchor )} - %endif - <% - anchor_loc = anchors.index( anchor ) - break - %> - %endif - %endfor - %else: - ${render_row( role, ctr, True, '' )} - %endif - %endfor -
- Jump to letter: - %for a in anchors: - | ${a} - %endfor -
NameDescriptionTypeUsersGroups
-%endif diff --git a/templates/admin/user/grid.mako b/templates/admin/user/grid.mako index 1aab076e48e..6a41b688c5e 100644 --- a/templates/admin/user/grid.mako +++ b/templates/admin/user/grid.mako @@ -1,224 +1 @@ -<%inherit file="/base.mako"/> -<%def name="title()">${grid.title} -<% from galaxy import util %> - -%if message: -

-

${util.restore_text( message )}
-
-

-%endif - -<%def name="javascripts()"> - ${parent.javascripts()} - ${h.js("jquery.autocomplete", "autocomplete_tagging" )} - - - -<%def name="stylesheets()"> - ${h.css( "base", "autocomplete_tagging" )} - - - -%if grid.standard_filters: -
-

${grid.title}

- Filter: - %for i, filter in enumerate( grid.standard_filters ): - %if i > 0: - | - %endif - ${filter.label} - %endfor -
-%endif - - - -%if query.count() == 0: - No users were returned for the current query. Click the Show all users button or a letter below. -%endif: -<% - letters = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] -%> -
-
- Show all users -
- Default behavior is displaying only users whose email begins with 'a' if there are more than 200 total users -
-
-
- - %for letter in letters: - | ${letter} - %endfor -
-
-
- - - - - %for column in grid.columns: - %if column.visible: - <% - href = "" - extra = "" - if column.sortable: - if sort_key == column.key: - if sort_order == "asc": - href = url( sort=( "-" + column.key ) ) - extra = "↓" - else: - href = url( sort=( column.key ) ) - extra = "↑" - else: - href = url( sort=column.key ) - %> - 1: - colspan="${column.ncells}" - %endif - > - %if href: - ${column.label} - %else: - ${column.label} - %endif - ${extra} - - %endif - %endfor - - - - - %for i, item in enumerate( query ): - - ## Item selection column - - ## Data columns - %for column in grid.columns: - %if column.visible: - <% - # Link - link = column.get_link( trans, grid, item ) - if link: - href = url( **link ) - else: - href = None - # Value (coerced to list so we can loop) - value = column.get_value( trans, grid, item ) - if column.ncells == 1: - value = [ value ] - %> - %for cellnum, v in enumerate( value ): - <% - # Attach popup menu? - if column.attach_popup and cellnum == 0: - extra = '' % i - else: - extra = "" - %> - %if href: - - %else: - - %endif - %endfor - %endif - %endfor - ## Actions column - - - %endfor - - %if grid.operations: - - - - - - - %endif -
- - ${v}${extra} -
- %for operation in grid.operations: - %if operation.allowed( item ) and operation.allow_popup: - ${operation.label} - %endif - %endfor -
-
- For selected users: - %for operation in grid.operations: - %if operation.allow_multiple: - - %endif - %endfor -
-
-
+<%inherit file="/grid_base.mako"/> diff --git a/templates/grid_base.mako b/templates/grid_base.mako index 618e3a22b28..65df11e6743 100644 --- a/templates/grid_base.mako +++ b/templates/grid_base.mako @@ -1,5 +1,6 @@ <%! - from galaxy.model import History, HistoryDatasetAssociation + from galaxy.model import History, HistoryDatasetAssociation, User, Role, Group + import galaxy.util def inherit(context): if context.get('use_panels'): return '/base_panels.mako' @@ -11,7 +12,7 @@ ## Render the grid's basic elements. Each of these elements can be subclassed. %if message:

-

${message}
+
${util.restore_text( message )}

%endif @@ -303,6 +304,12 @@ ${self.grid_table()} items_plural = "histories" elif grid.model_class == HistoryDatasetAssociation: items_plural = "datasets" + elif grid.model_class == User: + items_plural = "users" + elif grid.model_class == Role: + items_plural = "roles" + elif grid.model_class == Group: + items_plural = "groups" %> %if num_pages > 1: diff --git a/test/base/twilltestcase.py b/test/base/twilltestcase.py index d4f7e53661a..8325d0e358c 100644 --- a/test/base/twilltestcase.py +++ b/test/base/twilltestcase.py @@ -672,7 +672,8 @@ class TwillTestCase( unittest.TestCase ): self.check_page_for_string( "The user information has been updated with the changes." ) for value in info_values: self.check_page_for_string( value ) - def user_set_default_permissions( self, permissions_out=[], permissions_in=[], role_id=2 ): # role.id = 2 is Private Role for test2@bx.psu.edu + def user_set_default_permissions( self, permissions_out=[], permissions_in=[], role_id='2' ): + # role.id = 2 is Private Role for test2@bx.psu.edu # NOTE: Twill has a bug that requires the ~/user/permissions page to contain at least 1 option value # in each select list or twill throws an exception, which is: ParseError: OPTION outside of SELECT # Due to this bug, we'll bypass visiting the page, and simply pass the permissions on to the @@ -921,6 +922,7 @@ class TwillTestCase( unittest.TestCase ): # Tests associated with users def create_new_account_as_admin( self, email='test4@bx.psu.edu', password='testuser' ): """Create a new account for another user""" + # TODO: fix this so that it uses the form rather than the following URL. self.home() self.visit_url( "%s/user/create?admin_view=True&email=%s&password=%s&confirm=%s&create_user_button=Submit&subscribe=False" \ % ( self.url, email, password, password ) ) @@ -983,7 +985,13 @@ class TwillTestCase( unittest.TestCase ): self.home() # Tests associated with roles - def create_role( self, name='Role One', description="This is Role One", in_user_ids=[], in_group_ids=[], create_group_for_role='no', private_role='' ): + def create_role( self, + name='Role One', + description="This is Role One", + in_user_ids=[], + in_group_ids=[], + create_group_for_role='no', + private_role='' ): """Create a new role""" url = "%s/admin/create_role?create_role_button=Save&name=%s&description=%s" % ( self.url, name.replace( ' ', '+' ), description.replace( ' ', '+' ) ) if in_user_ids: @@ -1017,7 +1025,7 @@ class TwillTestCase( unittest.TestCase ): def rename_role( self, role_id, name='Role One Renamed', description='This is Role One Re-described' ): """Rename a role""" self.home() - self.visit_url( "%s/admin/role?rename=True&role_id=%s" % ( self.url, role_id ) ) + self.visit_url( "%s/admin/role?rename=True&id=%s" % ( self.url, role_id ) ) self.check_page_for_string( 'Change role name and description' ) tc.fv( "1", "name", name ) tc.fv( "1", "description", description ) @@ -1026,28 +1034,28 @@ class TwillTestCase( unittest.TestCase ): def mark_role_deleted( self, role_id, role_name ): """Mark a role as deleted""" self.home() - self.visit_url( "%s/admin/mark_role_deleted?role_id=%s" % ( self.url, role_id ) ) + self.visit_url( "%s/admin/roles?operation=delete&id=%s" % ( self.url, role_id ) ) check_str = "Role '%s' has been marked as deleted" % role_name self.check_page_for_string( check_str ) self.home() def undelete_role( self, role_id, role_name ): """Undelete an existing role""" self.home() - self.visit_url( "%s/admin/undelete_role?role_id=%s" % ( self.url, role_id ) ) + self.visit_url( "%s/admin/roles?operation=undelete&id=%s" % ( self.url, role_id ) ) check_str = "Role '%s' has been marked as not deleted" % role_name self.check_page_for_string( check_str ) self.home() def purge_role( self, role_id, role_name ): """Purge an existing role""" self.home() - self.visit_url( "%s/admin/purge_role?role_id=%s" % ( self.url, role_id ) ) + self.visit_url( "%s/admin/roles?operation=purge&id=%s" % ( self.url, role_id ) ) check_str = "The following have been purged from the database for role '%s': " % role_name check_str += "DefaultUserPermissions, DefaultHistoryPermissions, UserRoleAssociations, GroupRoleAssociations, DatasetPermissionss." self.check_page_for_string( check_str ) self.home() def associate_users_and_groups_with_role( self, role_id, role_name, user_ids=[], group_ids=[] ): self.home() - url = "%s/admin/role?role_id=%s&role_members_edit_button=Save" % ( self.url, role_id ) + url = "%s/admin/role?id=%s&role_members_edit_button=Save" % ( self.url, role_id ) if user_ids: url += "&in_users=%s" % ','.join( user_ids ) if group_ids: @@ -1076,14 +1084,14 @@ class TwillTestCase( unittest.TestCase ): def rename_group( self, group_id, name='Group One Renamed' ): """Rename a group""" self.home() - self.visit_url( "%s/admin/group?rename=True&group_id=%s" % ( self.url, group_id ) ) + self.visit_url( "%s/admin/group?rename=True&id=%s" % ( self.url, group_id ) ) self.check_page_for_string( 'Change group name' ) tc.fv( "1", "name", name ) tc.submit( "rename_group_button" ) self.home() def associate_users_and_roles_with_group( self, group_id, group_name, user_ids=[], role_ids=[] ): self.home() - url = "%s/admin/group?group_id=%s&group_roles_users_edit_button=Save" % ( self.url, group_id ) + url = "%s/admin/group?id=%s&group_roles_users_edit_button=Save" % ( self.url, group_id ) if user_ids: url += "&in_users=%s" % ','.join( user_ids ) if role_ids: @@ -1095,21 +1103,21 @@ class TwillTestCase( unittest.TestCase ): def mark_group_deleted( self, group_id, group_name ): """Mark a group as deleted""" self.home() - self.visit_url( "%s/admin/mark_group_deleted?group_id=%s" % ( self.url, group_id ) ) + self.visit_url( "%s/admin/groups?operation=delete&id=%s" % ( self.url, group_id ) ) check_str = "Group '%s' has been marked as deleted" % group_name self.check_page_for_string( check_str ) self.home() def undelete_group( self, group_id, group_name ): """Undelete an existing group""" self.home() - self.visit_url( "%s/admin/undelete_group?group_id=%s" % ( self.url, group_id ) ) + self.visit_url( "%s/admin/groups?operation=undelete&id=%s" % ( self.url, group_id ) ) check_str = "Group '%s' has been marked as not deleted" % group_name self.check_page_for_string( check_str ) self.home() def purge_group( self, group_id, group_name ): """Purge an existing group""" self.home() - self.visit_url( "%s/admin/purge_group?group_id=%s" % ( self.url, group_id ) ) + self.visit_url( "%s/admin/groups?operation=purge&id=%s" % ( self.url, group_id ) ) check_str = "The following have been purged from the database for group '%s': UserGroupAssociations, GroupRoleAssociations." % group_name self.check_page_for_string( check_str ) self.home() diff --git a/test/functional/test_history_functions.py b/test/functional/test_history_functions.py index 6d7ccea9322..2d922055f29 100644 --- a/test/functional/test_history_functions.py +++ b/test/functional/test_history_functions.py @@ -780,8 +780,8 @@ class TestHistory( TwillTestCase ): self.delete_history( id=self.security.encode_id( history4.id ) ) self.delete_history( id=self.security.encode_id( history5.id ) ) # Eliminate Sharing role for: test@bx.psu.edu, test2@bx.psu.edu - self.mark_role_deleted( str( sharing_role.id ), sharing_role.name ) - self.purge_role( str( sharing_role.id ), sharing_role.name ) + self.mark_role_deleted( self.security.encode_id( sharing_role.id ), sharing_role.name ) + self.purge_role( self.security.encode_id( sharing_role.id ), sharing_role.name ) # Manually delete the sharing role from the database sa_session.refresh( sharing_role ) sa_session.delete( sharing_role ) diff --git a/test/functional/test_security_and_libraries.py b/test/functional/test_security_and_libraries.py index 745a942fe28..d70b7ccdf29 100644 --- a/test/functional/test_security_and_libraries.py +++ b/test/functional/test_security_and_libraries.py @@ -327,8 +327,12 @@ class TestSecurityAndLibraries( TwillTestCase ): name = 'Role One' description = "This is Role Ones description" user_ids=[ str( admin_user.id ), str( regular_user1.id ), str( regular_user3.id ) ] - self.create_role( name=name, description=description, in_user_ids=user_ids, in_group_ids=[], - create_group_for_role='yes', private_role=admin_user.email ) + self.create_role( name=name, + description=description, + in_user_ids=user_ids, + in_group_ids=[], + create_group_for_role='yes', + private_role=admin_user.email ) # Get the role object for later tests global role_one role_one = sa_session.query( galaxy.model.Role ).filter( galaxy.model.Role.table.c.name==name ).first() @@ -352,13 +356,13 @@ class TestSecurityAndLibraries( TwillTestCase ): # Rename the role rename = "Role One's been Renamed" redescription="This is Role One's Re-described" - self.rename_role( str( role_one.id ), name=rename, description=redescription ) + self.rename_role( self.security.encode_id( role_one.id ), name=rename, description=redescription ) self.home() self.visit_page( 'admin/roles' ) self.check_page_for_string( rename ) self.check_page_for_string( redescription ) # Reset the role back to the original name and description - self.rename_role( str( role_one.id ), name=name, description=description ) + self.rename_role( self.security.encode_id( role_one.id ), name=name, description=description ) def test_050_create_group( self ): """Testing creating new group with 3 members and 1 associated role, then renaming it""" name = "Group One's Name" @@ -384,12 +388,12 @@ class TestSecurityAndLibraries( TwillTestCase ): % ( len( group_one.roles ), group_one.id, len( role_ids ) ) ) # Rename the group rename = "Group One's been Renamed" - self.rename_group( str( group_one.id ), name=rename, ) + self.rename_group( self.security.encode_id( group_one.id ), name=rename, ) self.home() self.visit_page( 'admin/groups' ) self.check_page_for_string( rename ) # Reset the group back to the original name - self.rename_group( str( group_one.id ), name=name ) + self.rename_group( self.security.encode_id( group_one.id ), name=name ) def test_055_add_members_and_role_to_group( self ): """Testing editing user membership and role associations of an existing group""" name = 'Group Two' @@ -405,10 +409,12 @@ class TestSecurityAndLibraries( TwillTestCase ): if group_two.roles: raise AssertionError( '%d GroupRoleAssociations were created for group id %d when it was created ( should have been 0 )' \ % ( len( group_two.roles ), group_two.id ) ) - group_two_id = str( group_two.id ) user_ids = [ str( regular_user1.id ) ] role_ids = [ str( role_one.id ) ] - self.associate_users_and_roles_with_group( group_two.id, group_two.name, user_ids=user_ids, role_ids=role_ids ) + self.associate_users_and_roles_with_group( self.security.encode_id( group_two.id ), + group_two.name, + user_ids=user_ids, + role_ids=role_ids ) def test_060_create_role_with_user_and_group_associations( self ): """Testing creating a role with user and group associations""" # NOTE: To get this to work with twill, all select lists on the ~/admin/role page must contain at least @@ -421,7 +427,11 @@ class TestSecurityAndLibraries( TwillTestCase ): group_ids=[ str( group_two.id ) ] private_role=admin_user.email # Create the role - self.create_role( name=name, description=description, in_user_ids=user_ids, in_group_ids=group_ids, private_role=private_role ) + self.create_role( name=name, + description=description, + in_user_ids=user_ids, + in_group_ids=group_ids, + private_role=private_role ) # Get the role object for later tests global role_two role_two = sa_session.query( galaxy.model.Role ).filter( galaxy.model.Role.table.c.name==name ).first() @@ -451,7 +461,11 @@ class TestSecurityAndLibraries( TwillTestCase ): user_ids=[] group_ids=[] private_role=admin_user.email - self.create_role( name=name, description=description, in_user_ids=user_ids, in_group_ids=group_ids, private_role=private_role ) + self.create_role( name=name, + description=description, + in_user_ids=user_ids, + in_group_ids=group_ids, + private_role=private_role ) # Get the role object for later tests global role_three role_three = sa_session.query( galaxy.model.Role ).filter( galaxy.model.Role.table.c.name==name ).first() @@ -466,8 +480,11 @@ class TestSecurityAndLibraries( TwillTestCase ): for uga in admin_user.groups: group_ids.append( str( uga.group_id ) ) check_str = "User '%s' has been updated with %d associated roles and %d associated groups" % ( admin_user.email, len( role_ids ), len( group_ids ) ) - self.associate_roles_and_groups_with_user( self.security.encode_id( admin_user.id ), str( admin_user.email ), - in_role_ids=role_ids, in_group_ids=group_ids, check_str=check_str ) + self.associate_roles_and_groups_with_user( self.security.encode_id( admin_user.id ), + str( admin_user.email ), + in_role_ids=role_ids, + in_group_ids=group_ids, + check_str=check_str ) sa_session.refresh( admin_user ) # admin_user should now be associated with 4 roles: private, role_one, role_two, role_three if len( admin_user.roles ) != 4: @@ -1374,7 +1391,7 @@ class TestSecurityAndLibraries( TwillTestCase ): self.home() self.visit_url( '%s/admin/groups' % self.url ) self.check_page_for_string( group_two.name ) - self.mark_group_deleted( str( group_two.id ), group_two.name ) + self.mark_group_deleted( self.security.encode_id( group_two.id ), group_two.name ) sa_session.refresh( group_two ) if not group_two.deleted: raise AssertionError( '%s was not correctly marked as deleted.' % group_two.name ) @@ -1386,7 +1403,7 @@ class TestSecurityAndLibraries( TwillTestCase ): def test_175_undelete_group( self ): """Testing undeleting a deleted group""" # Logged in as admin_user - self.undelete_group( str( group_two.id ), group_two.name ) + self.undelete_group( self.security.encode_id( group_two.id ), group_two.name ) sa_session.refresh( group_two ) if group_two.deleted: raise AssertionError( '%s was not correctly marked as not deleted.' % group_two.name ) @@ -1396,7 +1413,7 @@ class TestSecurityAndLibraries( TwillTestCase ): self.home() self.visit_url( '%s/admin/roles' % self.url ) self.check_page_for_string( role_two.name ) - self.mark_role_deleted( str( role_two.id ), role_two.name ) + self.mark_role_deleted( self.security.encode_id( role_two.id ), role_two.name ) sa_session.refresh( role_two ) if not role_two.deleted: raise AssertionError( '%s was not correctly marked as deleted.' % role_two.name ) @@ -1408,7 +1425,7 @@ class TestSecurityAndLibraries( TwillTestCase ): def test_185_undelete_role( self ): """Testing undeleting a deleted role""" # Logged in as admin_user - self.undelete_role( str( role_two.id ), role_two.name ) + self.undelete_role( self.security.encode_id( role_two.id ), role_two.name ) def test_190_mark_dataset_deleted( self ): """Testing marking a library dataset as deleted""" # Logged in as admin_user @@ -1541,59 +1558,57 @@ class TestSecurityAndLibraries( TwillTestCase ): def test_235_purge_group( self ): """Testing purging a group""" # Logged in as admin_user - group_id = str( group_two.id ) - self.mark_group_deleted( group_id, group_two.name ) - self.purge_group( group_id, group_two.name ) + self.mark_group_deleted( self.security.encode_id( group_two.id ), group_two.name ) + self.purge_group( self.security.encode_id( group_two.id ), group_two.name ) # Make sure there are no UserGroupAssociations uga = sa_session.query( galaxy.model.UserGroupAssociation ) \ - .filter( galaxy.model.UserGroupAssociation.table.c.group_id == group_id ) \ + .filter( galaxy.model.UserGroupAssociation.table.c.group_id == group_two.id ) \ .first() if uga: - raise AssertionError( "Purging the group did not delete the UserGroupAssociations for group_id '%s'" % group_id ) + raise AssertionError( "Purging the group did not delete the UserGroupAssociations for group_id '%s'" % group_two.id ) # Make sure there are no GroupRoleAssociations gra = sa_session.query( galaxy.model.GroupRoleAssociation ) \ - .filter( galaxy.model.GroupRoleAssociation.table.c.group_id == group_id ) \ + .filter( galaxy.model.GroupRoleAssociation.table.c.group_id == group_two.id ) \ .first() if gra: - raise AssertionError( "Purging the group did not delete the GroupRoleAssociations for group_id '%s'" % group_id ) + raise AssertionError( "Purging the group did not delete the GroupRoleAssociations for group_id '%s'" % group_two.id ) # Undelete the group for later test runs - self.undelete_group( group_id, group_two.name ) + self.undelete_group( self.security.encode_id( group_two.id ), group_two.name ) def test_240_purge_role( self ): """Testing purging a role""" # Logged in as admin_user - role_id = str( role_two.id ) - self.mark_role_deleted( role_id, role_two.name ) - self.purge_role( role_id, role_two.name ) + self.mark_role_deleted( self.security.encode_id( role_two.id ), role_two.name ) + self.purge_role( self.security.encode_id( role_two.id ), role_two.name ) # Make sure there are no UserRoleAssociations uras = sa_session.query( galaxy.model.UserRoleAssociation ) \ - .filter( galaxy.model.UserRoleAssociation.table.c.role_id == role_id ) \ + .filter( galaxy.model.UserRoleAssociation.table.c.role_id == role_two.id ) \ .all() if uras: - raise AssertionError( "Purging the role did not delete the UserRoleAssociations for role_id '%s'" % role_id ) + raise AssertionError( "Purging the role did not delete the UserRoleAssociations for role_id '%s'" % role_two.id ) # Make sure there are no DefaultUserPermissions associated with the Role dups = sa_session.query( galaxy.model.DefaultUserPermissions ) \ - .filter( galaxy.model.DefaultUserPermissions.table.c.role_id == role_id ) \ + .filter( galaxy.model.DefaultUserPermissions.table.c.role_id == role_two.id ) \ .all() if dups: - raise AssertionError( "Purging the role did not delete the DefaultUserPermissions for role_id '%s'" % role_id ) + raise AssertionError( "Purging the role did not delete the DefaultUserPermissions for role_id '%s'" % role_two.id ) # Make sure there are no DefaultHistoryPermissions associated with the Role dhps = sa_session.query( galaxy.model.DefaultHistoryPermissions ) \ - .filter( galaxy.model.DefaultHistoryPermissions.table.c.role_id == role_id ) \ + .filter( galaxy.model.DefaultHistoryPermissions.table.c.role_id == role_two.id ) \ .all() if dhps: - raise AssertionError( "Purging the role did not delete the DefaultHistoryPermissions for role_id '%s'" % role_id ) + raise AssertionError( "Purging the role did not delete the DefaultHistoryPermissions for role_id '%s'" % role_two.id ) # Make sure there are no GroupRoleAssociations gra = sa_session.query( galaxy.model.GroupRoleAssociation ) \ - .filter( galaxy.model.GroupRoleAssociation.table.c.role_id == role_id ) \ + .filter( galaxy.model.GroupRoleAssociation.table.c.role_id == role_two.id ) \ .first() if gra: - raise AssertionError( "Purging the role did not delete the GroupRoleAssociations for role_id '%s'" % role_id ) + raise AssertionError( "Purging the role did not delete the GroupRoleAssociations for role_id '%s'" % role_two.id ) # Make sure there are no DatasetPermissionss dp = sa_session.query( galaxy.model.DatasetPermissions ) \ - .filter( galaxy.model.DatasetPermissions.table.c.role_id == role_id ) \ + .filter( galaxy.model.DatasetPermissions.table.c.role_id == role_two.id ) \ .first() if dp: - raise AssertionError( "Purging the role did not delete the DatasetPermissionss for role_id '%s'" % role_id ) + raise AssertionError( "Purging the role did not delete the DatasetPermissionss for role_id '%s'" % role_two.id ) def test_245_manually_unpurge_role( self ): """Testing manually un-purging a role""" # Logged in as admin_user @@ -1601,7 +1616,7 @@ class TestSecurityAndLibraries( TwillTestCase ): # TODO: If we decide to implement the GUI feature for un-purging a role, replace this with a method call role_two.purged = False role_two.flush() - self.undelete_role( str( role_two.id ), role_two.name ) + self.undelete_role( self.security.encode_id( role_two.id ), role_two.name ) def test_250_purge_library( self ): """Testing purging a library""" # Logged in as admin_user @@ -1815,8 +1830,8 @@ class TestSecurityAndLibraries( TwillTestCase ): # Eliminate all non-private roles ################## for role in [ role_one, role_two, role_three ]: - self.mark_role_deleted( str( role.id ), role.name ) - self.purge_role( str( role.id ), role.name ) + self.mark_role_deleted( self.security.encode_id( role.id ), role.name ) + self.purge_role( self.security.encode_id( role.id ), role.name ) # Manually delete the role from the database sa_session.refresh( role ) sa_session.delete( role ) @@ -1825,8 +1840,8 @@ class TestSecurityAndLibraries( TwillTestCase ): # Eliminate all groups ################## for group in [ group_zero, group_one, group_two ]: - self.mark_group_deleted( str( group.id ), group.name ) - self.purge_group( str( group.id ), group.name ) + self.mark_group_deleted( self.security.encode_id( group.id ), group.name ) + self.purge_group( self.security.encode_id( group.id ), group.name ) # Manually delete the group from the database sa_session.refresh( group ) sa_session.delete( group ) @@ -1846,7 +1861,6 @@ class TestSecurityAndLibraries( TwillTestCase ): # Change DefaultHistoryPermissions for regular_user1 back to the default permissions_in = [ 'DATASET_MANAGE_PERMISSIONS' ] permissions_out = [ 'DATASET_ACCESS' ] - role_id = str( regular_user1_private_role.id ) - self.user_set_default_permissions( permissions_in=permissions_in, permissions_out=permissions_out, role_id=role_id ) + self.user_set_default_permissions( permissions_in=permissions_in, permissions_out=permissions_out, role_id=str( regular_user1_private_role.id ) ) self.logout() self.login( email=admin_user.email ) diff --git a/tool_conf.xml.main b/tool_conf.xml.main index abaf3d994f6..18025ec3926 100644 --- a/tool_conf.xml.main +++ b/tool_conf.xml.main @@ -8,6 +8,7 @@ + @@ -27,6 +28,7 @@ + @@ -34,15 +36,17 @@ +
- + +
@@ -50,6 +54,9 @@ + + +
@@ -80,9 +87,7 @@ -
@@ -90,7 +95,7 @@
- + @@ -147,12 +152,6 @@
-
- - - - -
@@ -262,4 +261,37 @@
+