mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-21 13:50:20 +08:00
Reintroduce roles. Unfinished stuff: setting default user and history
permissions, user-side permissions settings on datasets, viewing associated datasets under the role page in the admin controler (is this even necessary?), filtering out roles by type. I haven't addressed tests, so the security-related functional tests will fail. I haven't looked at history sharing yet either. Cleanup to remove unused methods is needed in the admin controller. And the admin templates are a bit messy.
This commit is contained in:
@@ -103,70 +103,16 @@ class JobToOutputDatasetAssociation( object ):
|
||||
self.name = name
|
||||
self.dataset = dataset
|
||||
|
||||
class GroupDatasetAssociation( object ):
|
||||
def __init__( self, group, dataset, permitted_actions=[] ):
|
||||
if isinstance( group, GroupDatasetAssociation ) or \
|
||||
isinstance( group, DefaultUserGroupAssociation ) or \
|
||||
isinstance( group, DefaultHistoryGroupAssociation ):
|
||||
group = group.group
|
||||
self.group = group
|
||||
if isinstance( dataset, HistoryDatasetAssociation ):
|
||||
dataset = dataset.dataset
|
||||
self.dataset = dataset
|
||||
self.permitted_actions = permitted_actions
|
||||
def add_permitted_action( self, action ):
|
||||
if action not in self.permitted_actions:
|
||||
return self.permitted_actions.append( action )
|
||||
raise 'action (%s) already exists in permitted actions list (%s: %s).' % ( action, str( self.id ), str( self.permitted_actions ) )
|
||||
def remove_permitted_action( self, action ):
|
||||
return self.permitted_actions.remove( action )
|
||||
|
||||
class Group( object ):
|
||||
public_id = None
|
||||
permitted_actions = galaxy.security.get_permitted_actions( 'GROUP' )
|
||||
def __init__( self, name = None, priority = 0 ):
|
||||
def __init__( self, name = None ):
|
||||
self.name = name
|
||||
self.priority = priority
|
||||
@classmethod
|
||||
def get_public_group( cls ):
|
||||
return Group.get( cls.public_id )
|
||||
@classmethod
|
||||
def set_public_group( cls, group ):
|
||||
# We store the id instead of the object, because of alchemy sessions
|
||||
if isinstance( group, Group ):
|
||||
group = group.id
|
||||
cls.public_id = group
|
||||
@classmethod
|
||||
def guess_public_group( cls ):
|
||||
# Retrieve from database and store public group id
|
||||
group = Group.filter_by( name='public' ).first()
|
||||
cls.set_public_group( group )
|
||||
|
||||
class UserGroupAssociation( object ):
|
||||
def __init__( self, user, group ):
|
||||
self.user = user
|
||||
self.group = group
|
||||
|
||||
class DefaultUserGroupAssociation( object ):
|
||||
def __init__( self, user, group, permitted_actions ):
|
||||
if isinstance( group, GroupDatasetAssociation ) or \
|
||||
isinstance( group, DefaultUserGroupAssociation ) or \
|
||||
isinstance( group, DefaultHistoryGroupAssociation ):
|
||||
group = group.group
|
||||
self.user = user
|
||||
self.group = group
|
||||
self.permitted_actions = permitted_actions
|
||||
|
||||
class DefaultHistoryGroupAssociation( object ):
|
||||
def __init__( self, history, group, permitted_actions ):
|
||||
if isinstance( group, GroupDatasetAssociation ) or \
|
||||
isinstance( group, DefaultUserGroupAssociation ) or \
|
||||
isinstance( group, DefaultHistoryGroupAssociation ):
|
||||
group = group.group
|
||||
self.history = history
|
||||
self.group = group
|
||||
self.permitted_actions = permitted_actions
|
||||
|
||||
class History( object ):
|
||||
def __init__( self, id=None, name=None, user=None ):
|
||||
self.id = id
|
||||
@@ -239,6 +185,64 @@ class History( object ):
|
||||
# self.history = history
|
||||
# self.datasets = []
|
||||
|
||||
class UserRoleAssociation( object ):
|
||||
def __init__( self, user, role ):
|
||||
self.user = user
|
||||
self.role = role
|
||||
|
||||
class GroupRoleAssociation( object ):
|
||||
def __init__( self, group, role ):
|
||||
self.group = group
|
||||
self.role = role
|
||||
|
||||
class Role( object ):
|
||||
private_id = None
|
||||
types = Bunch(
|
||||
PRIVATE = 'private',
|
||||
SYSTEM = 'system',
|
||||
USER = 'user',
|
||||
ADMIN = 'admin'
|
||||
)
|
||||
def __init__( self, name="", description="", type="system", deleted=False ):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.type = type
|
||||
self.deleted = deleted
|
||||
|
||||
class ActionObjectRolesAssociation( object ):
|
||||
"""
|
||||
Base class for an action->something->roles association, so set_roles
|
||||
doesn't have to be a member of each class that uses it.
|
||||
"""
|
||||
def set_roles( self, roles ):
|
||||
"""
|
||||
Convenience method to allow roles to be a list of Roles or role ids.
|
||||
"""
|
||||
def get_id( x ):
|
||||
if isinstance( x, Role ):
|
||||
return x.id
|
||||
else:
|
||||
return x
|
||||
self.role_ids = map( get_id, roles )
|
||||
|
||||
class ActionDatasetRolesAssociation( ActionObjectRolesAssociation ):
|
||||
def __init__( self, action, dataset, roles ):
|
||||
self.action = action
|
||||
self.dataset = dataset
|
||||
self.set_roles( roles )
|
||||
|
||||
class DefaultUserPermissions( ActionObjectRolesAssociation ):
|
||||
def __init__( self, user, action, roles ):
|
||||
self.user = user
|
||||
self.action = action
|
||||
self.set_roles( roles )
|
||||
|
||||
class DefaultHistoryPermissions( ActionObjectRolesAssociation ):
|
||||
def __init__( self, history, action, roles ):
|
||||
self.history = history
|
||||
self.action = action
|
||||
self.set_roles( roles )
|
||||
|
||||
class Dataset( object ):
|
||||
states = Bunch( NEW = 'new',
|
||||
QUEUED = 'queued',
|
||||
|
||||
+75
-39
@@ -117,7 +117,6 @@ Group.table = Table( "galaxy_group", metadata,
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "name", TEXT, index=True, unique=True ),
|
||||
Column( "priority", Integer ),
|
||||
Column( "deleted", Boolean, index=True, default=False ) )
|
||||
|
||||
UserGroupAssociation.table = Table( "user_group_association", metadata,
|
||||
@@ -127,32 +126,49 @@ UserGroupAssociation.table = Table( "user_group_association", metadata,
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ) )
|
||||
|
||||
GroupDatasetAssociation.table = Table( "group_dataset_association", metadata,
|
||||
UserRoleAssociation.table = Table( "user_role_association", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "group_id", Integer, ForeignKey( "galaxy_group.id" ), index=True ),
|
||||
Column( "dataset_id", Integer, ForeignKey( "dataset.id" ), index=True ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "permitted_actions", JSONType(), default=[] ) )
|
||||
|
||||
# The following table stores the permissions that are considered the defaults for new histories when they are created by a user
|
||||
DefaultUserGroupAssociation.table = Table( "default_user_group_association", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "group_id", Integer, ForeignKey( "galaxy_group.id" ), index=True ),
|
||||
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
|
||||
Column( "role_id", Integer, ForeignKey( "role.id" ), index=True ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "permitted_actions", JSONType(), default=[] ) )
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ) )
|
||||
|
||||
# The following table stores the default permissions assigned to histories for datasets
|
||||
# that need permissions ( dataset permissions that cannot be determined based on ancestor )
|
||||
DefaultHistoryGroupAssociation.table = Table( "default_history_group_association", metadata,
|
||||
GroupRoleAssociation.table = Table( "group_role_association", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "group_id", Integer, ForeignKey( "galaxy_group.id" ), index=True ),
|
||||
Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ),
|
||||
Column( "role_id", Integer, ForeignKey( "role.id" ), index=True ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ) )
|
||||
|
||||
Role.table = Table( "role", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "permitted_actions", JSONType(), default=[] ) )
|
||||
Column( "name", TEXT, index=True, unique=True ),
|
||||
Column( "description", TEXT ),
|
||||
Column( "type", TEXT, index=True ),
|
||||
Column( "deleted", Boolean, index=True, default=False ) )
|
||||
|
||||
# TODO: should role_ids be made in to another association table?
|
||||
ActionDatasetRolesAssociation.table = Table( "action_dataset_roles_association", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "action", TEXT ),
|
||||
Column( "dataset_id", Integer, ForeignKey( "dataset.id" ), index=True ),
|
||||
Column( "role_ids", JSONType(), default=[] ) )
|
||||
|
||||
DefaultUserPermissions.table = Table( "default_user_permissions", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
|
||||
Column( "action", TEXT ),
|
||||
Column( "role_ids", JSONType(), default=[] ) )
|
||||
|
||||
DefaultHistoryPermissions.table = Table( "default_history_permissions", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ),
|
||||
Column( "action", TEXT ),
|
||||
Column( "role_ids", JSONType(), default=[] ) )
|
||||
|
||||
LibraryFolderDatasetAssociation.table = Table( "library_folder_dataset_association", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
@@ -399,7 +415,7 @@ assign_mapper( context, History, History.table,
|
||||
) )
|
||||
|
||||
assign_mapper( context, User, User.table,
|
||||
properties=dict( histories=relation( History, backref="user",
|
||||
properties=dict( histories=relation( History, backref="user",
|
||||
order_by=desc(History.table.c.update_time) ),
|
||||
active_histories=relation( History, primaryjoin=( ( History.table.c.user_id == User.table.c.id ) & ( not_( History.table.c.deleted ) ) ), order_by=desc( History.table.c.update_time ) ),
|
||||
stored_workflow_menu_entries=relation( StoredWorkflowMenuEntry, backref="user",
|
||||
@@ -408,29 +424,49 @@ assign_mapper( context, User, User.table,
|
||||
) )
|
||||
|
||||
assign_mapper( context, Group, Group.table,
|
||||
properties=dict( users=relation( UserGroupAssociation ),
|
||||
datasets=relation( GroupDatasetAssociation ) ) )
|
||||
properties=dict( users=relation( UserGroupAssociation ) ) )
|
||||
|
||||
assign_mapper( context, UserGroupAssociation, UserGroupAssociation.table,
|
||||
properties=dict( user=relation( User, backref = "groups" ),
|
||||
group=relation( Group, backref = "members" ) ) )
|
||||
|
||||
assign_mapper( context, GroupDatasetAssociation, GroupDatasetAssociation.table,
|
||||
properties=dict( dataset=relation( Dataset, backref = "groups" ),
|
||||
group=relation( Group, backref = "group_datasets" ) ) )
|
||||
assign_mapper( context, DefaultUserPermissions, DefaultUserPermissions.table,
|
||||
properties=dict( user=relation( User, backref = "default_permissions" ) ) )
|
||||
|
||||
assign_mapper( context, DefaultUserGroupAssociation, DefaultUserGroupAssociation.table,
|
||||
properties=dict( user=relation( User, backref = "default_groups" ),
|
||||
group=relation( Group ) ) )
|
||||
assign_mapper( context, DefaultHistoryPermissions, DefaultHistoryPermissions.table,
|
||||
properties=dict( history=relation( History, backref = "default_permissions" ) ) )
|
||||
|
||||
assign_mapper( context, DefaultHistoryGroupAssociation, DefaultHistoryGroupAssociation.table,
|
||||
properties=dict( history=relation( History, backref = "default_groups" ),
|
||||
group=relation( Group ) ) )
|
||||
assign_mapper( context, Role, Role.table,
|
||||
properties=dict(
|
||||
users=relation( UserRoleAssociation ),
|
||||
groups=relation( GroupRoleAssociation )
|
||||
)
|
||||
)
|
||||
|
||||
assign_mapper( context, UserRoleAssociation, UserRoleAssociation.table,
|
||||
properties=dict(
|
||||
user=relation( User, backref="roles" ),
|
||||
role=relation( Role )
|
||||
)
|
||||
)
|
||||
|
||||
assign_mapper( context, GroupRoleAssociation, GroupRoleAssociation.table,
|
||||
properties=dict(
|
||||
group=relation( Group, backref="roles" ),
|
||||
role=relation( Role )
|
||||
)
|
||||
)
|
||||
|
||||
assign_mapper( context, ActionDatasetRolesAssociation, ActionDatasetRolesAssociation.table,
|
||||
properties=dict(
|
||||
dataset=relation( Dataset, backref="actions" )
|
||||
)
|
||||
)
|
||||
|
||||
assign_mapper( context, Library, Library.table,
|
||||
properties=dict(
|
||||
root_folder=relation( LibraryFolder,
|
||||
backref = backref( "library_root" ) )
|
||||
backref=backref( "library_root" ) )
|
||||
) )
|
||||
|
||||
assign_mapper( context, LibraryFolder, LibraryFolder.table,
|
||||
@@ -605,13 +641,13 @@ def init( file_path, url, engine_options={}, create_tables=False ):
|
||||
result.create_tables = create_tables
|
||||
#load local galaxy security policy
|
||||
result.security_agent = GalaxyRBACAgent( result )
|
||||
# Ensure group named 'public' exists
|
||||
public_group = result.Group.filter_by( name='public' ).first()
|
||||
if not public_group:
|
||||
public_group = result.security_agent.create_group( name = 'public' )
|
||||
# Store public group id
|
||||
result.security_agent.set_public_group( public_group )
|
||||
log.debug( "Public Group identified as id = %s." % ( public_group.id ) )
|
||||
# Create private roles if necessary.
|
||||
if not len( result.Role.select() ):
|
||||
for user in result.User.select():
|
||||
role = Role( name = user.email, description = 'Private Role for ' + user.email, type = 'private' )
|
||||
role.flush()
|
||||
ura = UserRoleAssociation( user = user, role = role )
|
||||
ura.flush()
|
||||
return result
|
||||
|
||||
def get_suite():
|
||||
|
||||
+216
-198
@@ -7,52 +7,55 @@ from galaxy.util.bunch import Bunch
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class Action( object ):
|
||||
def __init__( self, action, description, model ):
|
||||
self.action = action
|
||||
self.description = description
|
||||
self.model = model
|
||||
|
||||
class RBACAgent:
|
||||
"""Class that handles galaxy security"""
|
||||
permitted_actions = Bunch(
|
||||
# The ability to edit the metadata of the associated dataset
|
||||
DATASET_EDIT_METADATA = 'edit metadata',
|
||||
# The ability to change the permissions of a dataset (so specifically, to add and modify
|
||||
# group_dataset_association rows where the dataset is the dataset for which the permission is set).
|
||||
DATASET_MANAGE_PERMISSIONS = 'manage permissions',
|
||||
# The ability to perform any read only operation on the dataset (view, display at external site,
|
||||
# use in a job, etc).
|
||||
DATASET_ACCESS = 'access'
|
||||
)
|
||||
permitted_action_descriptions = Bunch(
|
||||
DATASET_EDIT_METADATA = "User can edit this dataset's metadata in the library",
|
||||
DATASET_MANAGE_PERMISSIONS = "User can manage the groups and group permitted actions associated with this dataset",
|
||||
DATASET_ACCESS = "User can import this dataset into their history for analysis"
|
||||
DATASET_EDIT_METADATA = Action(
|
||||
"edit metadata", "Role members can edit this dataset's metadata in the library", "grant" ),
|
||||
DATASET_MANAGE_PERMISSIONS = Action(
|
||||
"manage permissions", "Role members can manage the groups and group permitted actions associated with this dataset", "grant" ),
|
||||
DATASET_ACCESS = Action(
|
||||
"access", "Role members can import this dataset into their history for analysis", "restrict" )
|
||||
)
|
||||
def get_action( self, name, default=None ):
|
||||
"""
|
||||
Get a permitted action by its dict key or action name
|
||||
"""
|
||||
for k, v in self.permitted_actions.items():
|
||||
if k == name or v.action == name:
|
||||
return v
|
||||
return default
|
||||
def get_actions( self ):
|
||||
"""
|
||||
Get all permitted actions as a list
|
||||
"""
|
||||
return self.permitted_actions.__dict__.values()
|
||||
def allow_action( self, user, action, **kwd ):
|
||||
raise 'No valid method of checking action (%s) on %s for user %s.' % ( action, kwd, user )
|
||||
def guess_derived_permissions_for_datasets( self, datasets = [] ):
|
||||
raise "Unimplemented Method"
|
||||
def associate_components( self, **kwd ):
|
||||
raise 'No valid method of associating provided components: %s' % kwd
|
||||
def get_group( self, id ):
|
||||
raise 'No valid method of retrieving group %s' % ( id )
|
||||
def create_group( self, **kwd ):
|
||||
raise 'No valid method of creating group with %s' % ( kwd )
|
||||
def create_private_user_group( self, user ):
|
||||
def create_private_user_role( self, user ):
|
||||
raise "Unimplemented Method"
|
||||
def user_set_default_access( self, user, permissions = None, history = False, dataset = False ):
|
||||
def get_private_user_role( self, user ):
|
||||
raise "Unimplemented Method"
|
||||
def user_set_default_permissions( self, user, permissions = None, history = False, dataset = False ):
|
||||
raise "Unimplemented Method"
|
||||
def setup_new_user( self, user ):
|
||||
self.user_set_default_access( user, history = True, dataset = True )
|
||||
self.associate_components( user=user, group=self.get_public_group() )
|
||||
def history_set_default_access( self, history, permissions=None, dataset=False ):
|
||||
raise "Unimplemented Method"
|
||||
def set_public_group( self, group ):
|
||||
raise "Unimplemented Method"
|
||||
def get_public_group( self ):
|
||||
raise "Unimplemented Method"
|
||||
def guess_public_group( self ):
|
||||
self.create_private_user_role( user )
|
||||
self.user_set_default_permissions( user, history = True, dataset = True )
|
||||
#self.associate_components( user=user, group=self.get_public_group() )
|
||||
def history_set_default_permissions( self, history, permissions=None, dataset=False, bypass_manage_permission=False ):
|
||||
raise "Unimplemented Method"
|
||||
def set_dataset_permissions( self, dataset, permissions ):
|
||||
raise "Unimplemented Method"
|
||||
def set_dataset_permitted_actions( self, dataset ):
|
||||
raise "Unimplemented Method"
|
||||
def get_component_associations( self, **kwd ):
|
||||
raise "Unimplemented Method"
|
||||
def components_are_associated( self, **kwd ):
|
||||
@@ -63,18 +66,6 @@ class RBACAgent:
|
||||
form, ensure that they match our actual permitted actions.
|
||||
"""
|
||||
return filter( lambda x: x is not None, [ self.permitted_actions.get( action_string ) for action_string in permitted_action_strings ] )
|
||||
def get_permitted_action_description( self, permitted_action ):
|
||||
"""
|
||||
Return the description of a permitted_action, regardless of
|
||||
whether permitted_action is a key or value.
|
||||
"""
|
||||
if self.permitted_action_descriptions.get( permitted_action ) is not None:
|
||||
return self.permitted_action_descriptions.get( permitted_action )
|
||||
else:
|
||||
for k, v in self.permitted_actions.items():
|
||||
if v == permitted_action:
|
||||
return self.permitted_action_descriptions.get( k )
|
||||
return permitted_action # so at least something useful is printable
|
||||
|
||||
class GalaxyRBACAgent( RBACAgent ):
|
||||
def __init__( self, model, permitted_actions=None ):
|
||||
@@ -89,184 +80,212 @@ class GalaxyRBACAgent( RBACAgent ):
|
||||
"""Returns true when user has permission to perform an action"""
|
||||
if not isinstance( dataset, self.model.Dataset ):
|
||||
dataset = dataset.dataset
|
||||
if user is None:
|
||||
try:
|
||||
public_assoc = [ gda for gda in dataset.groups if gda.group == self.get_public_group() ][0]
|
||||
except:
|
||||
# There'll be an IndexError if the dataset doesn't have a gda with public
|
||||
return False
|
||||
if action in public_assoc.permitted_actions:
|
||||
return True
|
||||
elif user is not None:
|
||||
# Loop through permitted_actions and if allowed return true:
|
||||
# Check permitted_actions associated with dataset through groups
|
||||
for group_dataset_assoc in dataset.groups:
|
||||
if self.components_are_associated( user = user, group = group_dataset_assoc.group ):
|
||||
if action in group_dataset_assoc.permitted_actions:
|
||||
return True
|
||||
return False # No user and dataset not in public group, or user lacks permission
|
||||
if not user:
|
||||
if action == self.permitted_actions.DATASET_ACCESS and action.action not in [ adra.action for adra in dataset.actions ]:
|
||||
return True # anons only get access, and only if there are no roles required for the access action
|
||||
# other actions (or if the dataset has roles defined for the access action) fall through to the false below
|
||||
elif action.action not in [ adra.action for adra in dataset.actions ]:
|
||||
if action.model == 'restrict':
|
||||
return True # implicit access to restrict-style actions if the dataset does not have the action
|
||||
# grant-style actions fall through to the false below
|
||||
else:
|
||||
# collect a user's roles and their groups' roles
|
||||
user_roles = [ ura.role for ura in user.roles ]
|
||||
for group in [ uga.group for uga in user.groups ]:
|
||||
for role in [ gra.role for gra in group.roles ]:
|
||||
if role not in user_roles:
|
||||
user_roles.append( role )
|
||||
user_role_ids = sorted( [ r.id for r in user_roles ] )
|
||||
for adra in dataset.actions:
|
||||
if action.action != adra.action:
|
||||
continue
|
||||
# the filter() returns a list of the dataset's role ids
|
||||
# of which the user is not a member. so an empty list
|
||||
# means the user has all of the required roles.
|
||||
if not filter( lambda x: x not in user_role_ids, adra.role_ids ):
|
||||
return True # user has all of the roles required to perform the action
|
||||
break # fall through to the false. user is missing at least one required role
|
||||
return False # default is to reject
|
||||
def guess_derived_permissions_for_datasets( self, datasets=[] ):
|
||||
"""Returns a list of group/action tuples for the output dataset based upon provided datasets"""
|
||||
intersect = None
|
||||
priority_access_perms = None
|
||||
"""Returns a dict of { action : [ role, role, ... ] } for the output dataset based upon provided datasets"""
|
||||
perms = {}
|
||||
for dataset in datasets:
|
||||
# Determine access groups for output datasets - these groups are the
|
||||
# intersection across all inputs. If we end up with no intersection
|
||||
# between inputs, then we rely on priorities
|
||||
if isinstance( dataset, self.model.HistoryDatasetAssociation ):
|
||||
if not isinstance( dataset, self.model.Dataset ):
|
||||
dataset = dataset.dataset
|
||||
assocs = [ assoc for assoc in dataset.groups ]
|
||||
for assoc in assocs:
|
||||
if priority_access_perms is None or priority_access_perms[0].priority < assoc.group.priority:
|
||||
priority_access_perms = ( assoc.group, assoc.permitted_actions )
|
||||
if intersect is None:
|
||||
intersect = [ (a.group, a.permitted_actions) for a in assocs ]
|
||||
else:
|
||||
# Intersect existing perms with new perms
|
||||
#access_assocs = filter( lambda x: x.group in [ a.group for a in access_assocs ], assocs )
|
||||
new_intersect = []
|
||||
for group, actions in intersect:
|
||||
matches = filter( lambda x: x.group == group, assocs )
|
||||
# Could a dataset ever have more than one GDA with the same group id?
|
||||
if len( matches ) > 1:
|
||||
log.error( "Unable to derive permissions, duplicate group_dataset_association rows exist for group %d, dataset %d" % (group.id, dataset.id) )
|
||||
elif len( matches ) == 1:
|
||||
# compare permitted_actions
|
||||
pa_intersect = filter( lambda x: x in actions, matches[0].permitted_actions )
|
||||
new_intersect.append( ( group, pa_intersect ) )
|
||||
intersect = new_intersect
|
||||
# If we have no groups left after intersection, take the highest priority group
|
||||
if not intersect:
|
||||
if priority_access_perms:
|
||||
intersect = [ priority_access_perms ]
|
||||
return intersect
|
||||
def get_group( self, id ):
|
||||
return self.model.Group.get( id )
|
||||
raise 'No valid method of retrieving requested group by id %s' % ( str( id ) )
|
||||
def get_group_by_name( self, name ):
|
||||
return self.model.Group.filter_by( name=name ).first()
|
||||
raise 'No valid method of retrieving requested group by name %s' % ( str( name ) )
|
||||
def create_group( self, **kwd ):
|
||||
rval = self.model.Group( **kwd )
|
||||
rval.flush()
|
||||
return rval
|
||||
raise 'No valid method of creating group with %s' % ( kwd )
|
||||
these_perms = {}
|
||||
# initialize blank perms
|
||||
for a in self.get_actions():
|
||||
these_perms[ a.action ] = []
|
||||
# collect this dataset's perms
|
||||
for adra in dataset.actions:
|
||||
these_perms[ adra.action ] = adra.role_ids
|
||||
# join or intersect this dataset's permissions with others
|
||||
for action_name, role_ids in these_perms.items():
|
||||
if action_name not in perms.keys():
|
||||
perms[ action_name ] = role_ids
|
||||
else:
|
||||
if self.get_action( action_name ).model == 'grant':
|
||||
# intersect existing roles with new roles
|
||||
perms[ action_name ] = filter( lambda x: x in perms[ action_name ], role_ids )
|
||||
elif self.get_action( action_name ).model == 'restrict':
|
||||
# join existing roles with new roles
|
||||
perms[ action_name ].extend( filter( lambda x: x not in perms[ action_name ], role_ids ) )
|
||||
##perms = [ ( k, tuple( v ) ) for k, v in perms.items() ] # a list of ( action, ( role_id, role_id, ... ) ) tuples
|
||||
return perms
|
||||
def associate_components( self, **kwd ):
|
||||
assert len( kwd ) == 2, 'You must specify exactly 2 Galaxy security components to associate.'
|
||||
if 'dataset' in kwd:
|
||||
if 'group' in kwd:
|
||||
return self.associate_group_dataset( kwd['group'], kwd['dataset'] )
|
||||
elif 'permissions' in kwd:
|
||||
return self.associate_group_dataset( kwd['permissions'][0], kwd['dataset'], kwd['permissions'][1] )
|
||||
elif 'user' in kwd:
|
||||
##assert len( kwd ) == 2, 'You must specify exactly 2 Galaxy security components to associate.'
|
||||
if 'user' in kwd:
|
||||
if 'group' in kwd:
|
||||
return self.associate_user_group( kwd['user'], kwd['group'] )
|
||||
elif 'role' in kwd:
|
||||
return self.associate_user_role( kwd['user'], kwd['role'] )
|
||||
elif 'role' in kwd:
|
||||
if 'group' in kwd:
|
||||
return self.associate_group_role( kwd['group'], kwd['role'] )
|
||||
if 'action' in kwd:
|
||||
if 'dataset' in kwd and 'roles' in kwd:
|
||||
return self.associate_action_dataset_roles( kwd['action'], kwd['dataset'], kwd['roles'] )
|
||||
raise 'No valid method of associating provided components: %s' % kwd
|
||||
def associate_group_dataset( self, group, dataset, permitted_actions=[ RBACAgent.permitted_actions.DATASET_ACCESS ] ):
|
||||
# HACK: The default permitted_actions should really not be used... need to find cases where this is done and correct it
|
||||
assoc = self.model.GroupDatasetAssociation( group, dataset, permitted_actions )
|
||||
assoc.flush()
|
||||
return assoc
|
||||
def associate_user_group( self, user, group ):
|
||||
assoc = self.model.UserGroupAssociation( user, group )
|
||||
assoc.flush()
|
||||
return assoc
|
||||
def create_private_user_group( self, user ):
|
||||
# Create private group
|
||||
group_name = "%s private group" % user.email
|
||||
group = self.model.Group( name=group_name, priority=10 )
|
||||
group.flush()
|
||||
# Add user to group
|
||||
self.associate_components( group=group, user=user )
|
||||
group.flush()
|
||||
return group
|
||||
def user_set_default_access( self, user, permissions = None, history = False, dataset = False ):
|
||||
if permissions is None:
|
||||
permissions = [ ( self.create_private_user_group( user ), self.permitted_actions.__dict__.values() ) ]
|
||||
if permissions is not None:
|
||||
# Delete all of the previous DefaultUserGroupAssociation
|
||||
for duga in user.default_groups: #this is the association not the actual group
|
||||
duga.delete()
|
||||
duga.flush()
|
||||
# Add the new DefaultUserGroupAssociation
|
||||
for group, permitted_actions in permissions:
|
||||
duga = self.model.DefaultUserGroupAssociation( user, group, permitted_actions )
|
||||
duga.flush()
|
||||
def associate_user_role( self, user, role ):
|
||||
assoc = self.model.UserRoleAssociation( user, role )
|
||||
assoc.flush()
|
||||
return assoc
|
||||
def associate_group_role( self, group, role ):
|
||||
assoc = self.model.GroupRoleAssociation( group, role )
|
||||
assoc.flush()
|
||||
return assoc
|
||||
def associate_action_dataset_roles( self, action, dataset, roles ):
|
||||
assoc = self.model.ActionDatasetRolesAssociation( action, dataset, roles )
|
||||
assoc.flush()
|
||||
return assoc
|
||||
def create_private_user_role( self, user ):
|
||||
# Create private role
|
||||
role = self.model.Role( name=user.email, description='Private Role for ' + user.email, type=self.model.Role.types.PRIVATE )
|
||||
role.flush()
|
||||
# Add user to role
|
||||
self.associate_components( role=role, user=user )
|
||||
return role
|
||||
def get_private_user_role( self, user, auto_create=False ):
|
||||
role = self.model.Role.get_by( name=user.email, type=self.model.Role.types.PRIVATE )
|
||||
if not role:
|
||||
if auto_create:
|
||||
return self.create_private_user_role( user )
|
||||
else:
|
||||
return None
|
||||
def user_set_default_permissions( self, user, permissions = {}, history = False, dataset = False ):
|
||||
if user is None:
|
||||
return None
|
||||
if not permissions:
|
||||
permissions = { self.permitted_actions.DATASET_MANAGE_PERMISSIONS : [ self.get_private_user_role( user, auto_create=True ) ] }
|
||||
# Delete all of the previous defaults
|
||||
for dup in user.default_permissions:
|
||||
dup.delete()
|
||||
dup.flush()
|
||||
# Add the new defaults (if any)
|
||||
for action, roles in permissions.items():
|
||||
if isinstance( action, Action ):
|
||||
action = action.action
|
||||
dup = self.model.DefaultUserPermissions( user, action, roles )
|
||||
dup.flush()
|
||||
if history:
|
||||
for history in user.active_histories:
|
||||
self.history_set_default_access( history, permissions=permissions, dataset=dataset )
|
||||
def user_get_default_access( self, user ):
|
||||
return [ ( duga.group, duga.permitted_actions ) for duga in user.default_groups ]
|
||||
def history_set_default_access( self, history, permissions=None, dataset=False ):
|
||||
if permissions is None:
|
||||
if history.user:
|
||||
permissions = self.user_get_default_access( history.user )
|
||||
else:
|
||||
permissions = [ ( self.get_public_group(), self.permitted_actions.__dict__.values() ) ]
|
||||
if permissions is not None:
|
||||
# Delete all of the previous DefaultHistoryGroupAssociations
|
||||
for dhga in history.default_groups: #this is the association not the actual group
|
||||
dhga.delete()
|
||||
dhga.flush()
|
||||
# Add the new DefaultHistoryGroupAssociations
|
||||
for group, permitted_actions in permissions:
|
||||
dhga = self.model.DefaultHistoryGroupAssociation( history, group, permitted_actions )
|
||||
dhga.flush()
|
||||
self.history_set_default_permissions( history, permissions=permissions, dataset=dataset )
|
||||
def user_get_default_permissions( self, user ):
|
||||
perms = {}
|
||||
for dup in user.default_permissions:
|
||||
perms[ dup.action ] = dup.role_ids
|
||||
return perms
|
||||
def history_set_default_permissions( self, history, permissions = {}, dataset = False, bypass_manage_permission = False ):
|
||||
if not history.user:
|
||||
return None # default permissions on a userless history are none
|
||||
if not permissions:
|
||||
permissions = self.user_get_default_permissions( history.user )
|
||||
for dhp in history.default_permissions:
|
||||
dhp.delete()
|
||||
dhp.flush()
|
||||
for action, roles in permissions.items():
|
||||
if isinstance( action, Action ):
|
||||
action = action.action
|
||||
dhp = self.model.DefaultHistoryPermissions( history, action, roles )
|
||||
dhp.flush()
|
||||
if dataset:
|
||||
for hda in history.datasets:
|
||||
for hda2 in hda.dataset.history_associations:
|
||||
if history.user and hda2.history not in history.user.active_histories:
|
||||
# This will occur when a user logs in and has datasets in their previously-public history.
|
||||
self.set_dataset_permissions( hda.dataset, [ ( self.get_public_group(), [ self.permitted_actions.DATASET_ACCESS ] ) ] )
|
||||
#break
|
||||
for hda_in_history in history.datasets:
|
||||
if len( hda_in_history.dataset.library_associations ):
|
||||
continue # dataset has a library association, don't change the permissions
|
||||
if len( [ hda for hda in hda_in_history.dataset.history_associations if hda.history not in history.user.histories ] ):
|
||||
continue # dataset has a history association in a history the user doesn't own, don't change the permissions
|
||||
# bypass is used to change permissions of datasets in a userless history when logging in
|
||||
if bypass_manage_permission or self.allow_action( history.user, self.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=hda_in_history.dataset ):
|
||||
self.set_dataset_permissions( hda_in_history.dataset, permissions )
|
||||
def history_get_default_permissions( self, history ):
|
||||
perms = {}
|
||||
for dhp in history.default_permissions:
|
||||
perms[ dhp.action ] = dhp.role_ids
|
||||
return perms
|
||||
def set_dataset_permissions( self, dataset, permissions={} ):
|
||||
# to delete permission on an action, pass in a blank list of role ids with that action
|
||||
for action, role_ids in permissions.items():
|
||||
if isinstance( action, Action ):
|
||||
action = action.action
|
||||
for adra in dataset.actions:
|
||||
if adra.action != action:
|
||||
continue
|
||||
if not role_ids:
|
||||
adra.delete()
|
||||
else:
|
||||
# At this point, we will have already created a gda for the public group and delete_assocs
|
||||
# is set to False in order to preserve it.
|
||||
if self.allow_action( history.user, self.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=hda.dataset ):
|
||||
self.set_dataset_permissions( hda.dataset, permissions, delete_existing_assocs=False )
|
||||
def history_get_default_access( self, history ):
|
||||
return [ ( dhga.group, dhga.permitted_actions ) for dhga in history.default_groups ]
|
||||
def get_public_group( self ):
|
||||
return self.model.Group.get_public_group()
|
||||
def set_public_group( self, group ):
|
||||
return self.model.Group.set_public_group( group )
|
||||
def guess_public_group( self ):
|
||||
return self.model.Group.guess_public_group()
|
||||
def set_dataset_permissions( self, dataset, permissions, delete_existing_assocs=True ):
|
||||
"""
|
||||
Apply permissions (a list of (group, permitted_action) tuples)
|
||||
to a dataset, removing any existing permissions. permissions can
|
||||
also be a list of GroupDatasetAssociations (for simplicity).
|
||||
"""
|
||||
if isinstance( dataset, self.model.HistoryDatasetAssociation ):
|
||||
dataset = dataset.dataset
|
||||
if delete_existing_assocs:
|
||||
for gda in dataset.groups:
|
||||
gda.delete()
|
||||
gda.flush()
|
||||
if permissions and isinstance( permissions[0], self.model.GroupDatasetAssociation ):
|
||||
permissions = [ ( gda.group, gda.permitted_actions ) for gda in permissions ]
|
||||
for ptuple in permissions:
|
||||
self.associate_components( dataset=dataset, permissions=ptuple )
|
||||
def get_dataset_permissions( self, dataset, group_id=None ):
|
||||
adra.set_roles( role_ids )
|
||||
adra.flush()
|
||||
break
|
||||
else:
|
||||
if role_ids:
|
||||
self.associate_components( action=action, dataset=dataset, roles=role_ids )
|
||||
def get_dataset_permissions( self, dataset ):
|
||||
if not isinstance( dataset, self.model.Dataset ):
|
||||
dataset = dataset.dataset
|
||||
if group_id is not None:
|
||||
return [ ( gda.group, gda.permitted_actions ) for gda in dataset.groups if gda.group_id == int(group_id) ][0]
|
||||
else:
|
||||
return [ ( gda.group, gda.permitted_actions ) for gda in dataset.groups ]
|
||||
perms = {}
|
||||
for k, v in self.model.Dataset.permitted_actions.items():
|
||||
for adra in dataset.actions:
|
||||
if adra.action != v.action:
|
||||
continue
|
||||
perms[ v.action ] = adra.role_ids
|
||||
break
|
||||
else:
|
||||
perms[ v.action ] = []
|
||||
return perms
|
||||
def copy_dataset_permissions( self, src, dst ):
|
||||
if not isinstance( src, self.model.Dataset ):
|
||||
src = src.dataset
|
||||
if not isinstance( dst, self.model.Dataset ):
|
||||
dst = dst.dataset
|
||||
self.set_dataset_permissions( dst, self.get_dataset_permissions( src ) )
|
||||
def set_entity_role_associations( self, roles=[], users=[], groups=[], delete_existing_assocs=True ):
|
||||
for role in roles:
|
||||
if delete_existing_assocs:
|
||||
for a in role.users + role.groups:
|
||||
a.delete()
|
||||
a.flush()
|
||||
for user in users:
|
||||
self.associate_components( user=user, role=role )
|
||||
for group in groups:
|
||||
self.associate_components( group=group, role=role )
|
||||
def get_component_associations( self, **kwd ):
|
||||
# TODO, Nate: Make sure this method is functionally correct.
|
||||
assert len( kwd ) == 2, 'You must specify exactly 2 Galaxy security components to check for associations.'
|
||||
if 'dataset' in kwd:
|
||||
if 'group' in kwd:
|
||||
return self.model.GroupDatasetAssociation.filter_by( group_id=kwd['group'].id, dataset_id=kwd['dataset'].id ).first()
|
||||
if 'action' in kwd:
|
||||
return self.model.ActionDatasetRolesAssociation.filter_by( action = kwd['action'].action, dataset_id = kwd['dataset'].id ).first()
|
||||
elif 'user' in kwd:
|
||||
if 'group' in kwd:
|
||||
return self.model.UserGroupAssociation.filter_by( group_id=kwd['group'].id, user_id=kwd['user'].id ).first()
|
||||
return self.model.UserGroupAssociation.filter_by( group_id = kwd['group'].id, user_id = kwd['user'].id ).first()
|
||||
elif 'role' in kwd:
|
||||
return self.model.UserRoleAssociation.filter_by( role_id = kwd['role'].id, user_id = kwd['user'].id ).first()
|
||||
elif 'group' in kwd:
|
||||
if 'role' in kwd:
|
||||
return self.model.GroupRoleAssociation.filter_by( role_id = kwd['role'].id, group_id = kwd['group'].id ).first()
|
||||
raise 'No valid method of associating provided components: %s' % kwd
|
||||
def dataset_has_group( self, dataset_id, group_id ):
|
||||
return bool( self.model.GroupDatasetAssociation.filter_by( group_id=group_id, dataset_id=dataset_id ).first() )
|
||||
def check_folder_contents( self, user, entry ):
|
||||
"""
|
||||
Return true if there are any datasets under 'folder' that the
|
||||
@@ -288,7 +307,6 @@ class GalaxyRBACAgent( RBACAgent ):
|
||||
else:
|
||||
raise 'Passed an illegal object to check_folder_contents: %s' % type( entry )
|
||||
|
||||
|
||||
def get_permitted_actions( self, filter=None ):
|
||||
'''Utility method to return a subset of RBACAgent's permitted actions'''
|
||||
if filter is None:
|
||||
|
||||
@@ -1202,7 +1202,7 @@ class Tool:
|
||||
else: visible = False
|
||||
ext = fields.pop(0).lower()
|
||||
child_dataset = self.app.model.HistoryDatasetAssociation( extension=ext, parent_id=outdata.id, designation=designation, visible=visible, dbkey=outdata.dbkey, create_dataset=True )
|
||||
self.app.security_agent.set_dataset_permissions( child_dataset.dataset, outdata.dataset.groups )
|
||||
self.app.security_agent.copy_dataset_permissions( outdata.dataset, child_dataset.dataset )
|
||||
# Move data from temp location to dataset location
|
||||
shutil.move( filename, child_dataset.file_name )
|
||||
child_dataset.flush()
|
||||
@@ -1239,7 +1239,7 @@ class Tool:
|
||||
ext = fields.pop(0).lower()
|
||||
# Create new primary dataset
|
||||
primary_data = self.app.model.HistoryDatasetAssociation( extension=ext, designation=designation, visible=visible, dbkey=outdata.dbkey, create_dataset=True )
|
||||
self.app.security_agent.set_dataset_permissions( primary_data.dataset, outdata.dataset.groups )
|
||||
self.app.security_agent.copy_dataset_permissions( outdata.dataset, primary_data.dataset )
|
||||
primary_data.flush()
|
||||
# Move data from temp location to dataset location
|
||||
shutil.move( filename, primary_data.file_name )
|
||||
|
||||
@@ -84,13 +84,13 @@ class DefaultToolAction( object ):
|
||||
if data.dbkey not in [None, '?']:
|
||||
input_dbkey = data.dbkey
|
||||
|
||||
# Determine output dataset permitted_actions list
|
||||
# Determine output dataset permission/roles list
|
||||
existing_datasets = [ inp for inp in inp_data.values() if inp ]
|
||||
if existing_datasets:
|
||||
output_permissions = trans.app.security_agent.guess_derived_permissions_for_datasets( existing_datasets )
|
||||
else:
|
||||
# No valid inputs, we will use history defaults
|
||||
output_permissions = trans.app.security_agent.history_get_default_access( trans.history )
|
||||
output_permissions = trans.app.security_agent.history_get_default_permissions( trans.history )
|
||||
# Build name for output datasets based on tool name and input names
|
||||
if len( input_names ) == 1:
|
||||
on_text = input_names[0]
|
||||
|
||||
@@ -78,7 +78,7 @@ class UploadToolAction( object ):
|
||||
|
||||
def upload_empty(self, trans, err_code, err_msg):
|
||||
data = trans.app.model.HistoryDatasetAssociation( create_dataset=True )
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, trans.app.security_agent.history_get_default_access( trans.history ) )
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, trans.app.security_agent.history_get_default_permissions( trans.history ) )
|
||||
data.name = err_code
|
||||
data.extension = "txt"
|
||||
data.dbkey = "?"
|
||||
@@ -172,7 +172,7 @@ class UploadToolAction( object ):
|
||||
info = 'uploaded %s file' %data_type
|
||||
|
||||
data = trans.app.model.HistoryDatasetAssociation( history = trans.history, extension = ext, create_dataset = True )
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, trans.app.security_agent.history_get_default_access( trans.history ) )
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, trans.app.security_agent.history_get_default_permissions( trans.history ) )
|
||||
data.name = file_name
|
||||
data.dbkey = dbkey
|
||||
data.info = info
|
||||
|
||||
@@ -984,38 +984,6 @@ class DataToolParameter( ToolParameter ):
|
||||
|
||||
TODO: The following must be fixed to test correctly for the new security_check tag in the DataToolParameter ( the last test below is broken )
|
||||
Nate's next passs at the dataset security stuff will dramatically alter this anyway.
|
||||
|
||||
>>> # Mock up a history (not connected to database)
|
||||
>>> from galaxy.model import History, HistoryDatasetAssociation, User, Group
|
||||
>>> from galaxy.util.bunch import Bunch
|
||||
>>> from galaxy.security import GalaxyRBACAgent
|
||||
>>> import galaxy.model
|
||||
>>> security_agent = GalaxyRBACAgent( galaxy.model )
|
||||
>>> hist = History()
|
||||
>>> hist.flush()
|
||||
>>> group = Group( 'test' )
|
||||
>>> group.flush()
|
||||
>>> Group.public_id = group.id
|
||||
>>> dataset1 = HistoryDatasetAssociation( id=1, extension='txt', create_dataset=True )
|
||||
>>> dataset2 = HistoryDatasetAssociation( id=2, extension='bed', create_dataset=True )
|
||||
>>> security_agent.set_dataset_permissions( dataset2, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
|
||||
>>> dataset3 = HistoryDatasetAssociation( id=3, extension='fasta', create_dataset=True )
|
||||
>>> dataset4 = HistoryDatasetAssociation( id=4, extension='png', create_dataset=True )
|
||||
>>> dataset5 = HistoryDatasetAssociation( id=5, extension='interval', create_dataset=True )
|
||||
>>> security_agent.set_dataset_permissions( dataset5, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
|
||||
>>> hist.add_dataset( dataset1 )
|
||||
>>> hist.add_dataset( dataset2 )
|
||||
>>> hist.add_dataset( dataset3 )
|
||||
>>> hist.add_dataset( dataset4 )
|
||||
>>> hist.add_dataset( dataset5 )
|
||||
>>> p = DataToolParameter( None, XML( '<param name="blah" type="data" format="txt"><security_check group="test" action="access"/></param>' ) )
|
||||
>>> print p.name
|
||||
blah
|
||||
>>> print p.security_dict
|
||||
{'test': ['access']}
|
||||
>>> print p.get_html( trans=Bunch( history=hist, user=None, app=Bunch( security_agent = security_agent ) ) )
|
||||
<select name="blah">
|
||||
</select>
|
||||
"""
|
||||
|
||||
def __init__( self, tool, elem ):
|
||||
@@ -1077,6 +1045,7 @@ class DataToolParameter( ToolParameter ):
|
||||
hid = "%s.%d" % ( parent_hid, i + 1 )
|
||||
else:
|
||||
hid = str( hda.hid )
|
||||
# FIXME: This needs to be rewritten to use the new permissions model
|
||||
if not hda.dataset.state in [galaxy.model.Dataset.states.ERROR, galaxy.model.Dataset.states.DISCARDED] and hda.visible and trans.app.security_agent.allow_action( trans.user, hda.permitted_actions.DATASET_ACCESS, dataset=hda ):
|
||||
if self.security_dict:
|
||||
passed_security_check = True
|
||||
|
||||
+149
-243
@@ -59,6 +59,71 @@ class Admin( BaseController ):
|
||||
msg = params.msg
|
||||
return trans.fill_template( '/admin/dataset_security/index.mako', msg=msg )
|
||||
|
||||
# Galaxy Role Stuff
|
||||
@web.expose
|
||||
def roles( self, trans, **kwd ):
|
||||
if not self.user_is_admin( trans ):
|
||||
return trans.show_error_message( no_privilege_msg )
|
||||
p = util.Params( kwd )
|
||||
msg = p.msg
|
||||
if 'create' in kwd:
|
||||
if p.create == 'submitted':
|
||||
role = trans.app.model.Role( name = util.restore_text( p.name ),
|
||||
description = util.restore_text( p.description ),
|
||||
type = trans.app.model.Role.types.ADMIN )
|
||||
role.flush()
|
||||
trans.response.send_redirect( url_for( action='roles', associate=True ) )
|
||||
return trans.show_form(
|
||||
web.FormBuilder( action = web.url_for(), title = "Create a new role", name="role", submit_text = "Create" )
|
||||
.add_text( name = "name", label = "Name", value = "New Role" )
|
||||
.add_text( name = "description", label = "Description", value = "" )
|
||||
.add_input( 'hidden', '', 'create', 'submitted', use_label = False )
|
||||
.add_input( 'hidden', '', 'id', id, use_label = False ) )
|
||||
return trans.fill_template( '/admin/dataset_security/roles.mako',
|
||||
roles=trans.app.model.Role.select(),
|
||||
msg=msg )
|
||||
|
||||
@web.expose
|
||||
def role( self, trans, id=None, **kwd ):
|
||||
if not self.user_is_admin( trans ):
|
||||
return trans.show_error_message( no_privilege_msg )
|
||||
p = util.Params( kwd )
|
||||
msg = p.msg
|
||||
if not id:
|
||||
return trans.show_error_message( "Galaxy can't associate roles unless you provide a role id" )
|
||||
role = trans.app.model.Role.get( id )
|
||||
if not role:
|
||||
return trans.show_error_message( "The selected role is invalid" )
|
||||
if role.type == role.types.PRIVATE:
|
||||
return trans.show_error_message( "The Public Access Role cannot be modified" )
|
||||
if 'submitted' in kwd:
|
||||
if p.submitted == 'associate':
|
||||
in_users = [ trans.app.model.User.get( x ) for x in listify( p.in_users ) ]
|
||||
in_groups = [ trans.app.model.Group.get( x ) for x in listify( p.in_groups ) ]
|
||||
trans.app.security_agent.set_entity_role_associations( roles=[ role ], users=in_users, groups=in_groups )
|
||||
role.refresh()
|
||||
in_users = []
|
||||
out_users = []
|
||||
in_groups = []
|
||||
out_groups = []
|
||||
for user in sorted( trans.app.model.User.select(), lambda x,y: cmp( x.email, y.email ) ):
|
||||
if user in [ x.user for x in role.users ]:
|
||||
in_users.append( ( user.id, user.email ) )
|
||||
else:
|
||||
out_users.append( ( user.id, user.email ) )
|
||||
for group in sorted( trans.app.model.Group.select(), lambda x,y: cmp( x.name, y.name ) ):
|
||||
if group in [ x.group for x in role.groups ]:
|
||||
in_groups.append( ( group.id, group.name ) )
|
||||
else:
|
||||
out_groups.append( ( group.id, group.name ) )
|
||||
return trans.fill_template( '/admin/dataset_security/role.mako',
|
||||
role = role,
|
||||
in_users = in_users,
|
||||
out_users = out_users,
|
||||
in_groups = in_groups,
|
||||
out_groups = out_groups
|
||||
)
|
||||
|
||||
# Galaxy Group Stuff
|
||||
@web.expose
|
||||
def groups( self, trans, **kwd ):
|
||||
@@ -69,46 +134,19 @@ class Admin( BaseController ):
|
||||
# This query retrieves groups that are not deleted and members of each group
|
||||
q = sa.select( ( ( galaxy.model.Group.table.c.id ).label( 'group_id' ),
|
||||
( galaxy.model.Group.table.c.name ).label( 'group_name' ),
|
||||
( galaxy.model.Group.table.c.priority ).label( 'group_priority' ),
|
||||
sa.func.count( galaxy.model.User.table.c.id ).label( 'total_members' ) ),
|
||||
whereclause = galaxy.model.Group.table.c.deleted == False,
|
||||
from_obj = [ sa.outerjoin( galaxy.model.Group.table,
|
||||
galaxy.model.UserGroupAssociation.table
|
||||
).outerjoin( galaxy.model.User.table ) ],
|
||||
group_by = [ galaxy.model.Group.table.c.id,
|
||||
galaxy.model.Group.table.c.name,
|
||||
galaxy.model.Group.table.c.priority ],
|
||||
galaxy.model.Group.table.c.name ],
|
||||
order_by = [ galaxy.model.Group.table.c.name ] )
|
||||
groups = []
|
||||
for row in q.execute():
|
||||
total_datasets = 0
|
||||
permitted_actions = []
|
||||
# This 2nd query retrieves the number of datasets and dataset permitted_actions associated with each group
|
||||
q2 = sa.select( ( ( galaxy.model.Group.table.c.id ).label( 'group_id' ),
|
||||
( galaxy.model.GroupDatasetAssociation.table.c.permitted_actions ).label( 'permitted_actions' ),
|
||||
sa.func.count( galaxy.model.Dataset.table.c.id ).label( 'total_datasets' ) ),
|
||||
whereclause = sa.and_( galaxy.model.Group.table.c.id == row.group_id,
|
||||
galaxy.model.Dataset.table.c.deleted == False ),
|
||||
from_obj = [ sa.outerjoin( galaxy.model.Group.table,
|
||||
galaxy.model.GroupDatasetAssociation.table
|
||||
).outerjoin( galaxy.model.Dataset.table ) ],
|
||||
group_by = [ galaxy.model.Group.table.c.id,
|
||||
galaxy.model.GroupDatasetAssociation.table.c.permitted_actions ] )
|
||||
for row2 in q2.execute():
|
||||
total_datasets = row2.total_datasets
|
||||
permitted_actions = []
|
||||
# There may not yet be any GroupDatasetAssociations, in which case no
|
||||
# actions will be found
|
||||
if row2.permitted_actions:
|
||||
for action in row2.permitted_actions:
|
||||
permitted_actions.append( action.encode( 'ascii' ) )
|
||||
permitted_actions.sort()
|
||||
groups.append( ( row.group_id,
|
||||
escape( row.group_name, entities ),
|
||||
row.group_priority,
|
||||
row.total_members,
|
||||
total_datasets,
|
||||
permitted_actions ) )
|
||||
row.total_members ) )
|
||||
return trans.fill_template( '/admin/dataset_security/groups.mako',
|
||||
groups=groups,
|
||||
msg=msg )
|
||||
@@ -143,12 +181,8 @@ class Admin( BaseController ):
|
||||
msg = "A group with that name already exists"
|
||||
trans.response.send_redirect( '/admin/create_group?msg=%s' % msg )
|
||||
else:
|
||||
try:
|
||||
priority = int( params.priority )
|
||||
except:
|
||||
priority = 0
|
||||
# Create the group
|
||||
group = galaxy.model.Group( name, priority )
|
||||
group = galaxy.model.Group( name )
|
||||
group.flush()
|
||||
# Add the members
|
||||
members = params.members
|
||||
@@ -163,7 +197,7 @@ class Admin( BaseController ):
|
||||
# Create the UserGroupAssociation
|
||||
user_group_association = galaxy.model.UserGroupAssociation( user, group )
|
||||
user_group_association.flush()
|
||||
msg = "The new group has been created with priority %s and %s members" % ( str( priority ), str( len( members ) ) )
|
||||
msg = "The new group has been created with %s members" % str( len( members ) )
|
||||
trans.response.send_redirect( '/admin/groups?msg=%s' % msg )
|
||||
@web.expose
|
||||
def group_members( self, trans, **kwd ):
|
||||
@@ -279,50 +313,6 @@ class Admin( BaseController ):
|
||||
msg = "Group membership has been updated with a total of %s members" % len( members )
|
||||
trans.response.send_redirect( '/admin/group_members?group_id=%s&group_name=%s&msg=%s' % ( str( group_id ), params.group_name, msg ) )
|
||||
@web.expose
|
||||
def group_dataset_permitted_actions( self, trans, **kwd ):
|
||||
if not self.user_is_admin( trans ):
|
||||
return trans.show_error_message( no_privilege_msg )
|
||||
params = util.Params( kwd )
|
||||
msg = params.msg
|
||||
group_id = int( params.group_id )
|
||||
gdas = []
|
||||
permitted_actions = []
|
||||
group = galaxy.model.Group.get( group_id )
|
||||
return trans.fill_template( '/admin/dataset_security/group_dataset_permitted_actions_edit.mako',
|
||||
group=group,
|
||||
gdas=group.datasets,
|
||||
msg=msg )
|
||||
@web.expose
|
||||
def group_dataset_permitted_actions_edit( self, trans, **kwd ):
|
||||
if not self.user_is_admin( trans ):
|
||||
return trans.show_error_message( no_privilege_msg )
|
||||
params = util.Params( kwd )
|
||||
group_id = int( params.group_id )
|
||||
permissions = {}
|
||||
for gda_id in params.gdas.split(','):
|
||||
permissions[gda_id] = params.get('gda_actions_%s' % gda_id, None)
|
||||
if isinstance( permissions[gda_id], str ):
|
||||
permissions[gda_id] = [ permissions[gda_id] ]
|
||||
for gda_id, permitted_actions in permissions.items():
|
||||
if permitted_actions is None:
|
||||
gda = trans.app.model.GroupDatasetAssociation.get( int( gda_id ) )
|
||||
if gda.permitted_actions is not []:
|
||||
log.debug( "gda %s: permitted_actions emptied (set to none)" % gda_id )
|
||||
gda.permitted_actions = []
|
||||
gda.flush()
|
||||
else:
|
||||
valid_pas = trans.app.model.security_agent.convert_permitted_action_strings( permitted_actions )
|
||||
if not valid_pas:
|
||||
continue # this shouldn't happen, but might as well check
|
||||
gda = trans.app.model.GroupDatasetAssociation.get( int( gda_id ) )
|
||||
if sorted(gda.permitted_actions) != sorted(valid_pas):
|
||||
log.debug( "gda %s: permitted_actions changed to %s" % ( gda_id, valid_pas ) )
|
||||
gda = trans.app.model.GroupDatasetAssociation.get( int( gda_id ) )
|
||||
gda.permitted_actions = valid_pas
|
||||
gda.flush()
|
||||
msg = "The dataset permitted actions have been updated"
|
||||
trans.response.send_redirect( '/admin/groups?msg=%s' % msg )
|
||||
@web.expose
|
||||
def mark_group_deleted( self, trans, **kwd ):
|
||||
if not self.user_is_admin( trans ):
|
||||
return trans.show_error_message( no_privilege_msg )
|
||||
@@ -343,45 +333,19 @@ class Admin( BaseController ):
|
||||
# This query retrieves groups that are not deleted and members of each group
|
||||
q = sa.select( ( ( galaxy.model.Group.table.c.id ).label( 'group_id' ),
|
||||
( galaxy.model.Group.table.c.name ).label( 'group_name' ),
|
||||
( galaxy.model.Group.table.c.priority ).label( 'group_priority' ),
|
||||
sa.func.count( galaxy.model.User.table.c.id ).label( 'total_members' ) ),
|
||||
whereclause = galaxy.model.Group.table.c.deleted == True,
|
||||
from_obj = [ sa.outerjoin( galaxy.model.Group.table,
|
||||
galaxy.model.UserGroupAssociation.table
|
||||
).outerjoin( galaxy.model.User.table ) ],
|
||||
group_by = [ galaxy.model.Group.table.c.id,
|
||||
galaxy.model.Group.table.c.name,
|
||||
galaxy.model.Group.table.c.priority ],
|
||||
galaxy.model.Group.table.c.name ],
|
||||
order_by = [ galaxy.model.Group.table.c.name ] )
|
||||
groups = []
|
||||
for row in q.execute():
|
||||
total_datasets = 0
|
||||
permitted_actions = []
|
||||
# This 2nd query retrieves the number of datasets and dataset permitted_actions associated with each group
|
||||
q2 = sa.select( ( ( galaxy.model.Group.table.c.id ).label( 'group_id' ),
|
||||
( galaxy.model.GroupDatasetAssociation.table.c.permitted_actions ).label( 'permitted_actions' ),
|
||||
sa.func.count( galaxy.model.Dataset.table.c.id ).label( 'total_datasets' ) ),
|
||||
whereclause = sa.and_( galaxy.model.Group.table.c.id == row.group_id,
|
||||
galaxy.model.Dataset.table.c.deleted == False ),
|
||||
from_obj = [ sa.outerjoin( galaxy.model.Group.table,
|
||||
galaxy.model.GroupDatasetAssociation.table
|
||||
).outerjoin( galaxy.model.Dataset.table ) ],
|
||||
group_by = [ galaxy.model.Group.table.c.id,
|
||||
galaxy.model.GroupDatasetAssociation.table.c.permitted_actions ] )
|
||||
for row2 in q2.execute():
|
||||
total_datasets = row2.total_datasets
|
||||
permitted_actions = []
|
||||
# There may not yet be any GroupDatasetAssociations, in which case no actions will be found
|
||||
if row2.permitted_actions:
|
||||
for action in row2.permitted_actions:
|
||||
permitted_actions.append( action.encode( 'ascii' ) )
|
||||
permitted_actions.sort()
|
||||
groups.append( ( row.group_id,
|
||||
escape( row.group_name, entities ),
|
||||
row.group_priority,
|
||||
row.total_members,
|
||||
total_datasets,
|
||||
permitted_actions ) )
|
||||
row.total_members ) )
|
||||
return trans.fill_template( '/admin/dataset_security/deleted_groups.mako',
|
||||
groups=groups,
|
||||
msg=msg )
|
||||
@@ -449,25 +413,6 @@ class Admin( BaseController ):
|
||||
msg=msg )
|
||||
@web.expose
|
||||
def specified_users_groups( self, trans, **kwd ):
|
||||
def renderable( component, group_id ):
|
||||
#return True if component or at least one of components contents is
|
||||
#associated with group_id
|
||||
if isinstance( component, trans.app.model.LibraryFolder ):
|
||||
# Check the folder's datasets to see what can be rendered
|
||||
for library_folder_dataset_assoc in component.active_datasets:
|
||||
if renderable( library_folder_dataset_assoc, group_id ):
|
||||
return True
|
||||
# Check the folder's sub-folders to see what can be rendered
|
||||
for library_folder in component.active_folders:
|
||||
if renderable( library_folder, group_id ):
|
||||
return True
|
||||
elif isinstance( component, trans.app.model.LibraryFolderDatasetAssociation ):
|
||||
dataset = trans.app.model.Dataset.get( component.dataset_id )
|
||||
for group_dataset_assoc in dataset.groups:
|
||||
if group_dataset_assoc.group_id == group_id:
|
||||
return True
|
||||
return False
|
||||
|
||||
if not self.user_is_admin( trans ):
|
||||
return trans.show_error_message( no_privilege_msg )
|
||||
params = util.Params( kwd )
|
||||
@@ -476,49 +421,15 @@ class Admin( BaseController ):
|
||||
user_email = unescape( params.user_email, unentities )
|
||||
# Get the groups to which the user belongs
|
||||
q = sa.select( ( ( galaxy.model.Group.table.c.id ).label( 'group_id' ),
|
||||
( galaxy.model.Group.table.c.name ).label( 'group_name' ),
|
||||
( galaxy.model.Group.table.c.priority ).label( 'group_priority' ) ),
|
||||
( galaxy.model.Group.table.c.name ).label( 'group_name' ) ),
|
||||
whereclause = galaxy.model.User.table.c.id == user_id,
|
||||
from_obj = [ sa.outerjoin( galaxy.model.User.table,
|
||||
galaxy.model.UserGroupAssociation.table ).outerjoin( galaxy.model.Group.table ) ],
|
||||
order_by = [ 'group_name' ] )
|
||||
groups = []
|
||||
for row in q.execute():
|
||||
libraries = []
|
||||
groups = []
|
||||
permitted_actions = []
|
||||
total_datasets = 0
|
||||
# Perform a 2nd query to get datasets associated with each group
|
||||
q2 = sa.select( ( ( galaxy.model.Group.table.c.id ).label( 'group_id' ),
|
||||
( galaxy.model.GroupDatasetAssociation.table.c.permitted_actions ).label( 'permitted_actions' ),
|
||||
sa.func.count( galaxy.model.Dataset.table.c.id ).label( 'total_datasets' ) ),
|
||||
whereclause = sa.and_( galaxy.model.Group.table.c.id == row.group_id,
|
||||
galaxy.model.Dataset.table.c.deleted == False ),
|
||||
from_obj = [ sa.outerjoin( galaxy.model.Group.table,
|
||||
galaxy.model.GroupDatasetAssociation.table
|
||||
).outerjoin( galaxy.model.Dataset.table ) ],
|
||||
group_by = [ galaxy.model.Group.table.c.id,
|
||||
galaxy.model.GroupDatasetAssociation.table.c.permitted_actions ] )
|
||||
for row2 in q2.execute():
|
||||
libraries = []
|
||||
permitted_actions = []
|
||||
total_datasets = row2.total_datasets
|
||||
# There may not yet be any GroupDatasetAssociations, in which case no
|
||||
# actions will be found
|
||||
if row2.permitted_actions:
|
||||
for action in row2.permitted_actions:
|
||||
permitted_actions.append( action.encode( 'ascii' ) )
|
||||
permitted_actions.sort()
|
||||
# If we have permitted actions, then we have at least 1 GroupDatasetAssociation, in
|
||||
# which case, we can see if we have any Libraries that the user can access
|
||||
|
||||
libraries = [ library for library in trans.app.model.Library.select() if renderable( library.root_folder, row2.group_id ) ]
|
||||
|
||||
groups.append( ( row.group_id,
|
||||
escape( row.group_name, entities ),
|
||||
row.group_priority,
|
||||
total_datasets,
|
||||
permitted_actions,
|
||||
libraries ) )
|
||||
escape( row.group_name, entities ) ) )
|
||||
return trans.fill_template( '/admin/dataset_security/specified_users_groups.mako',
|
||||
user_id=user_id,
|
||||
user_email=escape( user_email, entities ),
|
||||
@@ -672,7 +583,7 @@ class Admin( BaseController ):
|
||||
msg = params.msg
|
||||
|
||||
# add_file method
|
||||
def add_file( file_obj, name, extension, dbkey, last_used_build, groups, info='no info', space_to_tab=False ):
|
||||
def add_file( file_obj, name, extension, dbkey, last_used_build, roles, info='no info', space_to_tab=False ):
|
||||
data_type = None
|
||||
temp_name = sniff.stream_to_file( file_obj )
|
||||
|
||||
@@ -718,14 +629,9 @@ class Admin( BaseController ):
|
||||
folder = trans.app.model.LibraryFolder.get( folder_id )
|
||||
folder.add_dataset( dataset, genome_build=last_used_build )
|
||||
dataset.flush()
|
||||
# GroupDatasetAssociations will enable security on the dataset based on the permitted_actions
|
||||
# associated with the GroupDatasetAssociation. The default permitted_actions at this point
|
||||
# will be DATASET_ACCESS, but the user can change this after the file is uploaded.
|
||||
permitted_actions = [ RBACAgent.permitted_actions.DATASET_ACCESS ]
|
||||
for group_id in groups:
|
||||
group = galaxy.model.Group.get( group_id )
|
||||
group_dataset_assoc = galaxy.model.GroupDatasetAssociation( group, dataset.dataset, permitted_actions )
|
||||
group_dataset_assoc.flush()
|
||||
if roles:
|
||||
adra = galaxy.model.ActionDatasetRolesAssociation( RBACAgent.permitted_actions.DATASET_ACCESS.action, dataset.dataset, roles )
|
||||
adra.flush()
|
||||
shutil.move( temp_name, dataset.dataset.file_name )
|
||||
dataset.dataset.state = dataset.dataset.states.OK
|
||||
dataset.init_meta()
|
||||
@@ -760,16 +666,9 @@ class Admin( BaseController ):
|
||||
if 'space_to_tab' in kwd:
|
||||
if kwd['space_to_tab'] not in ["None", None]:
|
||||
space_to_tab = True
|
||||
if 'groups' not in kwd and 'users' not in kwd and 'public' not in kwd:
|
||||
msg = 'The dataset must be associated with at least 1 user or group, or be set public.'
|
||||
trans.response.send_redirect( web.url_for( action='dataset', folder_id=folder_id, msg=msg ) )
|
||||
groups = []
|
||||
if 'groups' in kwd:
|
||||
groups.extend( listify(kwd['groups']) )
|
||||
if 'users' in kwd:
|
||||
groups.extend( listify(kwd['users']) )
|
||||
if 'public' in kwd:
|
||||
groups.extend( [ trans.app.security_agent.get_public_group().id ] )
|
||||
roles = []
|
||||
if 'roles' in kwd:
|
||||
roles = listify( kwd['roles'] )
|
||||
temp_name = ""
|
||||
data_list = []
|
||||
created_datasets = []
|
||||
@@ -782,7 +681,7 @@ class Admin( BaseController ):
|
||||
extension,
|
||||
dbkey,
|
||||
last_used_build,
|
||||
groups,
|
||||
roles,
|
||||
info="uploaded file",
|
||||
space_to_tab=space_to_tab )
|
||||
elif url_paste not in [ None, "" ]:
|
||||
@@ -796,7 +695,7 @@ class Admin( BaseController ):
|
||||
extension,
|
||||
dbkey,
|
||||
last_used_build,
|
||||
groups,
|
||||
roles,
|
||||
info="uploaded url",
|
||||
space_to_tab=space_to_tab )
|
||||
created_datasets.append( last_dataset_created )
|
||||
@@ -813,7 +712,7 @@ class Admin( BaseController ):
|
||||
extension,
|
||||
dbkey,
|
||||
last_used_build,
|
||||
groups,
|
||||
roles,
|
||||
info="pasted entry",
|
||||
space_to_tab=space_to_tab )
|
||||
elif server_dir not in [ None, "", "None" ]:
|
||||
@@ -831,7 +730,7 @@ class Admin( BaseController ):
|
||||
extension,
|
||||
dbkey,
|
||||
last_used_build,
|
||||
groups,
|
||||
roles,
|
||||
info="imported file",
|
||||
space_to_tab=space_to_tab )
|
||||
created_datasets.append( last_dataset_created )
|
||||
@@ -862,19 +761,14 @@ class Admin( BaseController ):
|
||||
yield build_name, dbkey, ( dbkey==last_used_build )
|
||||
dbkeys = get_dbkey_options( last_used_build )
|
||||
# Send list of groups to the form so the dataset can be associated with 1 or more of them.
|
||||
groups = []
|
||||
q = sa.select( ( ( galaxy.model.Group.table.c.id ).label( 'group_id' ),
|
||||
( galaxy.model.Group.table.c.name ).label( 'group_name' ) ),
|
||||
order_by = [ galaxy.model.Group.table.c.name ] )
|
||||
for row in q.execute():
|
||||
groups.append( ( row.group_id, row.group_name ) )
|
||||
groups = sorted( groups, key=operator.itemgetter(1) )
|
||||
#roles = trans.app.model.Role.select().order_by( 'role_id' )
|
||||
roles = trans.app.model.Role.select( order_by=trans.app.model.Role.c.name )
|
||||
return trans.fill_template( '/admin/library/new_dataset.mako',
|
||||
folder_id=folder_id,
|
||||
file_formats=file_formats,
|
||||
dbkeys=dbkeys,
|
||||
last_used_build=last_used_build,
|
||||
groups=groups,
|
||||
roles=roles,
|
||||
msg=msg )
|
||||
else:
|
||||
if id.count( ',' ):
|
||||
@@ -884,92 +778,111 @@ class Admin( BaseController ):
|
||||
ids = None
|
||||
# id specified, display attributes form
|
||||
if id:
|
||||
dataset = trans.app.model.LibraryFolderDatasetAssociation.get( id )
|
||||
if not dataset:
|
||||
lda = trans.app.model.LibraryFolderDatasetAssociation.get( id )
|
||||
if not lda:
|
||||
return trans.show_error_message( "Invalid dataset specified" )
|
||||
|
||||
# Copied from edit attributes for 'regular' datasets with some additions
|
||||
p = util.Params(kwd, safe=False)
|
||||
if p.change:
|
||||
if p.update_roles:
|
||||
# The user clicked the Save button on the 'Associate With Roles' form
|
||||
permissions = {}
|
||||
for k, v in trans.app.model.Dataset.permitted_actions.items():
|
||||
in_roles = [ trans.app.model.Role.get( x ) for x in listify( p.get( k + '_in', [] ) ) ]
|
||||
permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
|
||||
trans.app.security_agent.set_dataset_permissions( lda.dataset, permissions )
|
||||
lda.dataset.refresh()
|
||||
elif p.change:
|
||||
# The user clicked the Save button on the 'Change data type' form
|
||||
trans.app.datatypes_registry.change_datatype( dataset, p.datatype )
|
||||
trans.app.datatypes_registry.change_datatype( lda, p.datatype )
|
||||
trans.app.model.flush()
|
||||
elif p.save:
|
||||
# The user clicked the Save button on the 'Edit Attributes' form
|
||||
dataset.name = name
|
||||
dataset.info = info
|
||||
lda.name = name
|
||||
lda.info = info
|
||||
# The following for loop will save all metadata_spec items
|
||||
for name, spec in dataset.datatype.metadata_spec.items():
|
||||
for name, spec in lda.datatype.metadata_spec.items():
|
||||
if spec.get("readonly"):
|
||||
continue
|
||||
optional = p.get("is_"+name, None)
|
||||
if optional and optional == 'true':
|
||||
# optional element... == 'true' actually means it is NOT checked (and therefore ommitted)
|
||||
setattr(dataset.metadata,name,None)
|
||||
setattr(lda.metadata,name,None)
|
||||
else:
|
||||
setattr(dataset.metadata,name,spec.unwrap(p.get(name, None), p))
|
||||
setattr(lda.metadata,name,spec.unwrap(p.get(name, None), p))
|
||||
|
||||
dataset.metadata.dbkey = dbkey
|
||||
dataset.datatype.after_edit( dataset )
|
||||
lda.metadata.dbkey = dbkey
|
||||
lda.datatype.after_edit( lda )
|
||||
trans.app.model.flush()
|
||||
return trans.show_ok_message( "Attributes updated" )
|
||||
elif p.detect:
|
||||
# The user clicked the Auto-detect button on the 'Edit Attributes' form
|
||||
for name, spec in dataset.datatype.metadata_spec.items():
|
||||
for name, spec in lda.datatype.metadata_spec.items():
|
||||
# We need to be careful about the attributes we are resetting
|
||||
if name != 'name' and name != 'info' and name != 'dbkey':
|
||||
if spec.get( 'default' ):
|
||||
setattr( dataset.metadata,name,spec.unwrap( spec.get( 'default' ), spec ))
|
||||
dataset.datatype.set_meta( dataset )
|
||||
dataset.datatype.after_edit( dataset )
|
||||
setattr( lda.metadata,name,spec.unwrap( spec.get( 'default' ), spec ))
|
||||
lda.datatype.set_meta( lda )
|
||||
lda.datatype.after_edit( lda )
|
||||
trans.app.model.flush()
|
||||
return trans.show_ok_message( "Attributes updated" )
|
||||
elif p.delete:
|
||||
dataset.deleted = True
|
||||
dataset.flush()
|
||||
lda.deleted = True
|
||||
lda.flush()
|
||||
trans.response.send_redirect( web.url_for( action='library_browser' ) )
|
||||
dataset.datatype.before_edit( dataset )
|
||||
if "dbkey" in dataset.datatype.metadata_spec and not dataset.metadata.dbkey:
|
||||
lda.datatype.before_edit( lda )
|
||||
if "dbkey" in lda.datatype.metadata_spec and not lda.metadata.dbkey:
|
||||
# Copy dbkey into metadata, for backwards compatability
|
||||
# This looks like it does nothing, but getting the dbkey
|
||||
# returns the metadata dbkey unless it is None, in which
|
||||
# case it resorts to the old dbkey. Setting the dbkey
|
||||
# sets it properly in the metadata
|
||||
dataset.metadata.dbkey = dataset.dbkey
|
||||
lda.metadata.dbkey = lda.dbkey
|
||||
metadata = list()
|
||||
# a list of MetadataParemeters
|
||||
for name, spec in dataset.datatype.metadata_spec.items():
|
||||
for name, spec in lda.datatype.metadata_spec.items():
|
||||
if spec.visible:
|
||||
metadata.append( spec.wrap( dataset.metadata.get(name), dataset ) )
|
||||
metadata.append( spec.wrap( lda.metadata.get(name), lda ) )
|
||||
# let's not overwrite the imported datatypes module with the variable datatypes?
|
||||
ldatatypes = [x for x in trans.app.datatypes_registry.datatypes_by_extension.iterkeys()]
|
||||
ldatatypes.sort()
|
||||
return trans.fill_template( "/admin/library/dataset.mako",
|
||||
dataset=dataset,
|
||||
dataset=lda,
|
||||
metadata=metadata,
|
||||
datatypes=ldatatypes,
|
||||
err=None,
|
||||
msg=msg )
|
||||
# multiple ids specfied, display multi permission form
|
||||
elif ids:
|
||||
datasets = []
|
||||
ldas = []
|
||||
for id in [ int( id ) for id in ids ]:
|
||||
d = trans.app.model.LibraryFolderDatasetAssociation.get( id )
|
||||
if d is None:
|
||||
lda = trans.app.model.LibraryFolderDatasetAssociation.get( id )
|
||||
if lda is None:
|
||||
return trans.show_error_message( 'You specified an invalid dataset' )
|
||||
datasets.append( d )
|
||||
if len( datasets ) < 2:
|
||||
ldas.append( lda )
|
||||
if len( ldas ) < 2:
|
||||
return trans.show_error_message( 'You must specify at least two datasets to modify permissions on' )
|
||||
# If the permissions on the first dataset don't match the intersection
|
||||
# of permissions, the permissions across all datasets are not
|
||||
# identical. Although, should we care, or should we just let the admin
|
||||
# overwrite permissions regardless?
|
||||
if trans.app.security_agent.get_dataset_permissions( datasets[0] ) != \
|
||||
trans.app.security_agent.guess_derived_permissions_for_datasets( [ d.dataset for d in datasets ] ):
|
||||
if 'update_roles' in kwd:
|
||||
p = util.Params( kwd )
|
||||
permissions = {}
|
||||
for k, v in trans.app.model.Dataset.permitted_actions.items():
|
||||
in_roles = [ trans.app.model.Role.get( x ) for x in listify( p.get( k + '_in', [] ) ) ]
|
||||
permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
|
||||
for lda in ldas:
|
||||
trans.app.security_agent.set_dataset_permissions( lda.dataset, permissions )
|
||||
lda.dataset.refresh()
|
||||
# Ensure that the permissions across all datasets are
|
||||
# identical. Otherwise, we can't update together.
|
||||
tmp = []
|
||||
for lda in ldas:
|
||||
perms = trans.app.security_agent.get_dataset_permissions( lda.dataset )
|
||||
if perms not in tmp:
|
||||
tmp.append( perms )
|
||||
if len( tmp ) != 1:
|
||||
return trans.show_error_message( "The datasets you selected do not have identical permissions, so they can not be updated together" )
|
||||
else:
|
||||
return trans.fill_template( "/admin/library/dataset.mako",
|
||||
dataset=datasets )
|
||||
dataset=ldas )
|
||||
def check_gzip( self, temp_name ):
|
||||
"""
|
||||
Utility method to check gzipped uploads
|
||||
@@ -1042,6 +955,9 @@ class Admin( BaseController ):
|
||||
trans.response.send_redirect( web.url_for( action='library_browser' ) )
|
||||
@web.expose
|
||||
def datasets( self, trans, **kwd ):
|
||||
"""
|
||||
The datasets method is used by the dropdown box on the admin-side library browser.
|
||||
"""
|
||||
if not self.user_is_admin( trans ):
|
||||
return trans.show_error_message( no_privilege_msg )
|
||||
params = util.Params( kwd )
|
||||
@@ -1086,18 +1002,6 @@ class Admin( BaseController ):
|
||||
### -- Dan:
|
||||
|
||||
|
||||
# Delete any GroupDatasetAssociations #perhaps group assocs should only be deleted when the Dataset object is purged?
|
||||
#for group_dataset_assoc in dataset.groups:
|
||||
# group_dataset_assoc.delete()
|
||||
# group_dataset_assoc.flush()
|
||||
# Delete any HistoryDatasetAssociations #Just because we delete this Library Dataset Association from the library, doesn't mean we want to remove it from a user's history (without their knowledge even)
|
||||
#for history_dataset_assoc in dataset.history_associations:
|
||||
# history_dataset_assoc.deleted = True #set deleted flag to True, do not delete row
|
||||
# history_dataset_assoc.flush()
|
||||
# Delete the dataset
|
||||
#dataset.deleted = True
|
||||
#dataset.flush()
|
||||
|
||||
# Delete the LibraryFolderDatasetAssociation
|
||||
library_folder_dataset_assoc.deleted = True
|
||||
library_folder_dataset_assoc.flush()
|
||||
@@ -1144,11 +1048,13 @@ class Admin( BaseController ):
|
||||
trans.response.send_redirect( web.url_for( action = 'libraries', msg = 'You have deleted the library %s.' % library.id ) )
|
||||
return trans.show_error_message( "You did not specify a library to delete." )
|
||||
|
||||
def listify( item ):
|
||||
def listify( item, return_none=False ):
|
||||
"""
|
||||
Since single params are not a single item list
|
||||
"""
|
||||
if isinstance( item, list ):
|
||||
if item is None:
|
||||
return []
|
||||
elif isinstance( item, list ):
|
||||
return item
|
||||
else:
|
||||
return [ item ]
|
||||
|
||||
@@ -104,7 +104,7 @@ class ASync( BaseController ):
|
||||
#history.datasets.add_dataset( data )
|
||||
|
||||
data = trans.app.model.HistoryDatasetAssociation( create_dataset = True, extension = GALAXY_TYPE )
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, trans.app.security_agent.history_get_default_access( trans.history ) )
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, trans.app.security_agent.history_get_default_permissions( trans.history ) )
|
||||
data.name = GALAXY_NAME
|
||||
data.dbkey = GALAXY_BUILD
|
||||
data.info = GALAXY_INFO
|
||||
|
||||
@@ -271,6 +271,8 @@ class RootController( BaseController ):
|
||||
if target_type:
|
||||
msg = data.datatype.convert_dataset(trans, data, target_type)
|
||||
return trans.show_ok_message( msg, refresh_frames=['history'] )
|
||||
'''
|
||||
Form removed from template, needs to be remade
|
||||
elif p.change_permission:
|
||||
"""The user clicked the change_permission button on the 'Change permissions' form"""
|
||||
if not trans.user:
|
||||
@@ -287,6 +289,7 @@ class RootController( BaseController ):
|
||||
return trans.show_ok_message( "Dataset permissions have been set.", refresh_frames=['history'] )
|
||||
else:
|
||||
return trans.show_error_message( "You are not authorized to change this dataset's permitted actions." )
|
||||
'''
|
||||
|
||||
data.datatype.before_edit( data )
|
||||
|
||||
@@ -399,10 +402,10 @@ class RootController( BaseController ):
|
||||
if history:
|
||||
if history.user_id != None and user:
|
||||
assert user.id == history.user_id, "History does not belong to current user"
|
||||
# Delete DefaultHistoryGroupAssociations
|
||||
for default_history_group_association in history.default_groups:
|
||||
default_history_group_association.delete()
|
||||
default_history_group_association.flush()
|
||||
# Delete DefaultHistoryPermissions
|
||||
for dhp in history.default_permissions:
|
||||
dhp.delete()
|
||||
dhp.flush()
|
||||
# Mark history as deleted in db
|
||||
history.deleted = True
|
||||
history_names.append(history.name)
|
||||
@@ -454,6 +457,42 @@ class RootController( BaseController ):
|
||||
errors.append( "You must select at least one history to undelete." )
|
||||
return self.history_available( trans, id=','.join( id ), show_deleted=True, ok_msg = ok_msg, error_msg = " ".join( errors ) )
|
||||
|
||||
@web.expose
|
||||
def history_undelete( self, trans, id=[], **kwd):
|
||||
"""Undeletes a list of histories, ensures that histories are owned by current user"""
|
||||
history_names = []
|
||||
errors = []
|
||||
ok_msg = ""
|
||||
if id:
|
||||
if not isinstance( id, list ):
|
||||
id = id.split( "," )
|
||||
user = trans.get_user()
|
||||
for hid in id:
|
||||
try:
|
||||
int( hid )
|
||||
except:
|
||||
errors.append( "Invalid history: %s" % str( hid ) )
|
||||
continue
|
||||
history = self.app.model.History.get( hid )
|
||||
if history:
|
||||
if history.user != user:
|
||||
errors.append( "History does not belong to current user." )
|
||||
continue
|
||||
if history.purged:
|
||||
errors.append( "History has already been purged and can not be undeleted." )
|
||||
continue
|
||||
history_names.append( history.name )
|
||||
history.deleted = False
|
||||
else:
|
||||
errors.append( "Not able to find history %s." % str( hid ) )
|
||||
trans.log_event( "History id %s marked as undeleted" % str(hid) )
|
||||
self.app.model.flush()
|
||||
if history_names:
|
||||
ok_msg = "Histories (%s) have been undeleted." % ", ".join( history_names )
|
||||
else:
|
||||
errors.append( "You must select at least one history to undelete." )
|
||||
return self.history_available( trans, id=','.join( id ), show_deleted=True, ok_msg = ok_msg, error_msg = " ".join( errors ) )
|
||||
|
||||
@web.expose
|
||||
def clear_history( self, trans ):
|
||||
"""Clears the history for a user"""
|
||||
@@ -680,12 +719,13 @@ class RootController( BaseController ):
|
||||
"""Adds a POSTed file to a History"""
|
||||
try:
|
||||
history = trans.app.model.History.get( history_id )
|
||||
groups = trans.app.security_agent.history_get_default_access( history )
|
||||
data = trans.app.model.HistoryDatasetAssociation( name = name, info = info, extension = ext, dbkey = dbkey, create_dataset = True )
|
||||
if copy_access_from:
|
||||
copy_access_from = trans.app.model.HistoryDatasetAssociation.get( copy_access_from )
|
||||
group_dataset_associations = copy_access_from.dataset.groups
|
||||
data = trans.app.model.HistoryDatasetAssociation( name = name, info = info, extension = ext, dbkey = dbkey, create_dataset = True )
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, group_dataset_associations )
|
||||
trans.app.security_agent.copy_dataset_permissions( copy_access_from.dataset, data.dataset )
|
||||
else:
|
||||
permissions = trans.app.security_agent.history_get_default_permissions( history )
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, permissions )
|
||||
data.flush()
|
||||
data_file = open( data.file_name, "wb" )
|
||||
file_data.file.seek( 0 )
|
||||
@@ -710,6 +750,8 @@ class RootController( BaseController ):
|
||||
def history_set_default_permitted_actions( self, trans, **kwd ):
|
||||
"""Sets the user's default permitted_actions for the current history"""
|
||||
if trans.user:
|
||||
return trans.show_error_message( "This function is not implemented" )
|
||||
# TODO: reimplement
|
||||
if 'set_permitted_actions' in kwd:
|
||||
"""The user clicked the set_permitted_actions button on the set_permitted_actions form"""
|
||||
history = trans.get_history()
|
||||
|
||||
@@ -171,6 +171,8 @@ class User( BaseController ):
|
||||
def set_default_permitted_actions( self, trans, **kwd ):
|
||||
"""Sets the user's default permitted actions for the new histories"""
|
||||
if trans.user:
|
||||
return trans.show_error_message( "This function is not implemented" )
|
||||
# TODO: reimplement
|
||||
if 'set_permitted_actions' in kwd:
|
||||
"""The user clicked the set_permitted_actions button on the set_permitted_actions form"""
|
||||
group_args = [ k.replace('group_', '', 1) for k in kwd if k.startswith('group_') ]
|
||||
|
||||
@@ -200,7 +200,7 @@ class UniverseWebTransaction( base.DefaultWebTransaction ):
|
||||
history = self.app.model.History( user = self.user )
|
||||
# Make sure we have an id
|
||||
history.flush()
|
||||
self.app.security_agent.history_set_default_access( history )
|
||||
self.app.security_agent.history_set_default_permissions( history )
|
||||
# Immediately associate the new history with self
|
||||
self.__history = history
|
||||
# Make sure we have a valid session to associate with the new history
|
||||
@@ -436,7 +436,7 @@ class UniverseWebTransaction( base.DefaultWebTransaction ):
|
||||
if not history.user:
|
||||
# This user will now acquire previously non-owned history, so set permitted actions to user's default
|
||||
history.user = user
|
||||
self.app.security_agent.history_set_default_access( history, dataset=True )
|
||||
self.app.security_agent.history_set_default_permissions( history, dataset=True, bypass_manage_permission=True )
|
||||
history.user_id = user.id
|
||||
history.flush()
|
||||
self.__history = history
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<%def name="render_row( group_name, group )">
|
||||
<td><a href="${h.url_for( controller='admin', action='undelete_group', group_id=group[0] )}">Undelete</a></td>
|
||||
<td>${group_name}</td>
|
||||
<td>${group[2]}</td>
|
||||
<td><a href="${h.url_for( controller='admin', action='group_members', group_id=group[0], group_name=group[1] )}">${group[3]}</a></td>
|
||||
%if group[4] > 0:
|
||||
<td><a href="${h.url_for( controller='admin', action='group_dataset_permitted_actions', group_id=group[0], group_name=group[1] )}">${group[4]}</a></td>
|
||||
@@ -71,7 +70,6 @@
|
||||
<tr class="header">
|
||||
<td> </td>
|
||||
<td>Group</td>
|
||||
<td>Priority</td>
|
||||
<td>Members</td>
|
||||
<td>Datasets</td>
|
||||
<td>Group Permitted Actions on Datasets</td>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<table border="0">
|
||||
<form name="group_create" action="${h.url_for( controller='admin', action='new_group' )}" method="post" >
|
||||
<tr>
|
||||
<td>Name: <input name="name" type="textfield" value="" size=40"> Priority: <input name="priority" type="textfield" value="0" size=3"></td>
|
||||
<td>Name: <input name="name" type="textfield" value="" size=40"></td>
|
||||
</tr>
|
||||
%if len( users ) == 0:
|
||||
<tr><td>There are no Galaxy users</td></tr>
|
||||
|
||||
@@ -8,22 +8,7 @@
|
||||
## Render a row
|
||||
<%def name="render_row( group_name, group )">
|
||||
<td>${group_name}</td>
|
||||
<td>${group[2]}</td>
|
||||
<td><a href="${h.url_for( controller='admin', action='group_members', group_id=group[0], group_name=group[1] )}">${group[3]}</a></td>
|
||||
%if group[4] > 0:
|
||||
<td><a href="${h.url_for( controller='admin', action='group_dataset_permitted_actions', group_id=group[0], group_name=group[1] )}">${group[4]}</a></td>
|
||||
%else:
|
||||
<td>${group[4]}</td>
|
||||
%endif
|
||||
<td>
|
||||
%if len( group[5] ) == 1:
|
||||
${group[5][0]}
|
||||
%elif len( group[5] ) > 1:
|
||||
%for da in group[5]:
|
||||
${da}<br/>
|
||||
%endfor
|
||||
%endif
|
||||
</td>
|
||||
<td><a href="${h.url_for( controller='admin', action='group_members', group_id=group[0], group_name=group[1] )}">${group[2]}</a></td>
|
||||
<td><a href="${h.url_for( controller='admin', action='mark_group_deleted', group_id=group[0] )}">Mark group deleted</a></td>
|
||||
</%def>
|
||||
|
||||
@@ -75,10 +60,7 @@
|
||||
%endif
|
||||
<tr class="header">
|
||||
<td>Name</td>
|
||||
<td>Priority</td>
|
||||
<td>Members</td>
|
||||
<td>Datasets</td>
|
||||
<td>Group Permitted Actions on Datasets</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
%for group in groups:
|
||||
|
||||
@@ -25,19 +25,11 @@
|
||||
|
||||
<tr class="header">
|
||||
<td>Group</td>
|
||||
<td>Priority</td>
|
||||
<td>Datasets</td>
|
||||
<td>Permitted Actions on Datasets</td>
|
||||
<td>Containing Libraries</td>
|
||||
</tr>
|
||||
<% ctr = 0 %>
|
||||
%for group in groups:
|
||||
<%
|
||||
gn = unescape( group[1], unentities )
|
||||
library_ids = ''
|
||||
for library_id in group[5]:
|
||||
library_ids += "%s," % library_id
|
||||
library_ids = library_ids.rstrip( ',' )
|
||||
%>
|
||||
%if ctr % 2 == 1:
|
||||
<tr class="odd_row">
|
||||
@@ -45,24 +37,6 @@
|
||||
<tr class="tr">
|
||||
%endif
|
||||
<td>${gn}</td>
|
||||
<td>${group[2]}</td>
|
||||
%if group[3] > 0:
|
||||
<td><a href="${h.url_for( controller='admin', action='group_dataset_permitted_actions', group_id=group[0], group_name=group[1] )}">${group[3]}</a></td>
|
||||
%else:
|
||||
<td>${group[3]}</td>
|
||||
%endif
|
||||
<td>
|
||||
%for da in group[4]:
|
||||
${da}<br/>
|
||||
%endfor
|
||||
</td>
|
||||
<td>
|
||||
%if len( group[5] ) > 0:
|
||||
<a href="${h.url_for( controller='admin', action='specified_users_group_libraries', user_email=user_email, group_name=group[1], library_ids=library_ids )}">${len( group[5] )}</a>
|
||||
%else:
|
||||
${len( group[5] )}
|
||||
%endif
|
||||
</td>
|
||||
</tr>
|
||||
<% ctr += 1 %>
|
||||
%endfor
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
<div class="toolSectionBg">
|
||||
<div class="toolTitle"><a href="${h.url_for( action='users' )}" target="galaxy_main">Manage users</a></div>
|
||||
<div class="toolTitle"><a href="${h.url_for( action='groups' )}" target="galaxy_main">Manage groups</a></div>
|
||||
<div class="toolTitle"><a href="${h.url_for( action='roles' )}" target="galaxy_main">Manage roles</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toolSectionPad"></div>
|
||||
|
||||
@@ -141,6 +141,7 @@
|
||||
</ul>
|
||||
<form name="update_multiple_datasets" action="${h.url_for( action='datasets' )}" onSubmit="javascript:return checkForm();" method="post">
|
||||
<ul>
|
||||
%if libraries:
|
||||
%for library in libraries:
|
||||
##%if trans.app.security_agent.check_folder_contents( trans.user, library ):
|
||||
<li class="libraryRow libraryOrFolderRow" id="libraryRow"><div class="rowTitle"><table cellspacing="0" cellpadding="0" border="0" width="100%" class="libraryTitle"><tr>
|
||||
@@ -177,3 +178,6 @@
|
||||
<input type="submit" class="primary-button" name="with-selected" id="with-selected-submit" value="go"/>
|
||||
</div>
|
||||
</form>
|
||||
%else:
|
||||
There are no libraries.
|
||||
%endif
|
||||
|
||||
@@ -1,3 +1,33 @@
|
||||
<%def name="render_select( dataset, action_key, action )">
|
||||
<%
|
||||
in_roles = []
|
||||
for a in dataset.actions:
|
||||
if a.action == action.action:
|
||||
for role_id in a.role_ids:
|
||||
in_roles.append( trans.app.model.Role.get( role_id ) )
|
||||
out_roles = filter( lambda x: x not in in_roles, trans.app.model.Role.select() )
|
||||
%>
|
||||
<p><label>${action.description}</label></p>
|
||||
<div style="float: left; margin-right: 10px;">
|
||||
Roles associated:<br/>
|
||||
<select name="${action_key}_in" id="${action_key}_in_select" class="in_select" style="min-width: 250px;" multiple>
|
||||
%for role in in_roles:
|
||||
<option value="${role.id}">${role.name}</option>
|
||||
%endfor
|
||||
</select> <br/>
|
||||
<input type="submit" id="${action_key}_remove_button" class="role_remove_button" value=">>"/>
|
||||
</div>
|
||||
<div>
|
||||
Roles not associated:<br/>
|
||||
<select name="${action_key}_out" id="${action_key}_out_select" style="min-width: 250px;" multiple>
|
||||
%for role in out_roles:
|
||||
<option value="${role.id}">${role.name}</option>
|
||||
%endfor
|
||||
</select> <br/>
|
||||
<input type="submit" id="${action_key}_add_button" class="role_add_button" value="<<"/>
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
<%def name="render_permissions_forms( data_obj )">
|
||||
<script type="text/javascript">
|
||||
var q = jQuery.noConflict();
|
||||
@@ -14,6 +44,23 @@
|
||||
q("div#group_" + this.value).slideUp("fast");
|
||||
}
|
||||
});
|
||||
q('.role_add_button').click(function() {
|
||||
var action = this.id.substring( 0, this.id.lastIndexOf( '_add_button' ) )
|
||||
var in_select = '#' + action + '_in_select';
|
||||
var out_select = '#' + action + '_out_select';
|
||||
return !q(out_select + ' option:selected').remove().appendTo(in_select);
|
||||
});
|
||||
q('.role_remove_button').click(function() {
|
||||
var action = this.id.substring( 0, this.id.lastIndexOf( '_remove_button' ) )
|
||||
var in_select = '#' + action + '_in_select';
|
||||
var out_select = '#' + action + '_out_select';
|
||||
return !q(in_select + ' option:selected').remove().appendTo(out_select);
|
||||
});
|
||||
q('form#edit_role_associations').submit(function() {
|
||||
q('.in_select option').each(function(i) {
|
||||
q(this).attr("selected", "selected");
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -32,118 +79,30 @@
|
||||
trans.show_error_message( "Unknown object passed to render_permissions_forms" )
|
||||
if id is None:
|
||||
id = dataset.id
|
||||
|
||||
%>
|
||||
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Change Existing Permissions</div>
|
||||
<div class="toolFormTitle">Associate with roles and set permissions</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="edit_group_associations" action="${h.url_for( controller='admin', action='dataset_permissions' )}" method="post">
|
||||
<form name="edit_role_associations" id="edit_role_associations" action="${h.url_for( action='dataset' )}" method="post">
|
||||
<input type="hidden" name="id" value="${id}">
|
||||
%if redirect:
|
||||
<input type="hidden" name="${redirect[0]}" value="${redirect[1]}">
|
||||
%endif
|
||||
<div class="form-row">
|
||||
<%
|
||||
user_permissions = [ p for p in trans.app.security_agent.get_dataset_permissions( dataset ) if p[0].name.endswith( ' private group' ) ]
|
||||
real_permissions = [ p for p in trans.app.security_agent.get_dataset_permissions( dataset ) if not p[0].name.endswith( ' private group' ) and p[0].name != 'public' ]
|
||||
%>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
Update the permissions for the users and groups currently associated with this dataset.
|
||||
</div>
|
||||
<br/>
|
||||
%if trans.app.security_agent.dataset_has_group( dataset.id, trans.app.security_agent.get_public_group().id ):
|
||||
<label>Allow public access:</label><br/>
|
||||
<input type="checkbox" name="public" value="Yes" checked> This dataset can be accessed by anyone (it is public).<br/>
|
||||
%endif
|
||||
<br/>
|
||||
<label>Users with permissions on this dataset:</label><br/>
|
||||
%if not len( user_permissions ):
|
||||
None<br/>
|
||||
%endif
|
||||
%for p in user_permissions:
|
||||
<input type="checkbox" name="users" class="groupCheckbox" value="${p[0].id}" checked/> ${p[0].name.replace( ' private group', '' )} <br/>
|
||||
<div class="permissionContainer" id="group_${p[0].id}">
|
||||
%for k, v in trans.app.security_agent.permitted_actions.items():
|
||||
<input type="checkbox" name="actions" value="${p[0].id},${k}"
|
||||
%if v in p[1]:
|
||||
checked
|
||||
%endif
|
||||
/> ${trans.app.security_agent.get_permitted_action_description(k)} <br/>
|
||||
%endfor
|
||||
</div>
|
||||
%endfor
|
||||
<br/>
|
||||
<label>Groups with permissions on this dataset:</label><br/>
|
||||
%if not len( real_permissions ):
|
||||
None<br/>
|
||||
%endif
|
||||
%for p in real_permissions:
|
||||
<input type="checkbox" name="groups" class="groupCheckbox" value="${p[0].id}" checked/> ${p[0].name} <br/>
|
||||
<div class="permissionContainer" id="group_${p[0].id}">
|
||||
%for k, v in trans.app.security_agent.permitted_actions.items():
|
||||
<input type="checkbox" name="actions" value="${p[0].id},${k}"
|
||||
%if v in p[1]:
|
||||
checked
|
||||
%endif
|
||||
/> ${trans.app.security_agent.get_permitted_action_description(k)} <br/>
|
||||
%endfor
|
||||
</div>
|
||||
%endfor
|
||||
<br/>
|
||||
<label>
|
||||
Choose which roles are required to perform each action on this dataset.
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-row"><input type="submit" name="change_permitted_actions" value="Save"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<p/>
|
||||
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Add New Users and Groups</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="make_new_group_associations" action="${h.url_for( controller='admin', action='dataset_permissions' )}" method="post">
|
||||
<input type="hidden" name="id" value="${id}">
|
||||
%if redirect:
|
||||
<input type="hidden" name="${redirect[0]}" value="${redirect[1]}">
|
||||
%endif
|
||||
%for k, v in trans.app.model.Dataset.permitted_actions.items():
|
||||
<div class="form-row">
|
||||
${render_select( dataset, k, v )}
|
||||
</div>
|
||||
%endfor
|
||||
<div class="form-row">
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
Select new users and groups to associate with this dataset (you can assign permissions after creating the association).
|
||||
</div>
|
||||
## Don't display the public access checkbox if it's already public (it's shown above instead)
|
||||
%if not trans.app.security_agent.dataset_has_group( dataset.id, trans.app.security_agent.get_public_group().id ):
|
||||
<label>Allow public access:</label><br/>
|
||||
<input type="checkbox" name="public" value="Yes"> This dataset can be accessed by anyone (make it public).<br/>
|
||||
%endif
|
||||
<br/>
|
||||
<%
|
||||
all_groups = trans.app.model.Group.select()
|
||||
user_groups = [ g for g in all_groups if g.name.endswith( ' private group' ) ]
|
||||
real_groups = [ g for g in all_groups if not g.name.endswith( ' private group' ) and g.name != 'public' ]
|
||||
%>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<label>Associate with users:</label>
|
||||
<select name="users" multiple="true" size="5">
|
||||
%for group in user_groups:
|
||||
%if not trans.app.security_agent.dataset_has_group( dataset.id, group.id ):
|
||||
<option value="${group.id}">${group.name.replace( ' private group', '' )}</option>
|
||||
%endif
|
||||
%endfor
|
||||
</select>
|
||||
<p/>
|
||||
<label>Associate with groups:</label>
|
||||
<select name="groups" multiple="true" size="5">
|
||||
%for group in real_groups:
|
||||
%if dataset and not trans.app.security_agent.dataset_has_group( dataset.id, group.id ):
|
||||
<option value="${group.id}">${group.name}</option>
|
||||
%endif
|
||||
%endfor
|
||||
</select>
|
||||
</div>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
To select multiple users or groups, hold ctrl or command while clicking.
|
||||
</div>
|
||||
<input type="submit" name="update_roles" value="Save"/>
|
||||
</div>
|
||||
<div class="form-row"><input type="submit" name="create_group_associations" value="Save"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -164,11 +123,11 @@
|
||||
else:
|
||||
data_state = data.state
|
||||
%>
|
||||
%if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ):
|
||||
<div class="historyItemWrapper historyItem historyItem-${data_state} historyItem-noPermission" id="historyItem-${data.id}">
|
||||
%else:
|
||||
##%if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ):
|
||||
## <div class="historyItemWrapper historyItem historyItem-${data_state} historyItem-noPermission" id="historyItem-${data.id}">
|
||||
##%else:
|
||||
<div class="historyItemWrapper historyItem historyItem-${data_state}" id="historyItem-${data.id}">
|
||||
%endif
|
||||
##%endif
|
||||
|
||||
## Header row for history items (name, state, action buttons)
|
||||
|
||||
|
||||
@@ -80,30 +80,16 @@
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Allow public access:</label>
|
||||
<input type="checkbox" name="public" value="Yes"> This dataset can be accessed by anyone (make it public).<br/>
|
||||
<p/>
|
||||
<% user_groups = [ g for g in groups if g[1].endswith( ' private group' ) ] %>
|
||||
<% real_groups = [ g for g in groups if not g[1].endswith( ' private group' ) and g[1] != 'public' ] %>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<label>Associate with users:</label>
|
||||
<select name="users" multiple="true" size="5">
|
||||
%for group in user_groups:
|
||||
<option value="${group[0]}">${group[1].replace( ' private group', '' )}</option>
|
||||
<label>Restrict dataset access to specific roles:</label>
|
||||
<select name="roles" multiple="true" size="5">
|
||||
%for role in roles:
|
||||
<option value="${role.id}">${role.name}</option>
|
||||
%endfor
|
||||
</select>
|
||||
%if len( real_groups ):
|
||||
<p/>
|
||||
<label>Associate with groups:</label>
|
||||
<select name="groups" multiple="true" size="5">
|
||||
%for group in real_groups:
|
||||
<option value="${group[0]}">${group[1]}</option>
|
||||
%endfor
|
||||
</select>
|
||||
%endif
|
||||
</div>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
To select multiple users or groups, hold ctrl or command while clicking.
|
||||
To select multiple roles, hold ctrl or command while clicking. More permissions can be set after the upload is complete. Selecting no roles makes a dataset public.
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
|
||||
@@ -165,90 +165,3 @@ elif isinstance( data, trans.app.model.LibraryFolderDatasetAssociation ):
|
||||
|
||||
<p />
|
||||
%endif
|
||||
|
||||
%if trans.user and ( trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data ) ):
|
||||
<script type="text/javascript">
|
||||
var q = jQuery.noConflict();
|
||||
q( document ).ready( function () {
|
||||
// initialize state
|
||||
q("input.groupCheckbox").each( function() {
|
||||
if ( ! q(this).is(":checked") ) q("div#" + this.name).hide();
|
||||
});
|
||||
// handle events
|
||||
q("input.groupCheckbox").click( function() {
|
||||
if ( q(this).is(":checked") ) {
|
||||
q("div#" + this.name).slideDown("fast");
|
||||
} else {
|
||||
q("div#" + this.name).slideUp("fast");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Change Dataset Access Permissions</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="change_permission_form" action="${h.url_for( action='edit' )}" method="post">
|
||||
<input type="hidden" name="${id_name}" value="${data.id}">
|
||||
<div class="form-row">
|
||||
<% user_groups = [ assoc.group for assoc in trans.user.groups ] %>
|
||||
<% dataset_group_ids = [ assoc.group.id for assoc in data.dataset.groups ] %>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
Check each group which should have access to this dataset.
|
||||
</div>
|
||||
%for group in user_groups:
|
||||
%if group.id in dataset_group_ids:
|
||||
<% assoc = filter( lambda x: x.group_id == group.id, data.dataset.groups )[0] %>
|
||||
%else:
|
||||
<% assoc = None %>
|
||||
%endif
|
||||
<input type="checkbox" name="group_${group.id}" class="groupCheckbox"
|
||||
%if assoc is not None:
|
||||
checked
|
||||
%endif
|
||||
/> ${group.name} <br/>
|
||||
<div class="permissionContainer" id="group_${group.id}">
|
||||
%for k, v in trans.app.security_agent.permitted_actions.items():
|
||||
<input type="checkbox" name="group_${group.id}_${k}"
|
||||
%if assoc is not None and v in assoc.permitted_actions:
|
||||
checked
|
||||
%endif
|
||||
/> ${trans.app.security_agent.get_permitted_action_description(k)} <br/>
|
||||
%endfor
|
||||
</div>
|
||||
%endfor
|
||||
<input type="submit" name="change_permission" value="Save">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
%elif trans.user and ( trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ) ):
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Dataset Access Permissions</div>
|
||||
<div class="toolFormBody">
|
||||
<div class="form-row">
|
||||
<label>The following groups may perform the actions listed on this dataset:</label>
|
||||
<br/>
|
||||
%for assoc in data.dataset.groups:
|
||||
${assoc.group.name}
|
||||
<ul>
|
||||
%for action in assoc.permitted_actions:
|
||||
<li>${trans.app.security_agent.get_permitted_action_description(action)}</li>
|
||||
%endfor
|
||||
</ul>
|
||||
%endfor
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
You are not allowed to change the permitted actions on this dataset.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
%endif
|
||||
|
||||
<p>
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Copy History Item</div>
|
||||
<div class="toolFormBody">
|
||||
Click <a href="${h.url_for( controller='dataset', action='copy_datasets', source_dataset_ids=data.id, target_history_ids=data.history_id )}" target="galaxy_main">here</a> to make a copy of this history item.
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
@@ -530,20 +530,19 @@ class TwillTestCase( unittest.TestCase ):
|
||||
self.assertNotEqual(count, maxiter)
|
||||
|
||||
# Dataset Security stuff
|
||||
def create_group( self, name='New Test Group', priority='10' ):
|
||||
def create_group( self, name='New Test Group' ):
|
||||
"""Create a new group with 1 member"""
|
||||
self.visit_url( "%s/admin/create_group" % self.url )
|
||||
form = tc.show()
|
||||
self.check_page_for_string( "Create Group" )
|
||||
try:
|
||||
tc.fv( "1", "name", name )
|
||||
tc.fv( "1", "priority", priority )
|
||||
# twill version 0.9 still does not allow for easily testing forms that contain
|
||||
# multiple fields with the same name ( e.g., check boxes ). We could attempt to determine
|
||||
# the number of the field on the form and use it instead of the name of the field, but we
|
||||
# would be forced to drop and recreate the database every time we test in order to ensure
|
||||
# the fields will be the same on the form ( since it is dynamically rendered from the database ).
|
||||
tc.fv( "1", "3", "1" ) # 1-based form field 3 is the 1st check box named 'members', user id 1 is test@bx.psu.edu
|
||||
tc.fv( "1", "2", "1" ) # 1-based form field 3 is the 1st check box named 'members', user id 1 is test@bx.psu.edu
|
||||
tc.submit( "create_group_button" )
|
||||
except AssertionError, err:
|
||||
errmsg = 'Exception caught attempting to create group: %s' % str( err )
|
||||
|
||||
@@ -53,7 +53,7 @@ class TestHistory( TwillTestCase ):
|
||||
self.visit_page( "admin/groups" )
|
||||
# the following should have been created when account was created.
|
||||
self.check_page_for_string( 'test@bx.psu.edu private group' )
|
||||
self.create_group( name='New Test Group', priority='10' )
|
||||
self.create_group( name='New Test Group' )
|
||||
self.visit_page( "admin/groups" )
|
||||
self.check_page_for_string( "group_name=New+Test+Group" )
|
||||
# twill version 0.9 still does not allow for the following test
|
||||
|
||||
@@ -38,7 +38,7 @@ def exec_after_process(app, inp_data, out_data, param_dict, tool, stdout, stderr
|
||||
newdata.extension = file_type
|
||||
newdata.name = basic_name + " (" + description + ")"
|
||||
history.add_dataset( newdata )
|
||||
app.security_agent.set_dataset_permissions( newdata.dataset, base_dataset.dataset.groups )
|
||||
app.security_agent.copy_dataset_permissions( base_dataset.dataset, newdata.dataset )
|
||||
app.model.flush()
|
||||
try:
|
||||
copyfile(filepath,newdata.file_name)
|
||||
|
||||
@@ -129,7 +129,7 @@ def exec_after_process(app, inp_data, out_data, param_dict, tool, stdout, stderr
|
||||
newdata.extension = file_type
|
||||
newdata.name = basic_name + " (" + microbe_info[kingdom][org]['chrs'][chr]['data'][description]['feature'] +" for "+microbe_info[kingdom][org]['name']+":"+chr + ")"
|
||||
newdata.flush()
|
||||
app.security_agent.set_dataset_permissions( newdata.dataset, base_dataset.dataset.groups )
|
||||
app.security_agent.copy_dataset_permissions( base_dataset.dataset, newdata.dataset )
|
||||
history.add_dataset( newdata )
|
||||
app.model.flush()
|
||||
try:
|
||||
|
||||
@@ -32,7 +32,7 @@ def exec_after_process(app, inp_data, out_data, param_dict, tool, stdout, stderr
|
||||
newdata.name = basic_name + " (" + dbkey + ")"
|
||||
newdata.flush()
|
||||
history.add_dataset( newdata )
|
||||
app.security_agent.set_dataset_permissions( newdata.dataset, output_data.dataset.groups )
|
||||
app.security_agent.copy_dataset_permissions( output_data.dataset, newdata.dataset )
|
||||
newdata.flush()
|
||||
history.flush()
|
||||
app.model.flush()
|
||||
|
||||
Reference in New Issue
Block a user