First pass with adding role based access controls. Added roles and groups. Users can be associated with groups. Roles can be associated with roles, datasets, groups, and users.

Currently the creator of a dataset can mark the dataset as private, preventing other users from viewing or utilizing this dataset, even if it's containing history is shared. This is done via the edit attributes page for a particular dataset.

This requires enable_beta_features to be set.
This commit is contained in:
Daniel Blankenberg
2008-07-25 14:16:41 -04:00
parent 8d679d6541
commit 404d86d2ea
13 changed files with 872 additions and 234 deletions
+2 -2
View File
@@ -110,7 +110,7 @@ class Gmaj( data.Data ):
"nobutton": "false",
"urlpause" :"100",
"debug": "false",
"posturl": "history_add_to?%s" % urlencode( { 'history_id': dataset.history_id, 'ext': 'maf', 'name': 'GMAJ Output on data %s' % dataset.hid, 'info': 'Added by GMAJ', 'dbkey': dataset.dbkey } )
"posturl": "history_add_to?%s" % urlencode( { 'history_id': dataset.history_id, 'ext': 'maf', 'name': 'GMAJ Output on data %s' % dataset.hid, 'info': 'Added by GMAJ', 'dbkey': dataset.dbkey, 'copy_access_from': dataset.id } )
}
class_name = "edu.psu.bx.gmaj.MajApplet.class"
archive = "/static/gmaj/gmaj.jar"
@@ -180,7 +180,7 @@ class Laj( data.Text ):
"alignfile1": "display?id=%s" % dataset.id,
"buttonlabel": "Launch LAJ",
"title": "LAJ in Galaxy",
"posturl": "history_add_to?%s" % urlencode( { 'history_id': dataset.history_id, 'ext': 'lav', 'name': 'LAJ Output', 'info': 'Added by LAJ', 'dbkey': dataset.dbkey } ),
"posturl": "history_add_to?%s" % urlencode( { 'history_id': dataset.history_id, 'ext': 'lav', 'name': 'LAJ Output', 'info': 'Added by LAJ', 'dbkey': dataset.dbkey, 'copy_access_from': dataset.id } ),
"noseq": "true"
}
class_name = "edu.psu.cse.bio.laj.LajApplet.class"
+466 -105
View File
@@ -27,19 +27,97 @@ def set_datatypes_registry( d_registry ):
datatypes_registry = d_registry
class User( object ):
def __init__( self, email=None, password=None ):
def __init__( self, email=None, password=None, groups = [], roles = [], default_groups = [], default_roles = [] ):
self.email = email
self.password = password
self.external = False
# Relationships
self.histories = []
if not groups:
groups.append( GalaxyGroup.get( GalaxyGroup.public_id ) )
default_groups.append( groups[-1] )
default_groups.append( self.create_private_group() )
group_id_added = []
for group in groups:
if group.id not in group_id_added:
group.add_user( self )
group_id_added.append( group.id )
group_id_added = []
for group in default_groups:
if group.id not in group_id_added:
user_group_assoc = DefaultUserGroupAssociation( self, group )
user_group_assoc.flush()
group_id_added.append( group.id )
role_id_added = []
for role in roles:
if role.id not in role_id_added:
role.add_user( self )
role_id_added.append( role.id )
role_id_added = []
for role in default_roles:
if role.id not in role_id_added:
role_group_assoc = DefaultUserRoleAssociation( self, role )
role_group_assoc.flush()
role_id_added.append( role.id )
def set_password_cleartext( self, cleartext ):
"""Set 'self.password' to the digest of 'cleartext'."""
self.password = sha.new( cleartext ).hexdigest()
def check_password( self, cleartext ):
"""Check if 'cleartext' matches 'self.password' when hashed."""
return self.password == sha.new( cleartext ).hexdigest()
def create_private_group( self ):
#create private group
group = GalaxyGroup( self.email, priority = 10 )
group.flush()
#create private dataset access role
role = AccessRole( "%s dataset access" % self.email, list( Dataset.access_actions.__dict__.values() ), priority = 1 )
role.flush()
#add role to group
group.add_role( role )
#create roles for user modification of role
user_role = AccessRole( "%s role modification" % self.email, list( AccessRole.access_actions.__dict__.values() ) )
user_role.flush()
#add role to user
user_role.add_user( self )
#add role to role
role.add_role( user_role )
#create roles for user modification of group
group_role = AccessRole( "%s group modification" % self.email, list( GalaxyGroup.access_actions.__dict__.values() ) )
group_role.flush()
#add role to group
group.add_access_role( group_role )
#associate role and user
group_role.add_user( self )
#add user to group
group.add_user( self )
group.flush()
return group
def add_group( self, group ):
return group.add_user( self )
def has_group( self, check_group ):
return bool( UserGroupAssociation.get_by( group_id = check_group.id, user_id = self.id ) )
def has_role( self, check_role ):
return bool( UserRoleAssociation.get_by( role_id = check_role.id, user_id = self.id ) )
def set_default_access( self, groups = None, roles = None, history = False, dataset = False ):
if groups is not None:
for assoc in self.default_groups: #this is the association not the actual group
assoc.delete()
for group in groups:
assoc = DefaultUserGroupAssociation( self, group )
assoc.flush()
if roles is not None:
for assoc in self.default_roles: #this is the association not the actual group
assoc.delete()
for role in roles:
assoc = DefaultUserRoleAssociation( self, role )
assoc.flush()
if history:
for history in self.histories:
history.set_default_access( groups = groups, roles = roles, dataset = dataset )
class Job( object ):
"""
A job represents a request to run a tool given input datasets, tool
@@ -101,10 +179,337 @@ class JobToOutputDatasetAssociation( object ):
self.name = name
self.dataset = dataset
class AccessRole( object ):
dataset_actions = Bunch( VIEW = 'dataset_view', #viewing/downloading
USE = 'dataset_use', #use in jobs
ADD_ROLE = 'dataset_add_role', #dataset can be added to roles
REMOVE_ROLE = 'dataset_remove_role', #dataset can be removed from roles
ADD_GROUP = 'dataset_add_group', #dataset can be added to groups
REMOVE_GROUP = 'dataset_remove_group' ) #dataset can be removed from groups
role_actions = Bunch( ADD_DATASET = 'role_add_dataset', #add role to dataset
REMOVE_DATASET = 'role_remove_dataset', #remove role from dataset
DELETE = 'role_delete', #delete a role
MODIFY = 'role_modify', #change a role's actions,
ADD_GROUP = 'role_add_group', #add role to a group
REMOVE_GROUP = 'role_remove_group' ) #remove role from a group
group_actions = Bunch( ADD_DATASET = 'group_add_dataset', #add group to dataset
REMOVE_DATASET = 'group_remove_dataset', #remove dataset from group
DELETE = 'group_delete', #delete a group
ADD_ROLE = 'group_add_role', #add role to group
REMOVE_ROLE = 'group_remove_role', #remove role from group
ADD_USER = 'group_add_user' ) #add users to group
access_actions = role_actions
def __init__( self, name, actions, priority = 0 ):
self.name = name
if not isinstance( actions, list ):
actions = [ actions ]
self.actions = actions
self.priority = priority
def add_user( self, user ):
assoc = UserRoleAssociation( user, self )
assoc.flush()
return assoc
def add_group( self, group ):
assoc = GroupRoleAssociation( group, self )
assoc.flush()
return assoc
def add_role( self, role ):
assoc = RoleRoleAssociation( role, self )
assoc.flush()
return assoc
def add_dataset( self, dataset ):
assoc = RoleDatasetAssociation( self, dataset )
assoc.flush()
return assoc
class GalaxyGroup( object ):
public_id = None
access_actions = AccessRole.group_actions
def __init__( self, name, priority = 0 ):
self.name = name
self.priority = priority
def add_user( self, user ):
assoc = UserGroupAssociation( user, self )
assoc.flush()
return assoc
def add_role( self, role ):
return role.add_group( self )
def add_access_role( self, role ):
assoc = GroupRoleAccessAssociation( self, role )
assoc.flush()
return assoc
def add_dataset( self, dataset ):
assoc = GroupDatasetAssociation( self, dataset )
assoc.flush()
return assoc
class UserGroupAssociation( object ):
def __init__( self, user, group ):
self.user = user
self.group = group
class RoleRoleAssociation( object ):
def __init__( self, role, target_role ):
self.role = role
self.target_role = target_role
class GroupRoleAccessAssociation( object ):
def __init__( self, group, role ):
self.group = group
self.role = role
class GroupRoleAssociation( object ):
def __init__( self, group, role ):
self.group = group
self.role = role
class UserRoleAssociation( object ):
def __init__( self, user, role ):
self.user = user
self.role = role
class GroupDatasetAssociation( object ):
def __init__( self, group, dataset ):
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
class RoleDatasetAssociation( object ):
def __init__( self, role, dataset ):
if isinstance( role, RoleDatasetAssociation ) or isinstance( role, DefaultUserRoleAssociation ) or isinstance( role, DefaultHistoryRoleAssociation ):
role = role.role
self.role = role
if isinstance( dataset, HistoryDatasetAssociation ):
dataset = dataset.dataset
self.dataset = dataset
class DefaultUserRoleAssociation( object ):
def __init__( self, user, role ):
if isinstance( role, RoleDatasetAssociation ) or isinstance( role, DefaultUserRoleAssociation ) or isinstance( role, DefaultHistoryRoleAssociation ):
role = role.role
self.user = user
self.role = role
class DefaultUserGroupAssociation( object ):
def __init__( self, user, group ):
if isinstance( group, GroupDatasetAssociation ) or isinstance( group, DefaultUserGroupAssociation ) or isinstance( group, DefaultHistoryGroupAssociation ):
group = group.group
self.user = user
self.group = group
class DefaultHistoryRoleAssociation( object ):
def __init__( self, history, role ):
if isinstance( role, RoleDatasetAssociation ) or isinstance( role, DefaultUserRoleAssociation ) or isinstance( role, DefaultHistoryRoleAssociation ):
role = role.role
self.history = history
self.role = role
class DefaultHistoryGroupAssociation( object ):
def __init__( self, history, group ):
if isinstance( group, GroupDatasetAssociation ) or isinstance( group, DefaultUserGroupAssociation ) or isinstance( group, DefaultHistoryGroupAssociation ):
group = group.group
self.history = history
self.group = group
class Dataset( object ):
states = Bunch( NEW = 'new',
QUEUED = 'queued',
RUNNING = 'running',
OK = 'ok',
EMPTY = 'empty',
ERROR = 'error',
DISCARDED = 'discarded' )
access_actions = AccessRole.dataset_actions
file_path = "/tmp/"
engine = None
def __init__( self, id=None, state=None, external_filename=None, extra_files_path=None, file_size=None, purgable=True, access_groups=[], access_roles=[] ):
self.id = id
self.state = state
self.deleted = False
self.purged = False
self.purgable = purgable
self.external_filename = external_filename
self._extra_files_path = extra_files_path
self.file_size = file_size
if access_groups or access_roles:
#self.flush()
for group in access_groups:
group.add_dataset( self )
group.flush()
for role in access_roles:
role.add_dataset( self )
role.flush()
def get_file_name( self ):
if not self.external_filename:
assert self.id is not None, "ID must be set before filename used (commit the object)"
# First try filename directly under file_path
filename = os.path.join( self.file_path, "dataset_%d.dat" % self.id )
# Only use that filename if it already exists (backward compatibility),
# otherwise construct hashed path
if not os.path.exists( filename ):
dir = os.path.join( self.file_path, *directory_hash_id( self.id ) )
# Create directory if it does not exist
try:
os.makedirs( dir )
except OSError, e:
# File Exists is okay, otherwise reraise
if e.errno != errno.EEXIST:
raise
# Return filename inside hashed directory
return os.path.abspath( os.path.join( dir, "dataset_%d.dat" % self.id ) )
else:
filename = self.external_filename
# Make filename absolute
return os.path.abspath( filename )
def set_file_name ( self, filename ):
if not filename:
self.external_filename = None
else:
self.external_filename = filename
file_name = property( get_file_name, set_file_name )
@property
def extra_files_path( self ):
if self._extra_files_path:
path = self._extra_files_path
else:
path = os.path.join( self.file_path, "dataset_%d_files" % self.id )
#only use path directly under self.file_path if it exists
if not os.path.exists( path ):
path = os.path.join( os.path.join( self.file_path, *directory_hash_id( self.id ) ), "dataset_%d_files" % self.id )
# Make path absolute
return os.path.abspath( path )
def get_size( self ):
"""Returns the size of the data on disk"""
if self.file_size:
return self.file_size
else:
try:
return os.path.getsize( self.file_name )
except OSError:
return 0
def set_size( self ):
"""Returns the size of the data on disk"""
try:
self.file_size = os.path.getsize( self.file_name )
except OSError:
self.file_size = 0
def has_data( self ):
"""Detects whether there is any data"""
return self.get_size() > 0
def mark_deleted( self, include_children=True ):
self.deleted = True
def allow_action( self, user, action ):
"""Returns true when user has permission to perform an action"""
#if dataset is in public group, we always return true for viewing and using
#this may need to change when the ability to alter groups and roles is allowed
if action in [ self.access_actions.USE, self.access_actions.VIEW ] and GroupDatasetAssociation.get_by( group_id = GalaxyGroup.public_id, dataset_id = self.id ):
return True
elif user is not None:
#loop through permissions and if allowed return true:
#check roles associated directly with dataset first
for role_dataset_assoc in self.roles:
if action in role_dataset_assoc.role.actions and user.has_role( role_dataset_assoc.role ):
return True
#check roles associated with dataset through groups
for group_dataset_assoc in self.groups:
if user.has_group( group_dataset_assoc.group ):
for group_role_assoc in group_dataset_assoc.group.roles:
if action in group_role_assoc.role.actions:
return True
return False #no user and dataset not in public group, or user lacks permission
def guess_derived_groups_roles( self, other_datasets = [] ):
"""Returns a list of output roles and groups based upon itself and provided datasets"""
if not other_datasets:
return [ data_group_assoc.group for data_group_assoc in self.groups ], [ data_role_assoc.role for data_role_assoc in self.roles ]
access_roles = None
priority_access_role = None
access_groups = None
priority_access_group = None
for dataset in [ self ] + other_datasets:
#determine access roles and groups for output datasets
#roles and groups for output dataset is the intersection across all inputs
#if we end up with no intersection between inputs, then we rely on priorities
if isinstance( dataset, HistoryDatasetAssociation ):
dataset = dataset.dataset
roles = [ data_role_assoc.role for data_role_assoc in dataset.roles ]
for role in roles:
if priority_access_role is None or priority_access_role.priority < role.priority:
priority_access_role = role
groups = [ data_group_assoc.group for data_group_assoc in dataset.groups ]
for group in groups:
if priority_access_group is None or priority_access_group.priority < group.priority:
priority_access_group = group
if access_roles is None:
access_roles = set( roles )
access_groups = set( groups )
else:
access_roles.intersection_update( set( roles ) )
access_groups.intersection_update( set( groups ) )
#complete lists for output dataset access
if access_roles:
access_roles = list( access_roles )
else:
access_roles = []
if access_groups:
access_groups = list( access_groups)
else:
access_groups = []
#if we have no roles or groups left after intersection,
#take the highest priority group or role
if not access_roles and not access_groups:
if priority_access_role and priority_access_group:
if priority_access_group.priority == priority_access_role.priority:
access_groups = [ priority_access_group ]
access_roles = [ priority_access_role ]
elif priority_access_group.priority > priority_access_role.priority:
access_groups = [ priority_access_group ]
else:
access_roles = [ priority_access_role ]
elif priority_access_role:
access_roles = [ priority_access_role ]
elif priority_access_group:
access_groups = [ priority_access_group ]
return access_groups, access_roles
def add_group( self, group ):
return group.add_dataset( self )
def add_role( self, role ):
return role.add_dataset( self )
def has_group( self, group ):
return bool( GroupDatasetAssociation.get_by( group_id = group.id, dataset_id = self.id ) )
def has_role( self, role ):
return bool( RoleDatasetAssociation.get_by( role_id = role.id, dataset_id = self.id ) )
# FIXME: sqlalchemy will replace this
def _delete(self):
"""Remove the file that corresponds to this data"""
try:
os.remove(self.data.file_name)
except OSError, e:
log.critical('%s delete error %s' % (self.__class__.__name__, e))
class HistoryDatasetAssociation( object ):
states = Dataset.states
access_actions = Dataset.access_actions
def __init__( self, id=None, hid=None, name=None, info=None, blurb=None, peek=None, extension=None,
dbkey=None, metadata=None, history=None, dataset=None, deleted=False, designation=None,
parent_id=None, validation_errors=None, visible=True, create_dataset = False ):
parent_id=None, validation_errors=None, visible=True, create_dataset = False, access_groups = [], access_roles = [] ):
self.name = name or "Unnamed dataset"
self.id = id
self.hid = hid
@@ -120,7 +525,7 @@ class HistoryDatasetAssociation( object ):
# Relationships
self.history = history
if not dataset and create_dataset:
dataset = Dataset()
dataset = Dataset( access_groups = access_groups, access_roles = access_roles )
dataset.flush()
self.dataset = dataset
self.parent_id = parent_id
@@ -130,10 +535,6 @@ class HistoryDatasetAssociation( object ):
def ext( self ):
return self.extension
@property
def states( self ):
return self.dataset.states
def get_dataset_state( self ):
return self.dataset.state
def set_dataset_state ( self, state ):
@@ -251,7 +652,8 @@ class HistoryDatasetAssociation( object ):
def get_converter_types(self):
return self.datatype.get_converter_types( self, datatypes_registry)
def copy( self, copy_children = False, parent_id = None ):
def copy( self, copy_children = False, parent_id = None, target_user = None ):
if target_user is None: target_user = self.user
des = HistoryDatasetAssociation( hid=self.hid, name=self.name, info=self.info, blurb=self.blurb, peek=self.peek, extension=self.extension, dbkey=self.dbkey, metadata=self._metadata, dataset = self.dataset, visible=self.visible, deleted=self.deleted, parent_id=parent_id )
des.flush()
if copy_children:
@@ -273,10 +675,12 @@ class HistoryDatasetAssociation( object ):
for child in self.children:
child.mark_deleted()
def allow_action( self, user, action ):
return self.dataset.allow_action( user, action )
class History( object ):
def __init__( self, id=None, name=None, user=None ):
def __init__( self, id=None, name=None, user=None, default_roles = [], default_groups = [] ):
self.id = id
self.name = name or "Unnamed history"
self.deleted = False
@@ -287,6 +691,18 @@ class History( object ):
self.datasets = []
self.galaxy_sessions = []
if not default_roles:
if user:
default_roles = user.default_roles
if not default_groups:
if user:
default_groups = user.default_groups
else:
default_groups = [ GalaxyGroup.get( GalaxyGroup.public_id ) ]
self.set_default_access( roles = default_roles, groups = default_groups )
def _next_hid( self ):
# TODO: override this with something in the database that ensures
# better integrity
@@ -325,18 +741,55 @@ class History( object ):
self.genome_build = genome_build
self.datasets.append( dataset )
def copy(self):
des = History()
def copy( self, target_user = None ):
if not target_user:
target_user = self.user
des = History( user = target_user )
des.flush()
des.name = self.name
des.user_id = self.user_id
for data in self.datasets:
new_data = data.copy( copy_children = True )
new_data = data.copy( copy_children = True, target_user = target_user )
des.add_dataset( new_data )
new_data.flush()
des.hid_counter = self.hid_counter
des.flush()
return des
def set_default_access( self, groups = None, roles = None, dataset = False ):
if groups is not None:
for assoc in self.default_groups: #this is the association not the actual group
assoc.delete()
assoc.flush()
for group in groups:
assoc = DefaultHistoryGroupAssociation( self, group )
assoc.flush()
if roles is not None:
for assoc in self.default_roles: #this is the association not the actual group
assoc.delete()
assoc.flush()
for role in roles:
assoc = DefaultHistoryRoleAssociation( self, role )
assoc.flush()
if dataset:
for data in self.datasets:
for hda in data.dataset.history_associations:
if self.user and hda.history not in self.user.histories:
break
else:
if groups is not None:
for assoc in data.dataset.groups: #this is the association not the actual group
assoc.delete()
assoc.flush()
for group in groups:
group.add_dataset( data )
if roles is not None:
for assoc in data.dataset.roles: #this is the association not the actual group
assoc.delete()
assoc.flush()
for role in roles:
role.add_dataset( data )
# class Query( object ):
# def __init__( self, name=None, state=None, tool_parameters=None, history=None ):
@@ -347,98 +800,6 @@ class History( object ):
# self.history = history
# self.datasets = []
class Dataset( object ):
states = Bunch( NEW = 'new',
QUEUED = 'queued',
RUNNING = 'running',
OK = 'ok',
EMPTY = 'empty',
ERROR = 'error',
DISCARDED = 'discarded' )
file_path = "/tmp/"
engine = None
def __init__( self, id=None, state=None, external_filename=None, extra_files_path=None, file_size=None, purgable=True ):
self.id = id
self.state = state
self.deleted = False
self.purged = False
self.purgable = purgable
self.external_filename = external_filename
self._extra_files_path = extra_files_path
self.file_size = file_size
def get_file_name( self ):
if not self.external_filename:
assert self.id is not None, "ID must be set before filename used (commit the object)"
# First try filename directly under file_path
filename = os.path.join( self.file_path, "dataset_%d.dat" % self.id )
# Only use that filename if it already exists (backward compatibility),
# otherwise construct hashed path
if not os.path.exists( filename ):
dir = os.path.join( self.file_path, *directory_hash_id( self.id ) )
# Create directory if it does not exist
try:
os.makedirs( dir )
except OSError, e:
# File Exists is okay, otherwise reraise
if e.errno != errno.EEXIST:
raise
# Return filename inside hashed directory
return os.path.abspath( os.path.join( dir, "dataset_%d.dat" % self.id ) )
else:
filename = self.external_filename
# Make filename absolute
return os.path.abspath( filename )
def set_file_name ( self, filename ):
if not filename:
self.external_filename = None
else:
self.external_filename = filename
file_name = property( get_file_name, set_file_name )
@property
def extra_files_path( self ):
if self._extra_files_path:
path = self._extra_files_path
else:
path = os.path.join( self.file_path, "dataset_%d_files" % self.id )
#only use path directly under self.file_path if it exists
if not os.path.exists( path ):
path = os.path.join( os.path.join( self.file_path, *directory_hash_id( self.id ) ), "dataset_%d_files" % self.id )
# Make path absolute
return os.path.abspath( path )
def get_size( self ):
"""Returns the size of the data on disk"""
if self.file_size:
return self.file_size
else:
try:
return os.path.getsize( self.file_name )
except OSError:
return 0
def set_size( self ):
"""Returns the size of the data on disk"""
try:
self.file_size = os.path.getsize( self.file_name )
except OSError:
self.file_size = 0
def has_data( self ):
"""Detects whether there is any data"""
return self.get_size() > 0
def mark_deleted( self, include_children=True ):
self.deleted = True
# FIXME: sqlalchemy will replace this
def _delete(self):
"""Remove the file that corresponds to this data"""
try:
os.remove(self.data.file_name)
except OSError, e:
log.critical('%s delete error %s' % (self.__class__.__name__, e))
class Old_Dataset( Dataset ):
pass
+170
View File
@@ -113,6 +113,99 @@ ValidationError.table = Table( "validation_error", metadata,
Column( "err_type", TrimmedString( 64 ) ),
Column( "attributes", TEXT ) )
GalaxyGroup.table = Table( "galaxy_group", metadata,
Column( "id", Integer, primary_key=True ),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ),
Column( "name", TEXT ),
Column( "priority", Integer ) )
UserGroupAssociation.table = Table( "user_group_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
Column( "group_id", Integer, ForeignKey( "galaxy_group.id" ), index=True ),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ) )
AccessRole.table = Table( "access_role", metadata,
Column( "id", Integer, primary_key=True ),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ),
Column( "name", TEXT ),
Column( "actions", JSONType(), default=[] ),
Column( "priority", Integer ) )
UserRoleAssociation.table = Table( "user_role_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
Column( "role_id", Integer, ForeignKey( "access_role.id" ), index=True ),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ) )
GroupRoleAssociation.table = Table( "group_role_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "group_id", Integer, ForeignKey( "galaxy_group.id" ), index=True ),
Column( "role_id", Integer, ForeignKey( "access_role.id" ), index=True ),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ) )
GroupDatasetAssociation.table = Table( "group_dataset_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 ) )
RoleDatasetAssociation.table = Table( "role_dataset_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "role_id", Integer, ForeignKey( "access_role.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 ) )
RoleRoleAssociation.table = Table( "role_role_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "role_id", Integer, ForeignKey( "access_role.id" ), index=True ),
Column( "target_role_id", Integer, ForeignKey( "access_role.id" ), index=True ),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ) )
GroupRoleAccessAssociation.table = Table( "group_role_access_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "role_id", Integer, ForeignKey( "access_role.id" ), index=True ),
Column( "group_id", Integer, ForeignKey( "galaxy_group.id" ), index=True ),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ) )
DefaultUserRoleAssociation.table = Table( "default_user_role_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "role_id", Integer, ForeignKey( "access_role.id" ), index=True ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ) )
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( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ) )
DefaultHistoryRoleAssociation.table = Table( "default_history_role_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "role_id", Integer, ForeignKey( "access_role.id" ), index=True ),
Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ) )
DefaultHistoryGroupAssociation.table = Table( "default_history_group_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( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ) )
Job.table = Table( "job", metadata,
Column( "id", Integer, primary_key=True ),
Column( "create_time", DateTime, default=now ),
@@ -293,6 +386,56 @@ assign_mapper( context, User, User.table,
collection_class=ordering_list( 'order_index' ) )
) )
assign_mapper( context, GalaxyGroup, GalaxyGroup.table,
properties=dict( users=relation( UserGroupAssociation ),
datasets=relation( GroupDatasetAssociation ) ) )
assign_mapper( context, UserGroupAssociation, UserGroupAssociation.table,
properties=dict( user=relation( User, backref = "groups" ),
group=relation( GalaxyGroup, backref = "users" ) ) )
assign_mapper( context, UserRoleAssociation, UserRoleAssociation.table,
properties=dict( role=relation( AccessRole, backref = "users" ),
user=relation( User, backref = "roles" ) ) )
assign_mapper( context, GroupRoleAssociation, GroupRoleAssociation.table,
properties=dict( role=relation( AccessRole, backref = "groups" ),
group=relation( GalaxyGroup, backref = "roles" ) ) )
assign_mapper( context, AccessRole, AccessRole.table )
assign_mapper( context, GroupDatasetAssociation, GroupDatasetAssociation.table,
properties=dict( dataset=relation( Dataset, backref = "groups" ),
group=relation( GalaxyGroup, backref = "datasets" ) ) )
assign_mapper( context, RoleDatasetAssociation, RoleDatasetAssociation.table,
properties=dict( dataset=relation( Dataset, backref = "roles" ),
role=relation( AccessRole ) ) )
assign_mapper( context, RoleRoleAssociation, RoleRoleAssociation.table,
properties=dict( role=relation( AccessRole, primaryjoin=( ( RoleRoleAssociation.table.c.role_id == AccessRole.table.c.id ) ) ),
target_role=relation( AccessRole, primaryjoin=( RoleRoleAssociation.table.c.target_role_id == AccessRole.table.c.id ), backref="roles" ) ) )
assign_mapper( context, GroupRoleAccessAssociation, GroupRoleAccessAssociation.table,
properties=dict( role=relation( AccessRole, backref="access_groups" ),
group=relation( GalaxyGroup, backref="access_roles" ) ) )
assign_mapper( context, DefaultUserRoleAssociation, DefaultUserRoleAssociation.table,
properties=dict( user=relation( User, backref = "default_roles" ),
role=relation( AccessRole ) ) )
assign_mapper( context, DefaultUserGroupAssociation, DefaultUserGroupAssociation.table,
properties=dict( user=relation( User, backref = "default_groups" ),
group=relation( GalaxyGroup ) ) )
assign_mapper( context, DefaultHistoryRoleAssociation, DefaultHistoryRoleAssociation.table,
properties=dict( history=relation( History, backref = "default_roles" ),
role=relation( AccessRole ) ) )
assign_mapper( context, DefaultHistoryGroupAssociation, DefaultHistoryGroupAssociation.table,
properties=dict( history=relation( History, backref = "default_groups" ),
group=relation( GalaxyGroup ) ) )
assign_mapper( context, JobToInputDatasetAssociation, JobToInputDatasetAssociation.table,
properties=dict( job=relation( Job ), dataset=relation( HistoryDatasetAssociation ) ) )
@@ -406,6 +549,33 @@ def init( file_path, url, engine_options={}, create_tables=False ):
result.flush = lambda *args, **kwargs: context.current.flush( *args, **kwargs )
result.context = context
result.create_tables = create_tables
#set up default table entries here, currently only exist for access controls
if result.AccessRole.count() == 0:
log.warning( "There were no access roles located, setting up default (public) access roles." )
#create public group
public_group = result.GalaxyGroup( 'public' )
public_group.flush()
#create public_all role
public_role = result.AccessRole( 'public', [ result.Dataset.access_actions.USE, result.Dataset.access_actions.VIEW, result.GalaxyGroup.access_actions.ADD_DATASET, result.GalaxyGroup.access_actions.REMOVE_DATASET ] )
public_role.flush()
public_group.add_role( public_role )
#store public group id
GalaxyGroup.public_id = public_group.id #we use the id instead of the object, because of alchemy sessions
#add all datasets to public group
for dataset in result.Dataset.select():
public_group.add_dataset( dataset )
#loop through all current users and associate with the public group
#and create and associate with user's own group
for user in result.User.select():
public_group.add_user( user )
private_group = user.create_private_group()
user.set_default_access( groups = [ public_group, private_group ], roles = [], history = True, dataset = True )
else:
#retrieve from database and store public group id, assume first created group is public
GalaxyGroup.public_id = result.GalaxyGroup.select( order_by = asc( result.GalaxyGroup.table.c.create_time ) )[0].id #we use the id instead of the object, because of alchemy sessions
log.debug( "Public Group identified as id = %s." % ( GalaxyGroup.public_id ) )
return result
def get_suite():
+2 -2
View File
@@ -1084,7 +1084,7 @@ class Tool:
if visible == "visible": visible = True
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 )
child_dataset = self.app.model.HistoryDatasetAssociation( extension=ext, parent_id=outdata.id, designation=designation, visible=visible, dbkey=outdata.dbkey, create_dataset=True, access_groups=outdata.dataset.groups, access_roles=outdata.dataset.roles )
# Move data from temp location to dataset location
shutil.move( filename, child_dataset.file_name )
child_dataset.flush()
@@ -1120,7 +1120,7 @@ class Tool:
else: visible = False
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 )
primary_data = self.app.model.HistoryDatasetAssociation( extension=ext, designation=designation, visible=visible, dbkey=outdata.dbkey, create_dataset=True, access_groups=outdata.dataset.groups, access_roles=outdata.dataset.roles )
primary_data.flush()
# Move data from temp location to dataset location
shutil.move( filename, primary_data.file_name )
+15 -1
View File
@@ -43,6 +43,8 @@ class DefaultToolAction( object ):
assoc.flush()
data = new_data
break
if data and not data.allow_action( trans.user, data.access_actions.USE ):
raise "User does not have permission to use a dataset (%s) provided for input." % data.id
return data
if isinstance( input, DataToolParameter ):
if isinstance( value, list ):
@@ -79,6 +81,16 @@ class DefaultToolAction( object ):
data = NoneDataset( datatypes_registry = trans.app.datatypes_registry )
if data.dbkey not in [None, '?']:
input_dbkey = data.dbkey
#determine output dataset access list
existing_datasets = [ inp for inp in inp_data.values() if inp ]
if existing_datasets:
output_access_groups, output_access_roles = existing_datasets[0].dataset.guess_derived_groups_roles( existing_datasets[1:] )
else:
#no valid inputs, we will use history defaults
output_access_roles = [ role.role for role in trans.history.default_roles ]
output_access_groups = [ group.group for group in trans.history.default_groups ]
# Build name for output datasets based on tool name and input names
if len( input_names ) == 1:
on_text = input_names[0]
@@ -117,7 +129,7 @@ class DefaultToolAction( object ):
ext = output.format
if ext == "input":
ext = input_ext
data = trans.app.model.HistoryDatasetAssociation( extension=ext, create_dataset=True )
data = trans.app.model.HistoryDatasetAssociation( extension=ext, create_dataset=True, access_groups=output_access_groups, access_roles=output_access_roles )
# Commit the dataset immediately so it gets database assigned unique id
data.flush()
# Create an empty file immediately
@@ -183,6 +195,8 @@ class DefaultToolAction( object ):
job.add_parameter( name, value )
for name, dataset in inp_data.iteritems():
if dataset:
if not dataset.allow_action( trans.user, dataset.access_actions.USE ):
raise "User does not have permission to use a dataset (%s) provided for input." % data.id
job.add_input_dataset( name, dataset )
else:
job.add_input_dataset( name, None )
+2 -2
View File
@@ -65,7 +65,7 @@ class UploadToolAction( object ):
return dict( output=data_list[0] )
def upload_empty(self, trans, err_code, err_msg):
data = trans.app.model.HistoryDatasetAssociation( create_dataset = True )
data = trans.app.model.HistoryDatasetAssociation( create_dataset = True, access_groups = [ group.group for group in trans.history.default_groups ], access_roles = [ role.role for role in trans.history.default_roles ] )
data.name = err_code
data.extension = "txt"
data.dbkey = "?"
@@ -158,7 +158,7 @@ class UploadToolAction( object ):
if info is None:
info = 'uploaded %s file' %data_type
data = trans.app.model.HistoryDatasetAssociation( history = trans.history, extension = ext, create_dataset = True )
data = trans.app.model.HistoryDatasetAssociation( history = trans.history, extension = ext, create_dataset = True, access_groups = [ group.group for group in trans.history.default_groups ], access_roles = [ role.role for role in trans.history.default_roles ] )
data.name = file_name
data.dbkey = dbkey
data.info = info
+16 -8
View File
@@ -979,19 +979,25 @@ class DataToolParameter( ToolParameter ):
displayed as radio buttons and multiple selects as a set of checkboxes
>>> # Mock up a history (not connected to database)
>>> from galaxy.model import History, HistoryDatasetAssociation
>>> from galaxy.model import History, HistoryDatasetAssociation, User, AccessRole, GalaxyGroup, GroupRoleAssociation
>>> from galaxy.util.bunch import Bunch
>>> hist = History()
>>> hist.flush()
>>> hist.add_dataset( HistoryDatasetAssociation( id=1, extension='txt', create_dataset=True ) )
>>> hist.add_dataset( HistoryDatasetAssociation( id=2, extension='bed', create_dataset=True ) )
>>> hist.add_dataset( HistoryDatasetAssociation( id=3, extension='fasta', create_dataset=True ) )
>>> hist.add_dataset( HistoryDatasetAssociation( id=4, extension='png', create_dataset=True ) )
>>> hist.add_dataset( HistoryDatasetAssociation( id=5, extension='interval', create_dataset=True ) )
>>> role = AccessRole( 'test', list( AccessRole.dataset_actions.__dict__.values() ) )
>>> role.flush()
>>> group = GalaxyGroup( 'test' )
>>> group.flush()
>>> GalaxyGroup.public_id = group.id
>>> GroupRoleAssociation( group, role ).flush()
>>> hist.add_dataset( HistoryDatasetAssociation( id=1, extension='txt', create_dataset=True, access_groups=[ group ] ) )
>>> hist.add_dataset( HistoryDatasetAssociation( id=2, extension='bed', create_dataset=True, access_groups=[ group ] ) )
>>> hist.add_dataset( HistoryDatasetAssociation( id=3, extension='fasta', create_dataset=True, access_groups=[ group ] ) )
>>> hist.add_dataset( HistoryDatasetAssociation( id=4, extension='png', create_dataset=True, access_groups=[ group ] ) )
>>> hist.add_dataset( HistoryDatasetAssociation( id=5, extension='interval', create_dataset=True, access_groups=[ group ] ) )
>>> p = DataToolParameter( None, XML( '<param name="blah" type="data" format="interval"/>' ) )
>>> print p.name
blah
>>> print p.get_html( trans=Bunch( history=hist ) )
>>> print p.get_html( trans=Bunch( history=hist, user=None ) )
<select name="blah">
<option value="2">2: Unnamed dataset</option>
<option value="5" selected>5: Unnamed dataset</option>
@@ -1047,7 +1053,7 @@ class DataToolParameter( ToolParameter ):
hid = "%s.%d" % ( parent_hid, i + 1 )
else:
hid = str( data.hid )
if not data.deleted and data.state not in [data.states.ERROR] and data.visible:
if not data.deleted and data.state not in [data.states.ERROR] and data.visible and data.allow_action( trans.user, data.access_actions.USE ):
if self.options and data.get_dbkey() != filter_value:
continue
if isinstance( data.datatype, self.formats):
@@ -1061,6 +1067,8 @@ class DataToolParameter( ToolParameter ):
data = datasets[0]
elif not self.converter_safe( other_values, trans ):
continue
if not data.allow_action( trans.user, data.access_actions.USE ):
continue
selected = ( value and ( data in value ) )
field.add_option( "%s: (as %s) %s" % ( hid, target_ext, data.name[:30] ), data.id, selected )
break #we only report the first valid converter, assume self.extensions is a priority list
+1 -1
View File
@@ -103,7 +103,7 @@ class ASync( BaseController ):
#data.state = jobs.JOB_OK
#history.datasets.add_dataset( data )
data = trans.app.model.HistoryDatasetAssociation( create_dataset = True, extension = GALAXY_TYPE )
data = trans.app.model.HistoryDatasetAssociation( create_dataset = True, extension = GALAXY_TYPE, access_groups = [ group.group for group in trans.history.default_groups ], access_roles = [ role.role for role in trans.history.default_roles ] )
data.name = GALAXY_NAME
data.dbkey = GALAXY_BUILD
data.info = GALAXY_INFO
+23 -24
View File
@@ -103,28 +103,27 @@ class DatasetInterface( BaseController ):
@web.expose
def display(self, trans, dataset_id=None, filename=None, **kwd):
"""Catches the dataset id and displays file contents as directed"""
if filename is None or filename.lower() == "index":
try:
data = trans.app.model.HistoryDatasetAssociation.get( dataset_id )
if data:
mime = trans.app.datatypes_registry.get_mimetype_by_extension( data.extension.lower() )
trans.response.set_content_type(mime)
trans.log_event( "Display dataset id: %s" % str(dataset_id) )
try:
return open( data.file_name )
except:
return "This item contains no content"
except:
pass
return "Invalid dataset specified"
else:
#display files from directory here
try:
file_path = os.path.join(trans.app.model.HistoryDatasetAssociation.get( dataset_id ).extra_files_path, filename)
mime, encoding = mimetypes.guess_type(file_path)
if mime is None:
mime = trans.app.datatypes_registry.get_mimetype_by_extension(".".split(file_path)[-1])
data = trans.app.model.HistoryDatasetAssociation.get( dataset_id )
if not data:
raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid reference dataset." )
if data.allow_action( trans.user, data.access_actions.VIEW ):
if filename is None or filename.lower() == "index":
mime = trans.app.datatypes_registry.get_mimetype_by_extension( data.extension.lower() )
trans.response.set_content_type(mime)
return open(file_path)
except:
raise paste.httpexceptions.HTTPNotFound( "File Not Found (%s)." % (filename) )
trans.log_event( "Display dataset id: %s" % str( dataset_id ) )
try:
return open( data.file_name )
except:
raise paste.httpexceptions.HTTPNotFound( "File Not Found (%s)." % ( filename ) )
else:
file_path = os.path.join( data.extra_files_path, filename )
mime, encoding = mimetypes.guess_type( file_path )
if mime is None:
mime = trans.app.datatypes_registry.get_mimetype_by_extension( ".".split( file_path )[-1] )
trans.response.set_content_type( mime )
try:
return open( file_path )
except:
raise paste.httpexceptions.HTTPNotFound( "File Not Found (%s)." % ( filename ) )
else:
raise paste.httpexceptions.HTTPForbidden( "You are not privileged to access this dataset." )
+134 -86
View File
@@ -137,22 +137,25 @@ class RootController( BaseController ):
except:
return "Dataset id '%s' is invalid" %str( id )
if data:
mime = trans.app.datatypes_registry.get_mimetype_by_extension( data.extension.lower() )
trans.response.set_content_type(mime)
if tofile:
fStat = os.stat(data.file_name)
trans.response.headers['Content-Length'] = int(fStat.st_size)
if toext[0:1] != ".":
toext = "." + toext
valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
fname = data.name
fname = ''.join(c in valid_chars and c or '_' for c in fname)[0:150]
trans.response.headers["Content-Disposition"] = "attachment; filename=GalaxyHistoryItem-%s-[%s]%s" % (data.hid, fname, toext)
trans.log_event( "Display dataset id: %s" % str(id) )
try:
return open( data.file_name )
except:
return "This dataset contains no content"
if data.allow_action( trans.user, data.access_actions.VIEW ):
mime = trans.app.datatypes_registry.get_mimetype_by_extension( data.extension.lower() )
trans.response.set_content_type(mime)
if tofile:
fStat = os.stat(data.file_name)
trans.response.headers['Content-Length'] = int(fStat.st_size)
if toext[0:1] != ".":
toext = "." + toext
valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
fname = data.name
fname = ''.join(c in valid_chars and c or '_' for c in fname)[0:150]
trans.response.headers["Content-Disposition"] = "attachment; filename=GalaxyHistoryItem-%s-[%s]%s" % (data.hid, fname, toext)
trans.log_event( "Display dataset id: %s" % str(id) )
try:
return open( data.file_name )
except:
return "This dataset contains no content"
else:
return "You are not privileged to view this dataset."
else:
return "No dataset with id '%s'" % str( id )
@@ -164,9 +167,12 @@ class RootController( BaseController ):
try:
data = self.app.model.HistoryDatasetAssociation.get( parent_id )
if data:
child = data.get_child_by_designation(designation)
child = data.get_child_by_designation( designation )
if child:
return self.display(trans, id=child.id, tofile=tofile, toext=toext)
if child.allow_action( trans.user, child.access_actions.VIEW ):
return self.display( trans, id=child.id, tofile=tofile, toext=toext )
else:
return "You are not privileged to access this dataset."
except Exception:
pass
return "A child named %s could not be found for data %s" % ( designation, parent_id )
@@ -176,9 +182,12 @@ class RootController( BaseController ):
"""Returns a file in a format that can successfully be displayed in display_app"""
data = self.app.model.HistoryDatasetAssociation.get( id )
if data:
trans.response.set_content_type(data.get_mime())
trans.log_event( "Formatted dataset id %s for display at %s" % ( str(id), display_app ) )
return data.as_display_type(display_app, **kwd)
if data.allow_action( trans.user, data.access_actions.VIEW ):
trans.response.set_content_type( data.get_mime() )
trans.log_event( "Formatted dataset id %s for display at %s" % ( str( id ), display_app ) )
return data.as_display_type( display_app, **kwd )
else:
return "You are not privileged to access this dataset."
else:
return "No data with id=%d" % id
@@ -206,69 +215,99 @@ class RootController( BaseController ):
data = self.app.model.HistoryDatasetAssociation.get( id )
if data is None:
return trans.show_error_message( "Problem retrieving dataset id %s with history id %s." % ( str( id ), str( hid ) ) )
p = util.Params(kwd, safe=False)
if p.change:
# The user clicked the Save button on the 'Change data type' form
trans.app.datatypes_registry.change_datatype( data, p.datatype )
trans.app.model.flush()
elif p.save:
# The user clicked the Save button on the 'Edit Attributes' form
data.name = p.name
data.info = p.info
if data.history.user is not None and data.history.user != trans.user:
return trans.show_error_message( "This instance of a dataset (%s) in a history does not belong to you." % ( data.id ) )
if data.allow_action( trans.user, data.access_actions.USE ):
p = util.Params(kwd, safe=False)
# The following for loop will save all metadata_spec items
for name, spec in data.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(data.metadata,name,None)
else:
setattr(data.metadata,name,spec.unwrap(p.get(name, None), p))
if p.change:
# The user clicked the Save button on the 'Change data type' form
trans.app.datatypes_registry.change_datatype( data, p.datatype )
trans.app.model.flush()
elif p.save:
# The user clicked the Save button on the 'Edit Attributes' form
data.name = p.name
data.info = p.info
# The following for loop will save all metadata_spec items
for name, spec in data.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(data.metadata,name,None)
else:
setattr(data.metadata,name,spec.unwrap(p.get(name, None), p))
data.datatype.after_edit( data )
trans.app.model.flush()
return trans.show_ok_message( "Attributes updated", refresh_frames=['history'] )
elif p.detect:
# The user clicked the Auto-detect button on the 'Edit Attributes' form
data.datatype.after_edit( data )
trans.app.model.flush()
return trans.show_ok_message( "Attributes updated", refresh_frames=['history'] )
elif p.detect:
# The user clicked the Auto-detect button on the 'Edit Attributes' form
for name, spec in data.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( data.metadata,name,spec.unwrap( spec.get( 'default' ), spec ))
data.datatype.set_meta( data )
data.datatype.after_edit( data )
trans.app.model.flush()
return trans.show_ok_message( "Attributes updated", refresh_frames=['history'] )
elif p.convert_data:
"""The user clicked the Convert button on the 'Convert to new format' form"""
target_type = kwd.get("target_type", None)
if target_type:
msg = data.datatype.convert_dataset(trans, data, target_type)
return trans.show_ok_message( msg, refresh_frames=['history'] )
elif p.change_permision:
"""The user clicked the change_permision button on the 'Change permissions' form"""
if not trans.user:
return trans.show_error_message( "You must be logged in if you want to change dataset permissions." )
private_dataset = 'private_dataset'
public_group = trans.app.model.GalaxyGroup.get( trans.app.model.GalaxyGroup.public_id )
if private_dataset in kwd and data.dataset.has_group( public_group ):
#check user has permision and then remove public group
if data.dataset.allow_action( trans.user, data.dataset.access_actions.REMOVE_GROUP ):
for assoc in data.dataset.groups:
if assoc.group_id == public_group.id:
assoc.delete()
assoc.flush()
else:
return trans.show_error_message( "You are not authorized to change this dataset's permissions." )
elif private_dataset not in kwd and not data.dataset.has_group( public_group ):
#check user has permision and then add public group
if data.dataset.allow_action( trans.user, data.dataset.access_actions.ADD_GROUP ):
public_group.add_dataset( data.dataset )
public_group.flush()
else:
return trans.show_error_message( "You are not authorized to change this dataset's permissions." )
else:
return trans.show_error_message( "You have not specified a valid change of permissions." )
return trans.show_ok_message( 'Permissions have been changed.', refresh_frames=['history'] )
data.datatype.before_edit( data )
if "dbkey" in data.datatype.metadata_spec and not data.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
data.metadata.dbkey = data.dbkey
metadata = list()
# a list of MetadataParemeters
for name, spec in data.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( data.metadata,name,spec.unwrap( spec.get( 'default' ), spec ))
data.datatype.set_meta( data )
data.datatype.after_edit( data )
trans.app.model.flush()
return trans.show_ok_message( "Attributes updated", refresh_frames=['history'] )
elif p.convert_data:
"""The user clicked the Convert button on the 'Convert to new format' form"""
target_type = kwd.get("target_type", None)
if target_type:
msg = data.datatype.convert_dataset(trans, data, target_type)
return trans.show_ok_message( msg, refresh_frames=['history'] )
data.datatype.before_edit( data )
if "dbkey" in data.datatype.metadata_spec and not data.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
data.metadata.dbkey = data.dbkey
metadata = list()
# a list of MetadataParemeters
for name, spec in data.datatype.metadata_spec.items():
if spec.visible:
metadata.append( spec.wrap( data.metadata.get(name), data ) )
# 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()
trans.log_event( "Opened edit view on dataset %s" % str(id) )
return trans.fill_template( "/dataset/edit_attributes.mako", data=data, metadata=metadata,
datatypes=ldatatypes, err=None )
if spec.visible:
metadata.append( spec.wrap( data.metadata.get(name), data ) )
# 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()
trans.log_event( "Opened edit view on dataset %s" % str(id) )
return trans.fill_template( "/dataset/edit_attributes.mako", data=data, metadata=metadata,
datatypes=ldatatypes, err=None )
else:
return trans.show_error_message( "You do not have permission to edit this dataset's (%s) attributes." % id )
@web.expose
def delete( self, trans, id = None, **kwd):
@@ -327,6 +366,8 @@ class RootController( BaseController ):
self.app.job_stop_queue.put( data.creating_job_associations[0].job )
except IndexError:
pass # upload tool will cause this since it doesn't have a job
else:
return "Dataset id '%s' is invalid" %str( id )
return "OK"
## ---- History management -----------------------------------------------
@@ -404,7 +445,7 @@ class RootController( BaseController ):
send_to_err = "You can't send histories to yourself"
else:
for history in histories:
new_history = history.copy()
new_history = history.copy( target_user=send_to_user )
new_history.name = history.name+" from "+user.email
new_history.user_id = send_to_user.id
trans.log_event( "History share, id: %s, name: '%s': to new id: %s" % (str(history.id), history.name, str(new_history.id)) )
@@ -441,7 +482,7 @@ class RootController( BaseController ):
if user:
if import_history.user_id == user.id:
return trans.show_error_message( "You cannot import your own history.")
new_history = import_history.copy()
new_history = import_history.copy( target_user=trans.user )
new_history.name = "imported: "+new_history.name
new_history.user_id = user.id
galaxy_session = trans.get_galaxy_session()
@@ -548,11 +589,17 @@ class RootController( BaseController ):
return trans.show_message( "<p>%s" % change_msg, refresh_frames=['history'] )
@web.expose
def history_add_to( self, trans, history_id=None, file_data=None, name="Data Added to History",info=None,ext="txt",dbkey="?",**kwd ):
def history_add_to( self, trans, history_id=None, file_data=None, name="Data Added to History",info=None,ext="txt",dbkey="?",copy_access_from=None,**kwd ):
"""Adds a POSTed file to a History"""
try:
history = trans.app.model.History.get( history_id )
data = trans.app.model.HistoryDatasetAssociation( name = name, info = info, extension = ext, dbkey = dbkey, create_dataset = True )
roles = history.default_roles
groups = history.default_groups
if copy_access_from:
copy_access_from = trans.app.model.HistoryDatasetAssociation.get( copy_access_from )
roles = copy_access_from.dataset.roles
groups = copy_access_from.dataset.groups
data = trans.app.model.HistoryDatasetAssociation( name = name, info = info, extension = ext, dbkey = dbkey, create_dataset = True, access_groups = groups, access_roles = roles )
data.flush()
data_file = open( data.file_name, "wb" )
file_data.file.seek( 0 )
@@ -569,7 +616,8 @@ class RootController( BaseController ):
data.flush()
trans.log_event("Added dataset %d to history %d" %(data.id, trans.history.id))
return trans.show_ok_message("Dataset "+str(data.hid)+" added to history "+str(history_id)+".")
except:
except Exception, e:
trans.log_event( "Failed to add dataset to history: %s" % ( e ) )
return trans.show_error_message("Adding File to History has Failed")
@web.expose
+4 -1
View File
@@ -197,7 +197,7 @@ class UniverseWebTransaction( base.DefaultWebTransaction ):
return self.new_history()
return self.__history
def new_history( self ):
history = self.app.model.History()
history = self.app.model.History( user = self.user )
# Make sure we have an id
history.flush()
# Immediately associate the new history with self
@@ -431,6 +431,9 @@ class UniverseWebTransaction( base.DefaultWebTransaction ):
galaxy_session.flush()
self.__galaxy_session = galaxy_session
if history is not None and user is not None:
if not history.user:
#This user will now aquire previously unowned history, let set permissions to user's default
history.set_default_access( roles = [ role.role for role in user.default_roles ], groups = [ group.group for group in user.default_groups ], dataset = True )
history.user_id = user.id
history.flush()
self.__history = history