mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merged from central.
This commit is contained in:
+6
-1
@@ -17,4 +17,9 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Some icons found in Galaxy are from the Silk Icons set, available under
|
||||
the Creative Commons Attribution 2.5 License, from:
|
||||
|
||||
http://www.famfamfam.com/lab/icons/silk/
|
||||
|
||||
@@ -4,6 +4,7 @@ from galaxy import config, jobs, util, tools, web
|
||||
import galaxy.model
|
||||
import galaxy.model.mapping
|
||||
import galaxy.datatypes.registry
|
||||
import galaxy.security
|
||||
|
||||
class UniverseApplication( object ):
|
||||
"""Encapsulates the state of a Universe application"""
|
||||
@@ -30,6 +31,8 @@ class UniverseApplication( object ):
|
||||
self.toolbox = tools.ToolBox( self.config.tool_config, self.config.tool_path, self )
|
||||
#Load datatype converters
|
||||
self.datatypes_registry.load_datatype_converters( self.toolbox )
|
||||
#Load security policy
|
||||
self.security_agent = self.model.security_agent
|
||||
# Start the job queue
|
||||
job_dispatcher = jobs.DefaultJobDispatcher( self )
|
||||
self.job_queue = jobs.JobQueue( self, job_dispatcher )
|
||||
|
||||
@@ -45,7 +45,7 @@ class Configuration( object ):
|
||||
self.job_scheduler_policy = kwargs.get("job_scheduler_policy", "FIFO")
|
||||
self.job_queue_cleanup_interval = int( kwargs.get("job_queue_cleanup_interval", "5") )
|
||||
self.job_working_directory = resolve_path( kwargs.get( "job_working_directory", "database/job_working_directory" ), self.root )
|
||||
self.admin_pass = kwargs.get('admin_pass',"galaxy")
|
||||
self.admin_users = kwargs.get( "admin_users", "" )
|
||||
self.sendmail_path = kwargs.get('sendmail_path',"/usr/sbin/sendmail")
|
||||
self.mailing_join_addr = kwargs.get('mailing_join_addr',"galaxy-user-join@bx.psu.edu")
|
||||
self.error_email_to = kwargs.get( 'error_email_to', None )
|
||||
@@ -64,6 +64,9 @@ class Configuration( object ):
|
||||
self.bugs_email = kwargs.get( 'bugs_email', None )
|
||||
self.blog_url = kwargs.get( 'blog_url', None )
|
||||
self.screencasts_url = kwargs.get( 'screencasts_url', None )
|
||||
self.library_import_dir = kwargs.get( 'library_import_dir', None )
|
||||
if self.library_import_dir is not None and not os.path.exists( self.library_import_dir ):
|
||||
raise ConfigurationError( "library_import_dir specified in config (%s) does not exist" % self.library_import_dir )
|
||||
# Parse global_conf and save the parser
|
||||
global_conf = kwargs.get( 'global_conf', None )
|
||||
global_conf_parser = ConfigParser.ConfigParser()
|
||||
|
||||
@@ -47,6 +47,9 @@ class Data( object ):
|
||||
"""Stores the set of display applications, and viewing methods, supported by this datatype """
|
||||
supported_display_apps = {}
|
||||
|
||||
"""If False, the peek is regenerated whenever a dataset of this type is copied"""
|
||||
copy_safe_peek = True
|
||||
|
||||
def __init__(self, **kwd):
|
||||
"""Initialize the datatype"""
|
||||
object.__init__(self, **kwd)
|
||||
|
||||
@@ -103,18 +103,22 @@ def create_applet_tag_peek( class_name, archive, params ):
|
||||
class Gmaj( data.Data ):
|
||||
"""Class describing a GMAJ Applet"""
|
||||
file_ext = "gmaj.zip"
|
||||
copy_safe_peek = False
|
||||
def set_peek( self, dataset ):
|
||||
params = {
|
||||
"bundle":"display?id=%s&tofile=yes&toext=.zip" % dataset.id,
|
||||
"buttonlabel": "Launch GMAJ",
|
||||
"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 } )
|
||||
}
|
||||
class_name = "edu.psu.bx.gmaj.MajApplet.class"
|
||||
archive = "/static/gmaj/gmaj.jar"
|
||||
dataset.peek = create_applet_tag_peek( class_name, archive, params )
|
||||
if hasattr( dataset, 'history_id' ):
|
||||
params = {
|
||||
"bundle":"display?id=%s&tofile=yes&toext=.zip" % dataset.id,
|
||||
"buttonlabel": "Launch GMAJ",
|
||||
"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, 'copy_access_from': dataset.id } )
|
||||
}
|
||||
class_name = "edu.psu.bx.gmaj.MajApplet.class"
|
||||
archive = "/static/gmaj/gmaj.jar"
|
||||
dataset.peek = create_applet_tag_peek( class_name, archive, params )
|
||||
else:
|
||||
dataset.peek = "After you add this item to your history, you will be able to launch the GMAJ applet."
|
||||
dataset.blurb = 'GMAJ Multiple Alignment Viewer'
|
||||
def display_peek(self, dataset):
|
||||
try:
|
||||
@@ -175,17 +179,21 @@ class Html( data.Text ):
|
||||
class Laj( data.Text ):
|
||||
"""Class describing a LAJ Applet"""
|
||||
file_ext = "laj"
|
||||
copy_safe_peek = False
|
||||
def set_peek( self, dataset ):
|
||||
params = {
|
||||
"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 } ),
|
||||
"noseq": "true"
|
||||
}
|
||||
class_name = "edu.psu.cse.bio.laj.LajApplet.class"
|
||||
archive = "/static/laj/laj.jar"
|
||||
dataset.peek = create_applet_tag_peek( class_name, archive, params )
|
||||
if hasattr( dataset, 'history_id' ):
|
||||
params = {
|
||||
"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, 'copy_access_from': dataset.id } ),
|
||||
"noseq": "true"
|
||||
}
|
||||
class_name = "edu.psu.cse.bio.laj.LajApplet.class"
|
||||
archive = "/static/laj/laj.jar"
|
||||
dataset.peek = create_applet_tag_peek( class_name, archive, params )
|
||||
else:
|
||||
dataset.peek = "After you add this item to your history, you will be able to launch the LAJ applet."
|
||||
dataset.blurb = 'LAJ Multiple Alignment Viewer'
|
||||
def display_peek(self, dataset):
|
||||
try:
|
||||
|
||||
+427
-244
@@ -13,6 +13,7 @@ from galaxy import util
|
||||
import tempfile
|
||||
import galaxy.datatypes.registry
|
||||
from galaxy.datatypes.metadata import MetadataCollection
|
||||
from galaxy.security import RBACAgent
|
||||
|
||||
import logging
|
||||
log = logging.getLogger( __name__ )
|
||||
@@ -33,13 +34,14 @@ class User( object ):
|
||||
self.external = False
|
||||
# Relationships
|
||||
self.histories = []
|
||||
|
||||
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()
|
||||
|
||||
|
||||
class Job( object ):
|
||||
"""
|
||||
A job represents a request to run a tool given input datasets, tool
|
||||
@@ -101,252 +103,69 @@ class JobToOutputDatasetAssociation( object ):
|
||||
self.name = name
|
||||
self.dataset = dataset
|
||||
|
||||
class HistoryDatasetAssociation( object ):
|
||||
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, copied_from_history_dataset_association = None, validation_errors=None, visible=True, create_dataset = False ):
|
||||
self.name = name or "Unnamed dataset"
|
||||
self.id = id
|
||||
self.hid = hid
|
||||
self.info = info
|
||||
self.blurb = blurb
|
||||
self.peek = peek
|
||||
self.extension = extension
|
||||
self.designation = designation
|
||||
self._metadata = metadata or dict()
|
||||
self.dbkey = dbkey
|
||||
self.deleted = deleted
|
||||
self.visible = visible
|
||||
# Relationships
|
||||
self.history = history
|
||||
if not dataset and create_dataset:
|
||||
dataset = Dataset()
|
||||
dataset.flush()
|
||||
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.parent_id = parent_id
|
||||
self.validation_errors = validation_errors
|
||||
self.copied_from_history_dataset_association = copied_from_history_dataset_association
|
||||
|
||||
@property
|
||||
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 ):
|
||||
self.dataset.state = state
|
||||
self.dataset.flush() #flush here, because hda.flush() won't flush the Dataset object
|
||||
state = property( get_dataset_state, set_dataset_state )
|
||||
|
||||
def get_file_name( self ):
|
||||
return self.dataset.get_file_name()
|
||||
|
||||
def set_file_name (self, filename):
|
||||
return self.dataset.set_file_name( filename )
|
||||
|
||||
file_name = property( get_file_name, set_file_name )
|
||||
|
||||
@property
|
||||
def extra_files_path( self ):
|
||||
return self.dataset.extra_files_path
|
||||
|
||||
@property
|
||||
def datatype( self ):
|
||||
return datatypes_registry.get_datatype_by_extension( self.extension )
|
||||
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 )
|
||||
|
||||
def get_metadata( self ):
|
||||
if not self._metadata:
|
||||
self._metadata = dict()
|
||||
return MetadataCollection( self, self.datatype.metadata_spec )
|
||||
def set_metadata( self, bunch ):
|
||||
# Needs to accept a MetadataCollection, a bunch, or a dict
|
||||
self._metadata = dict( bunch.items() )
|
||||
metadata = property( get_metadata, set_metadata )
|
||||
class Group( object ):
|
||||
public_id = None
|
||||
permitted_actions = galaxy.security.get_permitted_actions( 'GROUP' )
|
||||
def __init__( self, name = None, priority = 0 ):
|
||||
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.select_by( name='public' )[0]
|
||||
cls.set_public_group( group )
|
||||
|
||||
"""
|
||||
This provide backwards compatibility with using the old dbkey
|
||||
field in the database. That field now maps to "old_dbkey" (see mapping.py).
|
||||
"""
|
||||
def get_dbkey( self ):
|
||||
dbkey = self.metadata.dbkey
|
||||
if not isinstance(dbkey, list): dbkey = [dbkey]
|
||||
#if dbkey in [["?"], [None], []]: dbkey = [self.old_dbkey]
|
||||
if dbkey in [[None], []]: return "?"
|
||||
return dbkey[0]
|
||||
def set_dbkey( self, value ):
|
||||
if "dbkey" in self.datatype.metadata_spec:
|
||||
if not isinstance(value, list):
|
||||
self.metadata.dbkey = [value]
|
||||
else:
|
||||
self.metadata.dbkey = value
|
||||
#if isinstance(value, list):
|
||||
# self.old_dbkey = value[0]
|
||||
#else:
|
||||
# self.old_dbkey = value
|
||||
dbkey = property( get_dbkey, set_dbkey )
|
||||
|
||||
def change_datatype( self, new_ext ):
|
||||
self.clear_associated_files()
|
||||
datatypes_registry.change_datatype( self, new_ext )
|
||||
def get_size( self ):
|
||||
"""Returns the size of the data on disk"""
|
||||
return self.dataset.get_size()
|
||||
def set_size( self ):
|
||||
"""Returns the size of the data on disk"""
|
||||
return self.dataset.set_size()
|
||||
def has_data( self ):
|
||||
"""Detects whether there is any data"""
|
||||
return self.dataset.has_data()
|
||||
def get_raw_data( self ):
|
||||
"""Returns the full data. To stream it open the file_name and read/write as needed"""
|
||||
return self.datatype.get_raw_data( self )
|
||||
def write_from_stream( self, stream ):
|
||||
"""Writes data from a stream"""
|
||||
self.datatype.write_from_stream(self, stream)
|
||||
def set_raw_data( self, data ):
|
||||
"""Saves the data on the disc"""
|
||||
self.datatype.set_raw_data(self, data)
|
||||
def get_mime( self ):
|
||||
"""Returns the mime type of the data"""
|
||||
return datatypes_registry.get_mimetype_by_extension( self.extension.lower() )
|
||||
def set_peek( self ):
|
||||
return self.datatype.set_peek( self )
|
||||
def init_meta( self, copy_from=None ):
|
||||
return self.datatype.init_meta( self, copy_from=copy_from )
|
||||
def set_meta( self, **kwd ):
|
||||
self.clear_associated_files( metadata_safe = True )
|
||||
return self.datatype.set_meta( self, **kwd )
|
||||
def set_readonly_meta( self, **kwd ):
|
||||
return self.datatype.set_readonly_meta( self, **kwd )
|
||||
def missing_meta( self ):
|
||||
return self.datatype.missing_meta( self )
|
||||
def as_display_type( self, type, **kwd ):
|
||||
return self.datatype.as_display_type( self, type, **kwd )
|
||||
def display_peek( self ):
|
||||
return self.datatype.display_peek( self )
|
||||
def display_name( self ):
|
||||
return self.datatype.display_name( self )
|
||||
def display_info( self ):
|
||||
return self.datatype.display_info( self )
|
||||
def get_converted_files_by_type( self, file_type ):
|
||||
valid = []
|
||||
for assoc in self.implicitly_converted_datasets:
|
||||
if not assoc.deleted and assoc.type == file_type:
|
||||
valid.append( assoc.dataset )
|
||||
return valid
|
||||
def clear_associated_files( self, metadata_safe = False, purge = False ):
|
||||
#metadata_safe = True means to only clear when assoc.metadata_safe == False
|
||||
for assoc in self.implicitly_converted_datasets:
|
||||
if not metadata_safe or not assoc.metadata_safe:
|
||||
assoc.clear( purge = purge )
|
||||
def get_child_by_designation(self, designation):
|
||||
for child in self.children:
|
||||
if child.designation == designation:
|
||||
return child
|
||||
return None
|
||||
|
||||
def get_converter_types(self):
|
||||
return self.datatype.get_converter_types( self, datatypes_registry)
|
||||
|
||||
def copy( self, copy_children = False, parent_id = None ):
|
||||
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, copied_from_history_dataset_association = self )
|
||||
des.flush()
|
||||
if copy_children:
|
||||
for child in self.children:
|
||||
child_copy = child.copy( copy_children = copy_children, parent_id = des.id )
|
||||
des.set_peek() #in some instances peek relies on dataset_id, i.e. gmaj.zip for viewing MAFs
|
||||
des.flush()
|
||||
return des
|
||||
|
||||
def add_validation_error( self, validation_error ):
|
||||
self.validation_errors.append( validation_error )
|
||||
|
||||
def extend_validation_errors( self, validation_errors ):
|
||||
self.validation_errors.extend(validation_errors)
|
||||
|
||||
def mark_deleted( self, include_children=True ):
|
||||
self.deleted = True
|
||||
if include_children:
|
||||
for child in self.children:
|
||||
child.mark_deleted()
|
||||
|
||||
|
||||
|
||||
class History( object ):
|
||||
def __init__( self, id=None, name=None, user=None ):
|
||||
self.id = id
|
||||
self.name = name or "Unnamed history"
|
||||
self.deleted = False
|
||||
self.purged = False
|
||||
self.genome_build = None
|
||||
# Relationships
|
||||
class UserGroupAssociation( object ):
|
||||
def __init__( self, user, group ):
|
||||
self.user = user
|
||||
self.datasets = []
|
||||
self.galaxy_sessions = []
|
||||
|
||||
def _next_hid( self ):
|
||||
# TODO: override this with something in the database that ensures
|
||||
# better integrity
|
||||
if len( self.datasets ) == 0:
|
||||
return 1
|
||||
else:
|
||||
last_hid = 0
|
||||
for dataset in self.datasets:
|
||||
if dataset.hid > last_hid:
|
||||
last_hid = dataset.hid
|
||||
return last_hid + 1
|
||||
self.group = group
|
||||
|
||||
def add_galaxy_session( self, galaxy_session, association=None ):
|
||||
if association is None:
|
||||
self.galaxy_sessions.append( GalaxySessionToHistoryAssociation( galaxy_session, self ) )
|
||||
else:
|
||||
self.galaxy_sessions.append( association )
|
||||
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
|
||||
|
||||
def add_dataset( self, dataset, parent_id=None, genome_build=None, set_hid = True ):
|
||||
if isinstance( dataset, Dataset ):
|
||||
dataset = HistoryDatasetAssociation( dataset = dataset )
|
||||
dataset.flush()
|
||||
elif not isinstance( dataset, HistoryDatasetAssociation ):
|
||||
raise TypeError, "You can only add Dataset and HistoryDatasetAssociation instances to a history."
|
||||
if parent_id:
|
||||
for data in self.datasets:
|
||||
if data.id == parent_id:
|
||||
dataset.hid = data.hid
|
||||
break
|
||||
else:
|
||||
if set_hid: dataset.hid = self._next_hid()
|
||||
else:
|
||||
if set_hid: dataset.hid = self._next_hid()
|
||||
dataset.history = self
|
||||
if genome_build not in [None, '?']:
|
||||
self.genome_build = genome_build
|
||||
self.datasets.append( dataset )
|
||||
|
||||
def copy(self):
|
||||
des = History()
|
||||
des.flush()
|
||||
des.name = self.name
|
||||
des.user_id = self.user_id
|
||||
for data in self.datasets:
|
||||
new_data = data.copy( copy_children = True )
|
||||
des.add_dataset( new_data )
|
||||
new_data.flush()
|
||||
des.hid_counter = self.hid_counter
|
||||
des.flush()
|
||||
return des
|
||||
|
||||
# class Query( object ):
|
||||
# def __init__( self, name=None, state=None, tool_parameters=None, history=None ):
|
||||
# self.name = name or "Unnamed query"
|
||||
# self.state = state
|
||||
# self.tool_parameters = tool_parameters
|
||||
# # Relationships
|
||||
# self.history = history
|
||||
# self.datasets = []
|
||||
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 Dataset( object ):
|
||||
states = Bunch( NEW = 'new',
|
||||
@@ -356,6 +175,7 @@ class Dataset( object ):
|
||||
EMPTY = 'empty',
|
||||
ERROR = 'error',
|
||||
DISCARDED = 'discarded' )
|
||||
permitted_actions = galaxy.security.get_permitted_actions( 'DATASET' )
|
||||
file_path = "/tmp/"
|
||||
engine = None
|
||||
def __init__( self, id=None, state=None, external_filename=None, extra_files_path=None, file_size=None, purgable=True ):
|
||||
@@ -440,8 +260,362 @@ class Dataset( object ):
|
||||
except OSError, e:
|
||||
log.critical('%s delete error %s' % (self.__class__.__name__, e))
|
||||
|
||||
class Old_Dataset( Dataset ):
|
||||
pass
|
||||
class DatasetInstance( object ):
|
||||
"""A base class for all 'dataset instances', HDAs, LDAs, etc"""
|
||||
states = Dataset.states
|
||||
permitted_actions = Dataset.permitted_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 ):
|
||||
self.name = name or "Unnamed dataset"
|
||||
self.id = id
|
||||
self.info = info
|
||||
self.blurb = blurb
|
||||
self.peek = peek
|
||||
self.extension = extension
|
||||
self.dbkey = dbkey
|
||||
self.designation = designation
|
||||
self._metadata = metadata or dict()
|
||||
self.deleted = deleted
|
||||
self.visible = visible
|
||||
# Relationships
|
||||
if not dataset and create_dataset:
|
||||
dataset = Dataset()
|
||||
dataset.flush()
|
||||
self.dataset = dataset
|
||||
self.parent_id = parent_id
|
||||
self.validation_errors = validation_errors
|
||||
@property
|
||||
def ext( self ):
|
||||
return self.extension
|
||||
def get_dataset_state( self ):
|
||||
return self.dataset.state
|
||||
def set_dataset_state ( self, state ):
|
||||
self.dataset.state = state
|
||||
self.dataset.flush() #flush here, because hda.flush() won't flush the Dataset object
|
||||
state = property( get_dataset_state, set_dataset_state )
|
||||
def get_file_name( self ):
|
||||
return self.dataset.get_file_name()
|
||||
def set_file_name (self, filename):
|
||||
return self.dataset.set_file_name( filename )
|
||||
file_name = property( get_file_name, set_file_name )
|
||||
@property
|
||||
def extra_files_path( self ):
|
||||
return self.dataset.extra_files_path
|
||||
@property
|
||||
def datatype( self ):
|
||||
return datatypes_registry.get_datatype_by_extension( self.extension )
|
||||
def get_metadata( self ):
|
||||
if not self._metadata:
|
||||
self._metadata = dict()
|
||||
return MetadataCollection( self, self.datatype.metadata_spec )
|
||||
def set_metadata( self, bunch ):
|
||||
# Needs to accept a MetadataCollection, a bunch, or a dict
|
||||
self._metadata = dict( bunch.items() )
|
||||
metadata = property( get_metadata, set_metadata )
|
||||
# This provide backwards compatibility with using the old dbkey
|
||||
# field in the database. That field now maps to "old_dbkey" (see mapping.py).
|
||||
def get_dbkey( self ):
|
||||
dbkey = self.metadata.dbkey
|
||||
if not isinstance(dbkey, list): dbkey = [dbkey]
|
||||
#if dbkey in [["?"], [None], []]: dbkey = [self.old_dbkey]
|
||||
if dbkey in [[None], []]: return "?"
|
||||
return dbkey[0]
|
||||
def set_dbkey( self, value ):
|
||||
if "dbkey" in self.datatype.metadata_spec:
|
||||
if not isinstance(value, list):
|
||||
self.metadata.dbkey = [value]
|
||||
else:
|
||||
self.metadata.dbkey = value
|
||||
#if isinstance(value, list):
|
||||
# self.old_dbkey = value[0]
|
||||
#else:
|
||||
# self.old_dbkey = value
|
||||
dbkey = property( get_dbkey, set_dbkey )
|
||||
def change_datatype( self, new_ext ):
|
||||
self.clear_associated_files()
|
||||
datatypes_registry.change_datatype( self, new_ext )
|
||||
def get_size( self ):
|
||||
"""Returns the size of the data on disk"""
|
||||
return self.dataset.get_size()
|
||||
def set_size( self ):
|
||||
"""Returns the size of the data on disk"""
|
||||
return self.dataset.set_size()
|
||||
def has_data( self ):
|
||||
"""Detects whether there is any data"""
|
||||
return self.dataset.has_data()
|
||||
def get_raw_data( self ):
|
||||
"""Returns the full data. To stream it open the file_name and read/write as needed"""
|
||||
return self.datatype.get_raw_data( self )
|
||||
def write_from_stream( self, stream ):
|
||||
"""Writes data from a stream"""
|
||||
self.datatype.write_from_stream(self, stream)
|
||||
def set_raw_data( self, data ):
|
||||
"""Saves the data on the disc"""
|
||||
self.datatype.set_raw_data(self, data)
|
||||
def get_mime( self ):
|
||||
"""Returns the mime type of the data"""
|
||||
return datatypes_registry.get_mimetype_by_extension( self.extension.lower() )
|
||||
def set_peek( self ):
|
||||
return self.datatype.set_peek( self )
|
||||
def init_meta( self, copy_from=None ):
|
||||
return self.datatype.init_meta( self, copy_from=copy_from )
|
||||
def set_meta( self, **kwd ):
|
||||
self.clear_associated_files( metadata_safe = True )
|
||||
return self.datatype.set_meta( self, **kwd )
|
||||
def set_readonly_meta( self, **kwd ):
|
||||
return self.datatype.set_readonly_meta( self, **kwd )
|
||||
def missing_meta( self ):
|
||||
return self.datatype.missing_meta( self )
|
||||
def as_display_type( self, type, **kwd ):
|
||||
return self.datatype.as_display_type( self, type, **kwd )
|
||||
def display_peek( self ):
|
||||
return self.datatype.display_peek( self )
|
||||
def display_name( self ):
|
||||
return self.datatype.display_name( self )
|
||||
def display_info( self ):
|
||||
return self.datatype.display_info( self )
|
||||
def get_converted_files_by_type( self, file_type ):
|
||||
valid = []
|
||||
for assoc in self.implicitly_converted_datasets:
|
||||
if not assoc.deleted and assoc.type == file_type:
|
||||
valid.append( assoc.dataset )
|
||||
return valid
|
||||
def clear_associated_files( self, metadata_safe = False, purge = False ):
|
||||
raise 'Unimplemented'
|
||||
def get_child_by_designation(self, designation):
|
||||
for child in self.children:
|
||||
if child.designation == designation:
|
||||
return child
|
||||
return None
|
||||
def get_converter_types(self):
|
||||
return self.datatype.get_converter_types( self, datatypes_registry)
|
||||
def add_validation_error( self, validation_error ):
|
||||
self.validation_errors.append( validation_error )
|
||||
def extend_validation_errors( self, validation_errors ):
|
||||
self.validation_errors.extend(validation_errors)
|
||||
def mark_deleted( self, include_children=True ):
|
||||
self.deleted = True
|
||||
if include_children:
|
||||
for child in self.children:
|
||||
child.mark_deleted()
|
||||
|
||||
class HistoryDatasetAssociation( DatasetInstance ):
|
||||
def __init__( self,
|
||||
hid = None,
|
||||
history = None,
|
||||
copied_from_history_dataset_association = None,
|
||||
copied_from_library_folder_dataset_association = None,
|
||||
**kwd ):
|
||||
DatasetInstance.__init__( self, **kwd )
|
||||
self.hid = hid
|
||||
# Relationships
|
||||
self.history = history
|
||||
self.copied_from_history_dataset_association = copied_from_history_dataset_association
|
||||
self.copied_from_library_folder_dataset_association = copied_from_library_folder_dataset_association
|
||||
def copy( self, copy_children = False, parent_id = None, target_history = None ):
|
||||
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,
|
||||
copied_from_history_dataset_association=self,
|
||||
history = target_history )
|
||||
des.flush()
|
||||
if copy_children:
|
||||
for child in self.children:
|
||||
child_copy = child.copy( copy_children = copy_children, parent_id = des.id )
|
||||
if not self.datatype.copy_safe_peek:
|
||||
des.set_peek() #in some instances peek relies on dataset_id, i.e. gmaj.zip for viewing MAFs
|
||||
des.flush()
|
||||
return des
|
||||
def clear_associated_files( self, metadata_safe = False, purge = False ):
|
||||
#metadata_safe = True means to only clear when assoc.metadata_safe == False
|
||||
for assoc in self.implicitly_converted_datasets:
|
||||
if not metadata_safe or not assoc.metadata_safe:
|
||||
assoc.clear( purge = purge )
|
||||
|
||||
class History( object ):
|
||||
def __init__( self, id=None, name=None, user=None ):
|
||||
self.id = id
|
||||
self.name = name or "Unnamed history"
|
||||
self.deleted = False
|
||||
self.purged = False
|
||||
self.genome_build = None
|
||||
# Relationships
|
||||
self.user = user
|
||||
self.datasets = []
|
||||
self.galaxy_sessions = []
|
||||
def _next_hid( self ):
|
||||
# TODO: override this with something in the database that ensures
|
||||
# better integrity
|
||||
if len( self.datasets ) == 0:
|
||||
return 1
|
||||
else:
|
||||
last_hid = 0
|
||||
for dataset in self.datasets:
|
||||
if dataset.hid > last_hid:
|
||||
last_hid = dataset.hid
|
||||
return last_hid + 1
|
||||
def add_galaxy_session( self, galaxy_session, association=None ):
|
||||
if association is None:
|
||||
self.galaxy_sessions.append( GalaxySessionToHistoryAssociation( galaxy_session, self ) )
|
||||
else:
|
||||
self.galaxy_sessions.append( association )
|
||||
def add_dataset( self, dataset, parent_id=None, genome_build=None, set_hid = True ):
|
||||
if isinstance( dataset, Dataset ):
|
||||
dataset = HistoryDatasetAssociation( dataset = dataset )
|
||||
dataset.flush()
|
||||
elif not isinstance( dataset, HistoryDatasetAssociation ):
|
||||
raise TypeError, "You can only add Dataset and HistoryDatasetAssociation instances to a history."
|
||||
if parent_id:
|
||||
for data in self.datasets:
|
||||
if data.id == parent_id:
|
||||
dataset.hid = data.hid
|
||||
break
|
||||
else:
|
||||
if set_hid: dataset.hid = self._next_hid()
|
||||
else:
|
||||
if set_hid: dataset.hid = self._next_hid()
|
||||
dataset.history = self
|
||||
if genome_build not in [None, '?']:
|
||||
self.genome_build = genome_build
|
||||
self.datasets.append( dataset )
|
||||
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
|
||||
for data in self.datasets:
|
||||
new_data = data.copy( copy_children = True, target_history = des )
|
||||
des.add_dataset( new_data, set_hid = False )
|
||||
new_data.flush()
|
||||
des.hid_counter = self.hid_counter
|
||||
des.flush()
|
||||
return des
|
||||
|
||||
class Library( object ):
|
||||
def __init__( self, name = None, description = None, root_folder = None ):
|
||||
self.name = name or "Unnamed library"
|
||||
self.description = description
|
||||
self.root_folder = root_folder
|
||||
|
||||
class LibraryFolder( object ):
|
||||
def __init__( self, name = None, description = None, item_count = 0, order_id = None ):
|
||||
self.name = name or "Unnamed folder"
|
||||
self.description = description
|
||||
self.item_count = item_count
|
||||
self.order_id = order_id
|
||||
self.genome_build = None
|
||||
def add_dataset( self, dataset, genome_build=None ):
|
||||
dataset.folder_id = self.id
|
||||
dataset.order_id = self.item_count
|
||||
self.item_count += 1
|
||||
if genome_build not in [None, '?']:
|
||||
self.genome_build = genome_build
|
||||
def add_folder( self, folder ):
|
||||
folder.parent_id = self.id
|
||||
folder.order_id = self.item_count
|
||||
self.item_count += 1
|
||||
|
||||
@property
|
||||
def active_components( self ):
|
||||
return list( self.active_folders ) + list( self.active_datasets )
|
||||
|
||||
class LibraryFolderDatasetAssociation( DatasetInstance ):
|
||||
def __init__( self,
|
||||
folder = None,
|
||||
order_id = None,
|
||||
copied_from_history_dataset_association = None,
|
||||
copied_from_library_folder_dataset_association = None,
|
||||
**kwd ):
|
||||
DatasetInstance.__init__( self, **kwd )
|
||||
self.folder = folder
|
||||
self.order_id = order_id
|
||||
self.copied_from_history_dataset_association = copied_from_history_dataset_association
|
||||
self.copied_from_library_folder_dataset_association = copied_from_library_folder_dataset_association
|
||||
def to_history_dataset_association( self, parent_id = None, target_history = None ):
|
||||
if target_history:
|
||||
hid = target_history._next_hid()
|
||||
else:
|
||||
hid = None
|
||||
des = HistoryDatasetAssociation( 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,
|
||||
copied_from_library_folder_dataset_association = self,
|
||||
history = target_history,
|
||||
hid = hid )
|
||||
des.flush()
|
||||
for child in self.children:
|
||||
child_copy = child.to_history_dataset_association( parent_id = des.id )
|
||||
if not self.datatype.copy_safe_peek:
|
||||
des.set_peek() #in some instances peek relies on dataset_id, i.e. gmaj.zip for viewing MAFs
|
||||
des.flush()
|
||||
return des
|
||||
def copy( self, copy_children = False, parent_id = None, target_folder = None ):
|
||||
des = LibraryFolderDatasetAssociation( 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,
|
||||
copied_from_library_folder_dataset_association = self,
|
||||
folder = target_folder )
|
||||
des.flush()
|
||||
if copy_children:
|
||||
for child in self.children:
|
||||
child_copy = child.copy( copy_children = copy_children, parent_id = des.id )
|
||||
if not self.datatype.copy_safe_peek:
|
||||
des.set_peek() #in some instances peek relies on dataset_id, i.e. gmaj.zip for viewing MAFs
|
||||
des.flush()
|
||||
return des
|
||||
def clear_associated_files( self, metadata_safe = False, purge = False ):
|
||||
return
|
||||
|
||||
class LibraryTag( object ):
|
||||
def __init__( self, tag ):
|
||||
self.tag = tag
|
||||
|
||||
class LibraryTagFolderAssociation( object ):
|
||||
def __init__( self, tag, folder ):
|
||||
self.tag = tag
|
||||
self.folder = folder
|
||||
|
||||
class LibraryTagDatasetAssociation( object ):
|
||||
def __init__( self, tag, dataset ):
|
||||
self.tag = tag
|
||||
self.dataset = dataset
|
||||
|
||||
# class Query( object ):
|
||||
# def __init__( self, name=None, state=None, tool_parameters=None, history=None ):
|
||||
# self.name = name or "Unnamed query"
|
||||
# self.state = state
|
||||
# self.tool_parameters = tool_parameters
|
||||
# # Relationships
|
||||
# self.history = history
|
||||
# self.datasets = []
|
||||
|
||||
|
||||
class ValidationError( object ):
|
||||
def __init__( self, message=None, err_type=None, attributes=None ):
|
||||
@@ -483,7 +657,16 @@ class Event( object ):
|
||||
self.message = message
|
||||
|
||||
class GalaxySession( object ):
|
||||
def __init__( self, id=None, user=None, remote_host=None, remote_addr=None, referer=None, current_history_id=None, session_key=None, is_valid=False, prev_session_id=None ):
|
||||
def __init__( self,
|
||||
id=None,
|
||||
user=None,
|
||||
remote_host=None,
|
||||
remote_addr=None,
|
||||
referer=None,
|
||||
current_history_id=None,
|
||||
session_key=None,
|
||||
is_valid=False,
|
||||
prev_session_id=None ):
|
||||
self.id = id
|
||||
self.user = user
|
||||
self.remote_host = remote_host
|
||||
|
||||
+200
-2
@@ -19,6 +19,7 @@ from sqlalchemy import *
|
||||
from galaxy.model import *
|
||||
from galaxy.model.custom_types import *
|
||||
from galaxy.util.bunch import Bunch
|
||||
from galaxy.security import GalaxyRBACAgent
|
||||
|
||||
metadata = DynamicMetaData( threadlocal=False )
|
||||
context = SessionContext( create_session )
|
||||
@@ -65,7 +66,6 @@ History.table = Table( "history", metadata,
|
||||
# Column( "state", String( 64 ) ),
|
||||
# Column( "tool_parameters", Pickle() ) )
|
||||
|
||||
|
||||
HistoryDatasetAssociation.table = Table( "history_dataset_association", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ),
|
||||
@@ -73,6 +73,7 @@ HistoryDatasetAssociation.table = Table( "history_dataset_association", metadata
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "copied_from_history_dataset_association_id", Integer, ForeignKey( "history_dataset_association.id" ), nullable=True ),
|
||||
Column( "copied_from_library_folder_dataset_association_id", Integer, ForeignKey( "library_folder_dataset_association.id" ), nullable=True ),
|
||||
Column( "hid", Integer ),
|
||||
Column( "name", TrimmedString( 255 ) ),
|
||||
Column( "info", TrimmedString( 255 ) ),
|
||||
@@ -114,6 +115,109 @@ ValidationError.table = Table( "validation_error", metadata,
|
||||
Column( "err_type", TrimmedString( 64 ) ),
|
||||
Column( "attributes", TEXT ) )
|
||||
|
||||
Group.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, index=True, unique=True ),
|
||||
Column( "priority", Integer ),
|
||||
Column( "deleted", Boolean, index=True, default=False ) )
|
||||
|
||||
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 ) )
|
||||
|
||||
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 ),
|
||||
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( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "permitted_actions", JSONType(), default=[] ) )
|
||||
|
||||
# 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,
|
||||
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 ),
|
||||
Column( "permitted_actions", JSONType(), default=[] ) )
|
||||
|
||||
LibraryFolderDatasetAssociation.table = Table( "library_folder_dataset_association", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "dataset_id", Integer, ForeignKey( "dataset.id" ), index=True ),
|
||||
Column( "folder_id", Integer, ForeignKey( "library_folder.id" ), index=True ),
|
||||
Column( "order_id", Integer ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "copied_from_history_dataset_association_id", Integer, ForeignKey( "history_dataset_association.id", use_alter=True, name='history_dataset_association_dataset_id_fkey' ), nullable=True ),
|
||||
Column( "copied_from_library_folder_dataset_association_id", Integer, ForeignKey( "library_folder_dataset_association.id", use_alter=True, name='library_folder_dataset_association_id_fkey' ), nullable=True ),
|
||||
Column( "name", TrimmedString( 255 ) ),
|
||||
Column( "info", TrimmedString( 255 ) ),
|
||||
Column( "blurb", TrimmedString( 255 ) ),
|
||||
Column( "peek" , TEXT ),
|
||||
Column( "extension", TrimmedString( 64 ) ),
|
||||
Column( "metadata", MetadataType(), key="_metadata" ),
|
||||
Column( "parent_id", Integer, ForeignKey( "library_folder_dataset_association.id" ), nullable=True ),
|
||||
Column( "designation", TrimmedString( 255 ) ),
|
||||
Column( "deleted", Boolean, index=True, default=False ),
|
||||
Column( "visible", Boolean ) )
|
||||
|
||||
Library.table = Table( "library", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "root_folder_id", Integer, ForeignKey( "library_folder.id" ), index=True ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "name", TEXT, index=True ),
|
||||
Column( "deleted", Boolean, index=True, default=False ),
|
||||
Column( "description", TEXT ) )
|
||||
|
||||
LibraryFolder.table = Table( "library_folder", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "parent_id", Integer, ForeignKey( "library_folder.id" ), nullable = True, index=True ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "name", TEXT ),
|
||||
Column( "description", TEXT ),
|
||||
Column( "order_id", Integer ),
|
||||
Column( "item_count", Integer ),
|
||||
Column( "deleted", Boolean, index=True, default=False ),
|
||||
Column( "genome_build", TrimmedString( 40 ) ) )
|
||||
|
||||
LibraryTag.table = Table( "library_tag", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ),
|
||||
Column( "text", TEXT ) )
|
||||
|
||||
LibraryTagFolderAssociation.table = Table( "library_tag_folder_association", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "folder_id", Integer, ForeignKey( "library_folder.id" ), index=True ),
|
||||
Column( "tag_id", Integer, ForeignKey( "library_tag.id" ), index=True ),
|
||||
Column( "create_time", DateTime, default=now ),
|
||||
Column( "update_time", DateTime, default=now, onupdate=now ) )
|
||||
|
||||
LibraryTagDatasetAssociation.table = Table( "library_tag_dataset_association", metadata,
|
||||
Column( "id", Integer, primary_key=True ),
|
||||
Column( "dataset_id", Integer, ForeignKey( "library_folder_dataset_association.id" ), index=True ),
|
||||
Column( "tag_id", Integer, ForeignKey( "library_tag.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 ),
|
||||
@@ -255,6 +359,10 @@ assign_mapper( context, HistoryDatasetAssociation, HistoryDatasetAssociation.tab
|
||||
HistoryDatasetAssociation,
|
||||
primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == HistoryDatasetAssociation.table.c.id ),
|
||||
backref=backref( "copied_from_history_dataset_association", primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == HistoryDatasetAssociation.table.c.id ), remote_side=[HistoryDatasetAssociation.table.c.id] ) ),
|
||||
copied_to_library_folder_dataset_associations=relation(
|
||||
LibraryFolderDatasetAssociation,
|
||||
primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_library_folder_dataset_association_id == LibraryFolderDatasetAssociation.table.c.id ),
|
||||
backref=backref( "copied_from_history_dataset_association", primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_library_folder_dataset_association_id == LibraryFolderDatasetAssociation.table.c.id ), remote_side=[LibraryFolderDatasetAssociation.table.c.id] ) ),
|
||||
implicitly_converted_datasets=relation(
|
||||
ImplicitlyConvertedDatasetAssociation,
|
||||
primaryjoin=( ImplicitlyConvertedDatasetAssociation.table.c.hda_parent_id == HistoryDatasetAssociation.table.c.id ) ),
|
||||
@@ -268,7 +376,10 @@ assign_mapper( context, Dataset, Dataset.table,
|
||||
properties=dict(
|
||||
history_associations=relation(
|
||||
HistoryDatasetAssociation,
|
||||
primaryjoin=( Dataset.table.c.id == HistoryDatasetAssociation.table.c.dataset_id ) )
|
||||
primaryjoin=( Dataset.table.c.id == HistoryDatasetAssociation.table.c.dataset_id ) ),
|
||||
library_associations=relation(
|
||||
LibraryFolderDatasetAssociation,
|
||||
primaryjoin=( Dataset.table.c.id == LibraryFolderDatasetAssociation.table.c.dataset_id ) )
|
||||
) )
|
||||
|
||||
|
||||
@@ -298,6 +409,84 @@ assign_mapper( context, User, User.table,
|
||||
collection_class=ordering_list( 'order_index' ) )
|
||||
) )
|
||||
|
||||
assign_mapper( context, Group, Group.table,
|
||||
properties=dict( users=relation( UserGroupAssociation ),
|
||||
datasets=relation( GroupDatasetAssociation ) ) )
|
||||
|
||||
assign_mapper( context, UserGroupAssociation, UserGroupAssociation.table,
|
||||
properties=dict( user=relation( User, backref = "groups" ),
|
||||
group=relation( Group, backref = "users" ) ) )
|
||||
|
||||
assign_mapper( context, GroupDatasetAssociation, GroupDatasetAssociation.table,
|
||||
properties=dict( dataset=relation( Dataset, backref = "groups" ),
|
||||
group=relation( Group, backref = "datasets" ) ) )
|
||||
|
||||
assign_mapper( context, DefaultUserGroupAssociation, DefaultUserGroupAssociation.table,
|
||||
properties=dict( user=relation( User, backref = "default_groups" ),
|
||||
group=relation( Group ) ) )
|
||||
|
||||
assign_mapper( context, DefaultHistoryGroupAssociation, DefaultHistoryGroupAssociation.table,
|
||||
properties=dict( history=relation( History, backref = "default_groups" ),
|
||||
group=relation( Group ) ) )
|
||||
|
||||
assign_mapper( context, Library, Library.table,
|
||||
properties=dict(
|
||||
root_folder=relation( LibraryFolder,
|
||||
backref = backref( "library_root" ) )
|
||||
) )
|
||||
|
||||
assign_mapper( context, LibraryFolder, LibraryFolder.table,
|
||||
properties=dict(
|
||||
folders=relation(
|
||||
LibraryFolder,
|
||||
primaryjoin=( LibraryFolder.table.c.parent_id == LibraryFolder.table.c.id ),
|
||||
backref=backref( "parent", primaryjoin=( LibraryFolder.table.c.parent_id == LibraryFolder.table.c.id ), remote_side=[LibraryFolder.table.c.id] ) ),
|
||||
active_folders=relation( LibraryFolder,
|
||||
primaryjoin=( ( LibraryFolder.table.c.parent_id == LibraryFolder.table.c.id ) & ( not_( LibraryFolder.table.c.deleted ) ) ),
|
||||
order_by=asc( LibraryFolder.table.c.order_id ),
|
||||
lazy=True, #"""sqlalchemy.exceptions.ArgumentError: Error creating eager relationship 'active_folders' on parent class '<class 'galaxy.model.LibraryFolder'>' to child class '<class 'galaxy.model.LibraryFolder'>': Cant use eager loading on a self referential relationship."""
|
||||
viewonly=True ),
|
||||
active_datasets=relation( LibraryFolderDatasetAssociation,
|
||||
primaryjoin=( ( LibraryFolderDatasetAssociation.table.c.folder_id == LibraryFolder.table.c.id ) & ( not_( LibraryFolderDatasetAssociation.table.c.deleted ) ) ),
|
||||
order_by=asc( LibraryFolderDatasetAssociation.table.c.order_id ),
|
||||
lazy=False,
|
||||
viewonly=True ),
|
||||
tags=relation(
|
||||
LibraryTagFolderAssociation,
|
||||
primaryjoin=( LibraryFolder.table.c.id == LibraryTagFolderAssociation.table.c.folder_id ),
|
||||
backref=backref( "folders" ) )
|
||||
) )
|
||||
|
||||
assign_mapper( context, LibraryFolderDatasetAssociation, LibraryFolderDatasetAssociation.table,
|
||||
properties=dict(
|
||||
dataset=relation( Dataset ),
|
||||
folder=relation(
|
||||
LibraryFolder,
|
||||
backref=backref( "datasets" ) ),
|
||||
copied_to_library_folder_dataset_associations=relation(
|
||||
LibraryFolderDatasetAssociation,
|
||||
primaryjoin=( LibraryFolderDatasetAssociation.table.c.copied_from_library_folder_dataset_association_id == LibraryFolderDatasetAssociation.table.c.id ),
|
||||
backref=backref( "copied_from_library_folder_dataset_association", primaryjoin=( LibraryFolderDatasetAssociation.table.c.copied_from_library_folder_dataset_association_id == LibraryFolderDatasetAssociation.table.c.id ), remote_side=[LibraryFolderDatasetAssociation.table.c.id] ) ),
|
||||
children=relation(
|
||||
LibraryFolderDatasetAssociation,
|
||||
primaryjoin=( LibraryFolderDatasetAssociation.table.c.parent_id == LibraryFolderDatasetAssociation.table.c.id ),
|
||||
backref=backref( "parent", primaryjoin=( LibraryFolderDatasetAssociation.table.c.parent_id == LibraryFolderDatasetAssociation.table.c.id ), remote_side=[LibraryFolderDatasetAssociation.table.c.id] ) ),
|
||||
tags=relation(
|
||||
LibraryTagDatasetAssociation,
|
||||
primaryjoin=( LibraryFolderDatasetAssociation.table.c.id == LibraryTagDatasetAssociation.table.c.dataset_id ),
|
||||
backref=backref( "datasets" ) )
|
||||
) )
|
||||
|
||||
assign_mapper( context, LibraryTag, LibraryTag.table )
|
||||
|
||||
assign_mapper( context, LibraryTagFolderAssociation, LibraryTagFolderAssociation.table,
|
||||
properties=dict( tag=relation( LibraryTag ),
|
||||
folder=relation( LibraryFolder ) ) )
|
||||
|
||||
assign_mapper( context, LibraryTagDatasetAssociation, LibraryTagDatasetAssociation.table,
|
||||
properties=dict( tag=relation( LibraryTag ),
|
||||
dataset=relation( LibraryFolderDatasetAssociation ) ) )
|
||||
|
||||
assign_mapper( context, JobToInputDatasetAssociation, JobToInputDatasetAssociation.table,
|
||||
properties=dict( job=relation( Job ), dataset=relation( HistoryDatasetAssociation ) ) )
|
||||
|
||||
@@ -411,6 +600,15 @@ 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
|
||||
#load local galaxy security policy
|
||||
result.security_agent = GalaxyRBACAgent( result )
|
||||
# Ensure group named 'public' exists
|
||||
public_group = result.Group.get_by( name='public' )
|
||||
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 ) )
|
||||
return result
|
||||
|
||||
def get_suite():
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
"""
|
||||
Galaxy Security
|
||||
|
||||
"""
|
||||
import logging
|
||||
from galaxy.util.bunch import Bunch
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
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"
|
||||
)
|
||||
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 ):
|
||||
raise "Unimplemented Method"
|
||||
def user_set_default_access( 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 ):
|
||||
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 ):
|
||||
return bool( self.get_component_associations( **kwd ) )
|
||||
def convert_permitted_action_strings( self, permitted_action_strings ):
|
||||
"""
|
||||
When getting permitted actions from an untrusted source like a
|
||||
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 ):
|
||||
self.model = model
|
||||
if permitted_actions:
|
||||
self.permitted_actions = permitted_actions
|
||||
def allow_action( self, user, action, **kwd ):
|
||||
if 'dataset' in kwd:
|
||||
return self.allow_dataset_action( user, action, kwd['dataset'] )
|
||||
raise 'No valid method of checking action (%s) on %s for user %s.' % ( action, kwd, user )
|
||||
def allow_dataset_action( self, user, action, dataset ):
|
||||
"""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
|
||||
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
|
||||
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 ):
|
||||
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 %s' % ( id )
|
||||
def create_group( self, **kwd ):
|
||||
rval = self.model.Group( **kwd )
|
||||
rval.flush()
|
||||
return rval
|
||||
raise 'No valid method of creating group with %s' % ( kwd )
|
||||
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:
|
||||
if 'group' in kwd:
|
||||
return self.associate_user_group( kwd['user'], kwd['group'] )
|
||||
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:
|
||||
for assoc in user.default_groups: #this is the association not the actual group
|
||||
assoc.delete()
|
||||
assoc.flush()
|
||||
for group, permitted_actions in permissions:
|
||||
assoc = self.model.DefaultUserGroupAssociation( user, group, permitted_actions )
|
||||
assoc.flush()
|
||||
if history:
|
||||
for history in user.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:
|
||||
for assoc in history.default_groups: #this is the association not the actual group
|
||||
assoc.delete()
|
||||
assoc.flush()
|
||||
for group, permitted_actions in permissions:
|
||||
assoc = self.model.DefaultHistoryGroupAssociation( history, group, permitted_actions )
|
||||
assoc.flush()
|
||||
if dataset:
|
||||
for data in history.datasets:
|
||||
for hda in data.dataset.history_associations:
|
||||
if history.user and hda.history not in history.user.histories:
|
||||
# This will occur when a user logs in and has datasets in their previously-public history.
|
||||
self.set_dataset_permissions( data.dataset, [ ( self.get_public_group(), [ self.permitted_actions.DATASET_ACCESS ] ) ] )
|
||||
break
|
||||
else:
|
||||
if self.allow_action( history.user, self.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=data.dataset ):
|
||||
self.set_dataset_permissions( data.dataset, permissions )
|
||||
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 ):
|
||||
"""
|
||||
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
|
||||
for group_dataset_assoc in dataset.groups:
|
||||
group_dataset_assoc.delete()
|
||||
group_dataset_assoc.flush()
|
||||
if len( 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 ):
|
||||
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 ]
|
||||
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.get_by( group_id = kwd['group'].id, dataset_id = kwd['dataset'].id )
|
||||
elif 'user' in kwd:
|
||||
if 'group' in kwd:
|
||||
return self.model.UserGroupAssociation.get_by( group_id = kwd['group'].id, user_id = kwd['user'].id )
|
||||
raise 'No valid method of associating provided components: %s' % kwd
|
||||
def dataset_has_group( self, dataset_id, group_id ):
|
||||
return bool( self.model.GroupDatasetAssociation.get_by( group_id = group_id, dataset_id = dataset_id ) )
|
||||
def check_folder_contents( self, user, entry ):
|
||||
"""
|
||||
Return true if there are any datasets under 'folder' that the
|
||||
user has access permission on. We do this a lot and it's a
|
||||
pretty inefficient method, optimizations are welcomed.
|
||||
"""
|
||||
if isinstance( entry, self.model.Library ):
|
||||
return self.check_folder_contents( user, entry.root_folder )
|
||||
elif isinstance( entry, self.model.LibraryFolderDatasetAssociation ):
|
||||
return self.allow_action( user, self.permitted_actions.DATASET_ACCESS, dataset=entry )
|
||||
elif isinstance( entry, self.model.LibraryFolder ):
|
||||
for dataset in entry.active_datasets:
|
||||
if self.allow_action( user, self.permitted_actions.DATASET_ACCESS, dataset=dataset ):
|
||||
return True
|
||||
for folder in entry.active_folders:
|
||||
if self.check_folder_contents( user, folder ):
|
||||
return True
|
||||
return False
|
||||
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:
|
||||
return RBACAgent.permitted_actions
|
||||
if not filter.endswith('_'):
|
||||
filter += '_'
|
||||
tmp_bunch = Bunch()
|
||||
[tmp_bunch.__dict__.__setitem__(k, v) for k, v in RBACAgent.permitted_actions.items() if k.startswith(filter)]
|
||||
return tmp_bunch
|
||||
@@ -1085,6 +1085,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 )
|
||||
# Move data from temp location to dataset location
|
||||
shutil.move( filename, child_dataset.file_name )
|
||||
child_dataset.flush()
|
||||
@@ -1121,6 +1122,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 )
|
||||
primary_data.flush()
|
||||
# Move data from temp location to dataset location
|
||||
shutil.move( filename, primary_data.file_name )
|
||||
|
||||
@@ -43,6 +43,9 @@ class DefaultToolAction( object ):
|
||||
assoc.flush()
|
||||
data = new_data
|
||||
break
|
||||
# TODO, Nate: Make sure the permitted actions here are appropriate.
|
||||
if data and not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset=data ):
|
||||
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 +82,14 @@ class DefaultToolAction( object ):
|
||||
data = NoneDataset( datatypes_registry = trans.app.datatypes_registry )
|
||||
if data.dbkey not in [None, '?']:
|
||||
input_dbkey = data.dbkey
|
||||
|
||||
# Determine output dataset permitted_actions 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 )
|
||||
# Build name for output datasets based on tool name and input names
|
||||
if len( input_names ) == 1:
|
||||
on_text = input_names[0]
|
||||
@@ -120,6 +131,7 @@ class DefaultToolAction( object ):
|
||||
data = trans.app.model.HistoryDatasetAssociation( extension=ext, create_dataset=True )
|
||||
# Commit the dataset immediately so it gets database assigned unique id
|
||||
data.flush()
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, output_permissions )
|
||||
# Create an empty file immediately
|
||||
open( data.file_name, "w" ).close()
|
||||
# This may not be neccesary with the new parent/child associations
|
||||
@@ -183,6 +195,9 @@ class DefaultToolAction( object ):
|
||||
job.add_parameter( name, value )
|
||||
for name, dataset in inp_data.iteritems():
|
||||
if dataset:
|
||||
# TODO, Nate: Make sure the permitted actions here are appropriate.
|
||||
if not trans.app.security_agent.allow_action( trans.user, dataset.permitted_actions.DATASET_ACCESS, dataset=dataset ):
|
||||
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 )
|
||||
|
||||
@@ -65,8 +65,9 @@ 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.name = err_code
|
||||
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 ) )
|
||||
data.name = err_code
|
||||
data.extension = "txt"
|
||||
data.dbkey = "?"
|
||||
data.info = err_msg
|
||||
@@ -85,12 +86,12 @@ class UploadToolAction( object ):
|
||||
if not os.path.getsize( temp_name ) > 0:
|
||||
raise BadFileException( "you attempted to upload an empty file." )
|
||||
|
||||
# See if we have a gzipped file, which, if it passes our restrictions, we'll decompress on the fly.
|
||||
# See if we have a gzipped file, which, if it passes our restrictions, we'll uncompress on the fly.
|
||||
is_gzipped, is_valid = self.check_gzip( temp_name )
|
||||
if is_gzipped and not is_valid:
|
||||
raise BadFileException( "you attempted to upload an inappropriate file." )
|
||||
elif is_gzipped and is_valid:
|
||||
#We need to decompress the temp_name file
|
||||
# We need to uncompress the temp_name file
|
||||
CHUNK_SIZE = 2**20 # 1Mb
|
||||
fd, uncompressed = tempfile.mkstemp()
|
||||
gzipped_file = gzip.GzipFile( temp_name )
|
||||
@@ -159,6 +160,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 ) )
|
||||
data.name = file_name
|
||||
data.dbkey = dbkey
|
||||
data.info = info
|
||||
|
||||
@@ -972,6 +972,8 @@ class DrillDownSelectToolParameter( ToolParameter ):
|
||||
|
||||
|
||||
class DataToolParameter( ToolParameter ):
|
||||
# TODO, Nate: Make sure the following unit tests appropriately test the dataset security
|
||||
# components. Add as many additional tests as necessary.
|
||||
"""
|
||||
Parameter that takes on one (or many) or a specific set of values.
|
||||
|
||||
@@ -979,19 +981,35 @@ 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, Group
|
||||
>>> from galaxy.util.bunch import Bunch
|
||||
>>> from galaxy.security import GalaxyRBACAgent
|
||||
>>> import galaxy.model
|
||||
>>> security_agent = GalaxyRBACAgent( galaxy.model )
|
||||
>>> 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 ) )
|
||||
>>> group = Group( 'test' )
|
||||
>>> group.flush()
|
||||
>>> Group.public_id = group.id
|
||||
>>> dataset1 = HistoryDatasetAssociation( id=1, extension='txt', create_dataset=True )
|
||||
>>> security_agent.set_dataset_permissions( dataset1, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
|
||||
>>> 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 )
|
||||
>>> security_agent.set_dataset_permissions( dataset3, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
|
||||
>>> dataset4 = HistoryDatasetAssociation( id=4, extension='png', create_dataset=True )
|
||||
>>> security_agent.set_dataset_permissions( dataset4, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
|
||||
>>> 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="interval"/>' ) )
|
||||
>>> print p.name
|
||||
blah
|
||||
>>> print p.get_html( trans=Bunch( history=hist ) )
|
||||
>>> print p.get_html( trans=Bunch( history=hist, user=None, app=Bunch( security_agent = security_agent ) ) )
|
||||
<select name="blah">
|
||||
<option value="2">2: Unnamed dataset</option>
|
||||
<option value="5" selected>5: Unnamed dataset</option>
|
||||
@@ -1047,7 +1065,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 trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ):
|
||||
if self.options and data.get_dbkey() != filter_value:
|
||||
continue
|
||||
if isinstance( data.datatype, self.formats):
|
||||
@@ -1061,6 +1079,8 @@ class DataToolParameter( ToolParameter ):
|
||||
data = datasets[0]
|
||||
elif not self.converter_safe( other_values, trans ):
|
||||
continue
|
||||
if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ):
|
||||
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
|
||||
|
||||
+1144
-15
File diff suppressed because it is too large
Load Diff
@@ -60,7 +60,7 @@ class ASync( BaseController ):
|
||||
if STATUS == 'OK':
|
||||
key = hmac.new( trans.app.config.tool_secret, "%d:%d" % ( data.id, data.history_id), sha ).hexdigest()
|
||||
if key != data_secret:
|
||||
return "You do not have permision to alter data %s." % data_id
|
||||
return "You do not have permission to alter data %s." % data_id
|
||||
# push the job into the queue
|
||||
data.state = data.blurb = data.states.RUNNING
|
||||
log.debug('executing tool %s' % tool.id)
|
||||
@@ -104,6 +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 ) )
|
||||
data.name = GALAXY_NAME
|
||||
data.dbkey = GALAXY_BUILD
|
||||
data.info = GALAXY_INFO
|
||||
|
||||
@@ -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 trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ):
|
||||
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:
|
||||
return trans.show_error_message( "You are not privileged to access this dataset." )
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
from galaxy.web.base.controller import *
|
||||
import logging
|
||||
|
||||
log = logging.getLogger( __name__ )
|
||||
|
||||
class Library( BaseController ):
|
||||
@web.expose
|
||||
def browse( self, trans, **kwd ):
|
||||
return trans.fill_template( '/library/browser.mako', libraries=trans.app.model.Library.select_by( deleted = False ) )
|
||||
index = browse
|
||||
@web.expose
|
||||
def import_datasets( self, trans, import_ids=[], **kwd ):
|
||||
if not import_ids:
|
||||
return trans.show_error_message( "You must select at least one dataset to import" )
|
||||
if not isinstance( import_ids, list ):
|
||||
import_ids = [ import_ids ]
|
||||
history = trans.get_history()
|
||||
for id in import_ids:
|
||||
dataset = trans.app.model.LibraryFolderDatasetAssociation.get( id ).to_history_dataset_association()
|
||||
history.add_dataset( dataset )
|
||||
dataset.flush()
|
||||
history.flush()
|
||||
return trans.show_ok_message( "%i dataset(s) have been imported in to your history" % len( import_ids ), refresh_frames=['history'] )
|
||||
@@ -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 trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = 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"
|
||||
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 trans.app.security_agent.allow_action( trans.user, child.permitted_actions.DATASET_ACCESS, dataset = child ):
|
||||
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 trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = 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 )
|
||||
else:
|
||||
return "You are not privileged to access this dataset."
|
||||
else:
|
||||
return "No data with id=%d" % id
|
||||
|
||||
@@ -194,81 +203,117 @@ class RootController( BaseController ):
|
||||
yield "No data with id=%d" % id
|
||||
|
||||
@web.expose
|
||||
def edit(self, trans, id=None, hid=None, **kwd):
|
||||
def edit(self, trans, id=None, hid=None, lid=None, **kwd):
|
||||
"""Returns data directly into the browser. Sets the mime-type according to the extension"""
|
||||
if hid is not None:
|
||||
history = trans.get_history()
|
||||
# TODO: hid handling
|
||||
data = history.datasets[ int( hid ) - 1 ]
|
||||
elif id is None:
|
||||
return trans.show_error_message( "Problem loading dataset id %s with history id %s." % ( str( id ), str( hid ) ) )
|
||||
else:
|
||||
elif lid is not None:
|
||||
data = self.app.model.LibraryFolderDatasetAssociation.get( lid )
|
||||
elif id is not None:
|
||||
data = self.app.model.HistoryDatasetAssociation.get( id )
|
||||
else:
|
||||
trans.log_event( "Problem loading dataset id %s with history id %s and library id %s." % ( str( id ), str( hid ), str( lid ) ) )
|
||||
return trans.show_error_message( "Problem loading dataset." )
|
||||
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
|
||||
trans.log_event( "Problem retrieving dataset id %s with history id %s and library id %s." % ( str( id ), str( hid ), str( lid ) ) )
|
||||
return trans.show_error_message( "Problem retrieving dataset." )
|
||||
if id is not None and 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 trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ):
|
||||
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))
|
||||
can_edit_metadata = lid is None or trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_EDIT_METADATA, dataset = data )
|
||||
if p.change:
|
||||
# The user clicked the Save button on the 'Change data type' form
|
||||
if not can_edit_metadata:
|
||||
return trans.show_error_message( "You are not authorized to change this dataset's metadata." )
|
||||
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
|
||||
if not can_edit_metadata:
|
||||
return trans.show_error_message( "You are not authorized to change this dataset's metadata." )
|
||||
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
|
||||
if not can_edit_metadata:
|
||||
return trans.show_error_message( "You are not authorized to change this dataset's metadata." )
|
||||
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:
|
||||
if lid is not None:
|
||||
return trans.show_error_message( "Data in the library cannot be converted. Please import it to a history and covert it." )
|
||||
"""The user clicked the Convert button on the 'Convert to new format' form"""
|
||||
if not can_edit_metadata:
|
||||
return trans.show_error_message( "You are not authorized to change this dataset's metadata." )
|
||||
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_permission:
|
||||
"""The user clicked the change_permission 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 permitted actions." )
|
||||
if trans.app.security_agent.allow_action( trans.user, data.dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data.dataset ):
|
||||
group_args = [ k.replace('group_', '', 1) for k in kwd if k.startswith('group_') ]
|
||||
group_ids_checked = filter( lambda x: not x.count('_'), group_args )
|
||||
permissions = []
|
||||
for group_id in group_ids_checked:
|
||||
action_strings = [ action.replace(group_id + '_', '', 1) for action in group_args if action.startswith(group_id + '_') ]
|
||||
actions = trans.app.security_agent.convert_permitted_action_strings( action_strings )
|
||||
permissions.append( ( trans.app.security_agent.get_group( group_id ), actions ) )
|
||||
trans.app.security_agent.set_dataset_permissions( data.dataset, permissions )
|
||||
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 )
|
||||
|
||||
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 +372,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 -----------------------------------------------
|
||||
@@ -356,8 +403,13 @@ 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"
|
||||
history_names.append(history.name)
|
||||
# Delete DefaultHistoryGroupAssociations
|
||||
for default_history_group_association in history.default_groups:
|
||||
default_history_group_association.delete()
|
||||
default_history_group_association.flush()
|
||||
# Mark history as deleted in db
|
||||
history.deleted = True
|
||||
history_names.append(history.name)
|
||||
# If deleting the current history, make a new current.
|
||||
if history == trans.get_history():
|
||||
trans.new_history()
|
||||
@@ -404,7 +456,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 +493,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 +600,16 @@ 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 )
|
||||
groups = trans.app.security_agent.history_get_default_access( history )
|
||||
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 )
|
||||
data.flush()
|
||||
data_file = open( data.file_name, "wb" )
|
||||
file_data.file.seek( 0 )
|
||||
@@ -569,9 +626,35 @@ 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
|
||||
def history_set_default_permitted_actions( self, trans, **kwd ):
|
||||
"""Sets the user's default permitted_actions for the current history"""
|
||||
if trans.user:
|
||||
if 'set_permitted_actions' in kwd:
|
||||
"""The user clicked the set_permitted_actions button on the set_permitted_actions form"""
|
||||
history = trans.get_history()
|
||||
group_args = [ k.replace('group_', '', 1) for k in kwd if k.startswith('group_') ]
|
||||
group_ids_checked = filter( lambda x: not x.count('_'), group_args )
|
||||
if not group_ids_checked:
|
||||
return trans.show_error_message( "You must specify at least one default group." )
|
||||
permissions = []
|
||||
for group_id in group_ids_checked:
|
||||
group = trans.app.security_agent.get_group( group_id )
|
||||
if not group:
|
||||
return trans.show_error_message( 'You have specified an invalid group.' )
|
||||
action_strings = [ action.replace(group_id + '_', '', 1) for action in group_args if action.startswith(group_id + '_') ]
|
||||
permissions.append( ( group, trans.app.security_agent.convert_permitted_action_strings( action_strings ) ) )
|
||||
trans.app.security_agent.history_set_default_access( history, permissions = permissions )
|
||||
return trans.show_ok_message( 'Default history permitted actions have been changed.' )
|
||||
return trans.fill_template( 'history/permissions.mako' )
|
||||
else:
|
||||
#user not logged in, history group must be only public
|
||||
return trans.show_error_message( "You must be logged in to change a history's default permitted actions." )
|
||||
|
||||
@web.expose
|
||||
def dataset_make_primary( self, trans, id=None):
|
||||
"""Copies a dataset and makes primary"""
|
||||
@@ -588,7 +671,7 @@ class RootController( BaseController ):
|
||||
return trans.show_error_message( "<p>Failed to make secondary dataset primary.</p>" )
|
||||
|
||||
@web.expose
|
||||
def masthead( self, trans ):
|
||||
def masthead( self, trans, active_view=None ):
|
||||
brand = trans.app.config.get( "brand", "" )
|
||||
if brand:
|
||||
brand ="<span class='brand'>/%s</span>" % brand
|
||||
@@ -596,8 +679,15 @@ class RootController( BaseController ):
|
||||
bugs_email = trans.app.config.get( "bugs_email", "mailto:galaxy-bugs@bx.psu.edu" )
|
||||
blog_url = trans.app.config.get( "blog_url", "http://g2.trac.bx.psu.edu/blog" )
|
||||
screencasts_url = trans.app.config.get( "screencasts_url", "http://g2.trac.bx.psu.edu/wiki/ScreenCasts" )
|
||||
admin_user = "false"
|
||||
admin_users = trans.app.config.get( "admin_users", "" ).split( "," )
|
||||
user = trans.get_user()
|
||||
if user:
|
||||
user_email = trans.get_user().email
|
||||
if user_email in admin_users:
|
||||
admin_user = "true"
|
||||
return trans.fill_template( "/root/masthead.mako", brand=brand, wiki_url=wiki_url,
|
||||
blog_url=blog_url,bugs_email=bugs_email, screencasts_url=screencasts_url )
|
||||
blog_url=blog_url,bugs_email=bugs_email, screencasts_url=screencasts_url, admin_user=admin_user, active_view=active_view )
|
||||
|
||||
@web.expose
|
||||
def dataset_errors( self, trans, id=None, **kwd ):
|
||||
|
||||
@@ -118,6 +118,7 @@ class User( BaseController ):
|
||||
user = trans.app.model.User( email=email )
|
||||
user.set_password_cleartext( password )
|
||||
user.flush()
|
||||
trans.app.security_agent.setup_new_user( user )
|
||||
trans.set_user( user )
|
||||
trans.ensure_valid_galaxy_session()
|
||||
"""
|
||||
@@ -166,3 +167,27 @@ class User( BaseController ):
|
||||
return trans.show_form(
|
||||
web.FormBuilder( web.url_for(), "Reset Password", submit_text="Submit" )
|
||||
.add_text( "email", "Email", value=email, error=error ) )
|
||||
|
||||
@web.expose
|
||||
def set_default_permitted_actions( self, trans, **kwd ):
|
||||
"""Sets the user's default permitted actions for the new histories"""
|
||||
if trans.user:
|
||||
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_') ]
|
||||
group_ids_checked = filter( lambda x: not x.count('_'), group_args )
|
||||
if not group_ids_checked:
|
||||
return trans.show_error_message( "You must specify at least one default group." )
|
||||
permissions = []
|
||||
for group_id in group_ids_checked:
|
||||
group = trans.app.security_agent.get_group( group_id )
|
||||
if not group:
|
||||
return trans.show_error_message( 'You have specified an invalid group.' )
|
||||
action_strings = [ action.replace(group_id + '_', '', 1) for action in group_args if action.startswith(group_id + '_') ]
|
||||
permissions.append( ( group, trans.app.security_agent.convert_permitted_action_strings( action_strings ) ) )
|
||||
trans.app.security_agent.user_set_default_access( trans.user, permissions )
|
||||
return trans.show_ok_message( 'Default new history permitted actions have been changed.' )
|
||||
return trans.fill_template( 'user/permissions.mako' )
|
||||
else:
|
||||
# User not logged in, history group must be only public
|
||||
return trans.show_error_message( "You must be logged in to change your default permitted actions." )
|
||||
|
||||
@@ -16,8 +16,12 @@ class WorkflowController( BaseController ):
|
||||
beta = True
|
||||
|
||||
@web.expose
|
||||
@web.require_login( "use Galaxy workflows" )
|
||||
def index( self, trans ):
|
||||
return trans.fill_template( "workflow/index.mako" )
|
||||
|
||||
@web.expose
|
||||
@web.require_login( "use Galaxy workflows" )
|
||||
def list( self, trans ):
|
||||
"""
|
||||
Render workflow main page (management of existing workflows)
|
||||
"""
|
||||
@@ -32,7 +36,7 @@ class WorkflowController( BaseController ):
|
||||
.filter( model.StoredWorkflow.c.deleted == False ) \
|
||||
.order_by( desc( model.StoredWorkflow.c.update_time ) ) \
|
||||
.all()
|
||||
return trans.fill_template( "workflow/index.mako",
|
||||
return trans.fill_template( "workflow/list.mako",
|
||||
workflows = workflows,
|
||||
shared_by_others = shared_by_others )
|
||||
|
||||
@@ -63,7 +67,7 @@ class WorkflowController( BaseController ):
|
||||
session.save( share )
|
||||
session.flush()
|
||||
trans.set_message( "Workflow '%s' shared with user '%s'" % ( stored.name, other.email ) )
|
||||
return self.index( trans )
|
||||
return self.list( trans )
|
||||
return trans.fill_template( "workflow/share.mako",
|
||||
message = msg,
|
||||
messagetype = mtype,
|
||||
@@ -78,7 +82,7 @@ class WorkflowController( BaseController ):
|
||||
stored.name = new_name
|
||||
trans.sa_session.flush()
|
||||
trans.set_message( "Workflow renamed to '%s'." % new_name )
|
||||
return self.index( trans )
|
||||
return self.list( trans )
|
||||
else:
|
||||
return form( url_for( id=trans.security.encode_id(stored.id) ), "Rename workflow", submit_text="Rename" ) \
|
||||
.add_text( "new_name", "Workflow Name", value=stored.name )
|
||||
@@ -107,7 +111,7 @@ class WorkflowController( BaseController ):
|
||||
session.flush()
|
||||
# Display the management page
|
||||
trans.set_message( 'Clone created with name "%s"' % new_stored.name )
|
||||
return self.index( trans )
|
||||
return self.list( trans )
|
||||
|
||||
@web.expose
|
||||
@web.require_login( "create workflows" )
|
||||
@@ -132,7 +136,7 @@ class WorkflowController( BaseController ):
|
||||
session.flush()
|
||||
# Display the management page
|
||||
trans.set_message( "Workflow '%s' created" % stored_workflow.name )
|
||||
return self.index( trans )
|
||||
return self.list( trans )
|
||||
else:
|
||||
return form( url_for(), "Create new workflow", submit_text="Create" ) \
|
||||
.add_text( "workflow_name", "Workflow Name", value="Unnamed workflow" )
|
||||
@@ -149,7 +153,7 @@ class WorkflowController( BaseController ):
|
||||
stored.flush()
|
||||
# Display the management page
|
||||
trans.set_message( "Workflow '%s' deleted" % stored.name )
|
||||
return self.index( trans )
|
||||
return self.list( trans )
|
||||
|
||||
@web.expose
|
||||
@web.require_login( "edit workflows" )
|
||||
@@ -433,8 +437,7 @@ class WorkflowController( BaseController ):
|
||||
trans.sa_session.save( stored )
|
||||
trans.sa_session.flush()
|
||||
# Index page with message
|
||||
trans.template_context['message'] = "Workflow '%s' created" % workflow_name
|
||||
return self.index( trans )
|
||||
return trans.show_message( "Workflow '%s' created from current history." % workflow_name )
|
||||
## return trans.show_ok_message( "<p>Workflow '%s' created.</p><p><a target='_top' href='%s'>Click to load in workflow editor</a></p>"
|
||||
## % ( workflow_name, web.url_for( action='editor', id=trans.security.encode_id(stored.id) ) ) )
|
||||
|
||||
|
||||
@@ -197,9 +197,10 @@ 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()
|
||||
self.app.security_agent.history_set_default_access( history )
|
||||
# Immediately associate the new history with self
|
||||
self.__history = history
|
||||
# Make sure we have a valid session to associate with the new history
|
||||
@@ -271,6 +272,7 @@ class UniverseWebTransaction( base.DefaultWebTransaction ):
|
||||
user.set_password_cleartext( 'external' )
|
||||
user.external = True
|
||||
user.flush()
|
||||
self.app.security_agent.setup_new_user( user )
|
||||
self.log_event( "Automatically created account '%s'" % user.email )
|
||||
return user
|
||||
def get_cookie_user( self ):
|
||||
@@ -431,6 +433,10 @@ 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 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 )
|
||||
history.user_id = user.id
|
||||
history.flush()
|
||||
self.__history = history
|
||||
@@ -522,8 +528,8 @@ class FormBuilder( object ):
|
||||
self.action = action
|
||||
self.submit_text = submit_text
|
||||
self.inputs = []
|
||||
def add_input( self, type, name, label, value=None, error=None, help=None ):
|
||||
self.inputs.append( FormInput( type, label, name, value, error, help ) )
|
||||
def add_input( self, type, name, label, value=None, error=None, help=None, use_label=True ):
|
||||
self.inputs.append( FormInput( type, label, name, value, error, help, use_label ) )
|
||||
return self
|
||||
def add_text( self, name, label, value=None, error=None, help=None ):
|
||||
return self.add_input( 'text', label, name, value, error, help )
|
||||
@@ -534,13 +540,14 @@ class FormInput( object ):
|
||||
"""
|
||||
Simple class describing a form input element
|
||||
"""
|
||||
def __init__( self, type, name, label, value=None, error=None, help=None ):
|
||||
def __init__( self, type, name, label, value=None, error=None, help=None, use_label=True ):
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.label = label
|
||||
self.value = value
|
||||
self.error = error
|
||||
self.help = help
|
||||
self.use_label = use_label
|
||||
|
||||
class FormData( object ):
|
||||
"""
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 593 B |
Binary file not shown.
|
After Width: | Height: | Size: 622 B |
Binary file not shown.
|
After Width: | Height: | Size: 537 B |
Binary file not shown.
|
After Width: | Height: | Size: 688 B |
Binary file not shown.
|
After Width: | Height: | Size: 446 B |
Binary file not shown.
|
After Width: | Height: | Size: 395 B |
@@ -283,6 +283,11 @@ table.colored tr
|
||||
background: $table_row_bg;
|
||||
}
|
||||
|
||||
table.colored tr.odd_row
|
||||
{
|
||||
background: $odd_row_bg;
|
||||
}
|
||||
|
||||
div.debug
|
||||
{
|
||||
margin: 10px;
|
||||
@@ -350,6 +355,16 @@ ul.toolParameterExpandableCollapsable
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul.manage-table-actions {
|
||||
float: right;
|
||||
margin-top: -2.5em;
|
||||
}
|
||||
ul.manage-table-actions li {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
background: #eeeeee;
|
||||
color: #333;
|
||||
@@ -416,4 +431,8 @@ div.popupmenu-item:hover {
|
||||
|
||||
.popup-arrow:hover {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
div.permissionContainer {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ img
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
||||
a:link, a:visited, a:active
|
||||
{
|
||||
color: #303030;
|
||||
@@ -282,6 +283,11 @@ table.colored tr
|
||||
background: white;
|
||||
}
|
||||
|
||||
table.colored tr.odd_row
|
||||
{
|
||||
background: #DADFEF;
|
||||
}
|
||||
|
||||
div.debug
|
||||
{
|
||||
margin: 10px;
|
||||
@@ -293,7 +299,7 @@ div.debug
|
||||
|
||||
div.odd_row
|
||||
{
|
||||
background: #FFFF99;
|
||||
background: #DADFEF;
|
||||
}
|
||||
|
||||
#footer {
|
||||
@@ -348,6 +354,16 @@ ul.toolParameterExpandableCollapsable
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul.manage-table-actions {
|
||||
float: right;
|
||||
margin-top: -2.5em;
|
||||
}
|
||||
ul.manage-table-actions li {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
background: #eeeeee;
|
||||
color: #333;
|
||||
@@ -414,4 +430,8 @@ div.popupmenu-item:hover {
|
||||
|
||||
.popup-arrow:hover {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
div.permissionContainer {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
@@ -80,6 +80,13 @@ div.historyItem-running
|
||||
*/
|
||||
}
|
||||
|
||||
div.historyItem-noPermission
|
||||
{
|
||||
filter: alpha(opacity=60);
|
||||
-moz-opacity: .60;
|
||||
opacity: .60;
|
||||
}
|
||||
|
||||
div.historyItem-queued
|
||||
{
|
||||
}
|
||||
@@ -101,4 +108,4 @@ pre.peek th
|
||||
{
|
||||
color: white;
|
||||
background: #023858;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
.libraryRow {
|
||||
background-color: #d2c099;
|
||||
}
|
||||
|
||||
.datasetHighlighted {
|
||||
background-color: #C1C9E5;
|
||||
}
|
||||
|
||||
div.historyItemBody {
|
||||
padding: 4px 4px 2px 4px;
|
||||
}
|
||||
|
||||
li.folderRow,
|
||||
li.datasetRow
|
||||
{
|
||||
border-top: solid 1px #ddd;
|
||||
}
|
||||
|
||||
li.folderRow:hover,
|
||||
li.datasetRow:hover
|
||||
{
|
||||
background-color: #C1C9E5;
|
||||
}
|
||||
|
||||
img.expanderIcon {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
input.datasetCheckbox,
|
||||
li, ul
|
||||
{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.rowTitle
|
||||
{
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.libraryTitle th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
pre.peek
|
||||
{
|
||||
background: white;
|
||||
color: black;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
pre.peek th
|
||||
{
|
||||
color: white;
|
||||
background: #023858;
|
||||
}
|
||||
|
||||
a.expandLink {
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -7,6 +7,7 @@ body
|
||||
margin: 3px;
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.pageTitle
|
||||
@@ -24,3 +25,38 @@ a:link, a:visited, a:active
|
||||
{
|
||||
color: #eeeeee;
|
||||
}
|
||||
|
||||
#tab-bar-bottom
|
||||
{
|
||||
z-index: -1;
|
||||
position:absolute;
|
||||
top:27px; left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #222532;
|
||||
}
|
||||
|
||||
span.link-group
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
|
||||
span.link-group span
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
span.link-group span.active-link
|
||||
{
|
||||
background: #222532;
|
||||
padding-left: 3px; padding-right: 3px;
|
||||
margin-left: -3px; margin-right: -3px;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
@@ -45,6 +45,19 @@ body
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#messagebox
|
||||
{
|
||||
position:absolute;
|
||||
top:33px;
|
||||
left:0;
|
||||
width:100%;
|
||||
height:24px !important;
|
||||
overflow: hidden;
|
||||
border-bottom: solid #999 1px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
|
||||
#left, #left-border, #center, #right-border, #right
|
||||
{
|
||||
position: absolute;
|
||||
@@ -146,7 +159,6 @@ table.column-layout
|
||||
|
||||
.unified-panel-header {
|
||||
height: 2em;
|
||||
overflow: hidden;
|
||||
z-index: 1000;
|
||||
background: #cccccc;
|
||||
background-image: url(panel_header_bg.png);
|
||||
@@ -160,18 +172,17 @@ table.column-layout
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.unified-panel-header-inner {
|
||||
padding-top: 0.45em;
|
||||
}
|
||||
|
||||
|
||||
.menu-bg {
|
||||
background: #C1C9E5 url(menu_bg.png) top repeat-x;
|
||||
}
|
||||
|
||||
div.unified-panel-body {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 2em;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
@@ -197,6 +208,7 @@ div.unified-panel-body {
|
||||
color: black;
|
||||
background: #aaaaaa;
|
||||
}
|
||||
|
||||
.panel-header-button:active {
|
||||
color: white;
|
||||
background: #aaaaaa;
|
||||
@@ -240,7 +252,7 @@ div.popupmenu-item:hover {
|
||||
}
|
||||
|
||||
#overlay {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0; left: 0; width: 100%; height: 100%;
|
||||
z-index: 20000;
|
||||
}
|
||||
@@ -271,6 +283,34 @@ div.popupmenu-item:hover {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.dialog-box body {
|
||||
overflow: scroll;
|
||||
|
||||
.panel-error-message, .panel-warning-message, .panel-done-message, .panel-info-message
|
||||
{
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
color: #303030;
|
||||
padding: 0px;
|
||||
padding-left: 26px;
|
||||
background-color: #FFCCCC;
|
||||
background-image: url(error_small.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 6px 50%;
|
||||
}
|
||||
|
||||
.panel-warning-message
|
||||
{
|
||||
background-image: url(warn_small.png);
|
||||
background-color: #FFFFCC;
|
||||
}
|
||||
|
||||
.panel-done-message
|
||||
{
|
||||
background-image: url(done_small.png);
|
||||
background-color: #CCFFCC;
|
||||
}
|
||||
|
||||
.panel-info-message
|
||||
{
|
||||
background-image: url(info_small.png);
|
||||
background-color: #CCCCFF;
|
||||
}
|
||||
@@ -15,7 +15,7 @@ form_border=#d8b365
|
||||
#form_body_bg=#FFFFFF
|
||||
form_body_bg_top=#FFFFFF
|
||||
form_body_bg_bottom=#FFFFFF
|
||||
odd_row_bg=#FFFF99
|
||||
odd_row_bg=#DADFEF
|
||||
# Messages
|
||||
error_message_border=#AA6666
|
||||
error_message_bg=#FFCCCC
|
||||
@@ -48,6 +48,7 @@ masthead_bg=#2C3143
|
||||
masthead_text=#eeeeee
|
||||
masthead_bg_hatch=-
|
||||
masthead_link=#eeeeee
|
||||
masthead_active_tab_bg=#222532
|
||||
# ---- Layout -----------------------------------------------------------------
|
||||
# Overall background color (including space between panels)
|
||||
layout_bg=#eee
|
||||
|
||||
@@ -80,6 +80,13 @@ div.historyItem-running
|
||||
*/
|
||||
}
|
||||
|
||||
div.historyItem-noPermission
|
||||
{
|
||||
filter: alpha(opacity=60);
|
||||
-moz-opacity: .60;
|
||||
opacity: .60;
|
||||
}
|
||||
|
||||
div.historyItem-queued
|
||||
{
|
||||
}
|
||||
@@ -101,4 +108,4 @@ pre.peek th
|
||||
{
|
||||
color: white;
|
||||
background: $peek_table_header;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
.libraryRow {
|
||||
background-color: $form_title_bg_bottom;
|
||||
}
|
||||
|
||||
.datasetHighlighted {
|
||||
background-color: $menu_bg_over;
|
||||
}
|
||||
|
||||
div.historyItemBody {
|
||||
padding: 4px 4px 2px 4px;
|
||||
}
|
||||
|
||||
li.folderRow,
|
||||
li.datasetRow
|
||||
{
|
||||
border-top: solid 1px #ddd;
|
||||
}
|
||||
|
||||
li.folderRow:hover,
|
||||
li.datasetRow:hover
|
||||
{
|
||||
background-color: $menu_bg_over;
|
||||
}
|
||||
|
||||
img.expanderIcon {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
input.datasetCheckbox,
|
||||
li, ul
|
||||
{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.rowTitle
|
||||
{
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.libraryTitle th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
pre.peek
|
||||
{
|
||||
background: white;
|
||||
color: black;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
pre.peek th
|
||||
{
|
||||
color: white;
|
||||
background: $peek_table_header;
|
||||
}
|
||||
|
||||
a.expandLink {
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from galaxy import eggs
|
||||
import pkg_resources
|
||||
pkg_resources.require("Cheetah")
|
||||
|
||||
import sys
|
||||
from Cheetah.Template import Template
|
||||
import string
|
||||
@@ -13,8 +17,8 @@ def run( cmd ):
|
||||
|
||||
templates = [ ( "base.css.tmpl", "base.css" ),
|
||||
( "panel_layout.css.tmpl", "panel_layout.css" ),
|
||||
( "panel_layout_ie.css.tmpl", "panel_layout_ie.css" ),
|
||||
( "masthead.css.tmpl", "masthead.css"),
|
||||
( "library.css.tmpl", "library.css"),
|
||||
( "history.css.tmpl", "history.css" ),
|
||||
( "tool_menu.css.tmpl", "tool_menu.css" ),
|
||||
( "reset.css.tmpl", "reset.css" ) ]
|
||||
@@ -64,7 +68,8 @@ for line in open( vars ):
|
||||
for input, output in templates:
|
||||
print input ,"->", output
|
||||
open( os.path.join( out_dir, output ), "w" ).write( str( Template( file=input, searchList=[context] ) ) )
|
||||
|
||||
|
||||
"""
|
||||
for rule, output in images:
|
||||
t = string.Template( rule ).substitute( context )
|
||||
print t, "->", output
|
||||
@@ -74,3 +79,4 @@ for src, bg, out in shared_images:
|
||||
t = "./png_over_color.py shared_images/%s %s %s" % ( src, context[bg], os.path.join( out_dir, out ) )
|
||||
print t
|
||||
run( t.split() )
|
||||
"""
|
||||
|
||||
@@ -7,6 +7,7 @@ body
|
||||
margin: 3px;
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.pageTitle
|
||||
@@ -24,3 +25,38 @@ a:link, a:visited, a:active
|
||||
{
|
||||
color: $masthead_link;
|
||||
}
|
||||
|
||||
#tab-bar-bottom
|
||||
{
|
||||
z-index: -1;
|
||||
position:absolute;
|
||||
top:27px; left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: $masthead_active_tab_bg;
|
||||
}
|
||||
|
||||
span.link-group
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
|
||||
span.link-group span
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
span.link-group span.active-link
|
||||
{
|
||||
background: $masthead_active_tab_bg;
|
||||
padding-left: 3px; padding-right: 3px;
|
||||
margin-left: -3px; margin-right: -3px;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
@@ -45,6 +45,19 @@ body
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#messagebox
|
||||
{
|
||||
position:absolute;
|
||||
top:33px;
|
||||
left:0;
|
||||
width:100%;
|
||||
height:24px !important;
|
||||
overflow: hidden;
|
||||
border-bottom: solid #999 1px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
|
||||
#left, #left-border, #center, #right-border, #right
|
||||
{
|
||||
position: absolute;
|
||||
@@ -268,4 +281,37 @@ div.popupmenu-item:hover {
|
||||
|
||||
.dialog-box .body, .dialog-box .buttons {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
## Messages for message box, slightly different style
|
||||
|
||||
.panel-error-message, .panel-warning-message, .panel-done-message, .panel-info-message
|
||||
{
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
color: $base_text;
|
||||
padding: 0px;
|
||||
padding-left: 26px;
|
||||
background-color: $error_message_bg;
|
||||
background-image: url(error_small.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 6px 50%;
|
||||
}
|
||||
|
||||
.panel-warning-message
|
||||
{
|
||||
background-image: url(warn_small.png);
|
||||
background-color: $warn_message_bg;
|
||||
}
|
||||
|
||||
.panel-done-message
|
||||
{
|
||||
background-image: url(done_small.png);
|
||||
background-color: $done_message_bg;
|
||||
}
|
||||
|
||||
.panel-info-message
|
||||
{
|
||||
background-image: url(info_small.png);
|
||||
background-color: $info_message_bg;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%
|
||||
from galaxy.web.controllers.admin import entities, unentities
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
%>
|
||||
|
||||
## Render a row
|
||||
<%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>
|
||||
%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='purge_group', group_id=group[0] )}">Purge</a></td>
|
||||
</%def>
|
||||
|
||||
<%def name="title()">Groups</%def>
|
||||
<div class="toolForm">
|
||||
<div class="form-row">
|
||||
<a href="${h.url_for( controller='admin', action='libraries' )}">Libraries</a> |
|
||||
<a href="${h.url_for( controller='admin', action='groups' )}">Groups</a> |
|
||||
<tr><td><a href="${h.url_for( controller='admin', action='users' )}">Users</a></td></tr>
|
||||
</div>
|
||||
<table align="center" class="colored">
|
||||
%if msg:
|
||||
<tr><td colspan="7"><p class="ok_bgr">${msg}</p></td></tr>
|
||||
%endif
|
||||
%if len( groups ) == 0:
|
||||
<tr><td colspan="7">There are no deleted Galaxy groups</td></tr>
|
||||
%else:
|
||||
<%
|
||||
render_quick_find = len( groups ) > 50
|
||||
ctr = 0
|
||||
%>
|
||||
%if render_quick_find:
|
||||
<%
|
||||
anchors = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
|
||||
anchor_loc = 0
|
||||
anchored = False
|
||||
curr_anchor = 'A'
|
||||
%>
|
||||
<tr class="header"><td colspan="7"><center><a name="TOP">Deleted Galaxy Groups - Quick Find</a></td></center></tr>
|
||||
<tr>
|
||||
<td colspan="7">
|
||||
<center>
|
||||
|<a href="#A">A</a>|<a href="#B">B</a>|<a href="#C">C</a>|<a href="#D">D</a>|<a href="#E">E</a>|<a href="#F">F</a>
|
||||
|<a href="#G">G</a>|<a href="#H">H</a>|<a href="#I">I</a>|<a href="#J">J</a>|<a href="#K">K</a>|<a href="#L">L</a>
|
||||
|<a href="#M">M</a>|<a href="#N">N</a>|<a href="#O">O</a>|<a href="#P">P</a>|<a href="#Q">Q</a>|<a href="#R">R</a>
|
||||
|<a href="#S">S</a>|<a href="#T">T</a>|<a href="#U">U</a>|<a href="#V">V</a>|<a href="#W">W</a>|<a href="#X">X</a>
|
||||
|<a href="#Y">Y</a>|<a href="#Z">Z</a>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
%else:
|
||||
<tr class="header"><td colspan="7"><center>Deleted Galaxy Groups</td></center></tr>
|
||||
%endif
|
||||
<tr class="header">
|
||||
<td> </td>
|
||||
<td>Group</td>
|
||||
<td>Priority</td>
|
||||
<td>Members</td>
|
||||
<td>Datasets</td>
|
||||
<td>Group Permitted Actions on Datasets</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
%for group in groups:
|
||||
<% group_name = unescape( group[1], unentities ) %>
|
||||
%if render_quick_find and not group_name.upper().startswith( curr_anchor ):
|
||||
<% anchored = False %>
|
||||
%endif
|
||||
<tr>
|
||||
%if ctr % 2 == 1:
|
||||
<div class="odd_row">
|
||||
%endif
|
||||
%if render_quick_find and group_name.upper().startswith( curr_anchor ):
|
||||
%if not anchored:
|
||||
<tr>
|
||||
<td colspan="7" class=panel-body">
|
||||
<a name="${curr_anchor}"></a>
|
||||
<div style="float: right;"><a href="#TOP">quick find</a></div>
|
||||
<% anchored = True %>
|
||||
</td>
|
||||
</tr>
|
||||
%endif
|
||||
${render_row( group_name, group )}
|
||||
%elif render_quick_find:
|
||||
%for anchor in anchors[ anchor_loc: ]:
|
||||
%if group_name.upper().startswith( anchor ):
|
||||
%if not anchored:
|
||||
<tr>
|
||||
<td colspan="7" class="panel-body">
|
||||
<a name="${anchor}"></a>
|
||||
<div style="float: right;"><a href="#TOP">quick find</a></div>
|
||||
<%
|
||||
curr_anchor = anchor
|
||||
anchored = True
|
||||
%>
|
||||
</td>
|
||||
</tr>
|
||||
%endif
|
||||
${render_row( group_name, group )}
|
||||
<%
|
||||
anchor_loc = anchors.index( anchor )
|
||||
break
|
||||
%>
|
||||
%endif
|
||||
%endfor
|
||||
%else:
|
||||
${render_row( group_name, group )}
|
||||
%endif
|
||||
%if ctr % 2 == 1:
|
||||
</div>
|
||||
%endif
|
||||
<% ctr += 1 %>
|
||||
</tr>
|
||||
%endfor
|
||||
%endif
|
||||
</table>
|
||||
</div>
|
||||
@@ -0,0 +1,106 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%
|
||||
from galaxy.web.controllers.admin import entities, unentities
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
%>
|
||||
|
||||
<%def name="title()">Create Group</%def>
|
||||
<div class="toolForm">
|
||||
<div class="form-row">
|
||||
<a href="${h.url_for( controller='admin', action='libraries' )}">Libraries</a> |
|
||||
<a href="${h.url_for( controller='admin', action='groups' )}">Groups</a> |
|
||||
<tr><td><a href="${h.url_for( controller='admin', action='users' )}">Users</a></td></tr>
|
||||
</div>
|
||||
<h3 align="center">Create Group</h3>
|
||||
<table align="center" class="colored">
|
||||
%if msg:
|
||||
<tr><td><p class="ok_bgr">${msg}</p></td></tr>
|
||||
%endif
|
||||
<tr>
|
||||
<td>
|
||||
<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>
|
||||
</tr>
|
||||
%if len( users ) == 0:
|
||||
<tr><td>There are no Galaxy users</td></tr>
|
||||
%else:
|
||||
<%
|
||||
render_quick_find = len( users ) > 50
|
||||
%>
|
||||
%if render_quick_find:
|
||||
<%
|
||||
anchors = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
|
||||
anchor_loc = 0
|
||||
anchored = False
|
||||
curr_anchor = 'A'
|
||||
%>
|
||||
<tr class="header"><td><a name="TOP">Add Members to Group - Quick Find</a></td></tr>
|
||||
<tr>
|
||||
<td>
|
||||
|<a href="#A">A</a>|<a href="#B">B</a>|<a href="#C">C</a>|<a href="#D">D</a>|<a href="#E">E</a>|<a href="#F">F</a>
|
||||
|<a href="#G">G</a>|<a href="#H">H</a>|<a href="#I">I</a>|<a href="#J">J</a>|<a href="#K">K</a>|<a href="#L">L</a>
|
||||
|<a href="#M">M</a>|<a href="#N">N</a>|<a href="#O">O</a>|<a href="#P">P</a>|<a href="#Q">Q</a>|<a href="#R">R</a>
|
||||
|<a href="#S">S</a>|<a href="#T">T</a>|<a href="#U">U</a>|<a href="#V">V</a>|<a href="#W">W</a>|<a href="#X">X</a>
|
||||
|<a href="#Y">Y</a>|<a href="#Z">Z</a>
|
||||
</td>
|
||||
</tr>
|
||||
%else:
|
||||
<tr class="header"><td>Add Members to Group</td></tr>
|
||||
%endif
|
||||
<tr>
|
||||
<td>
|
||||
%for user in users:
|
||||
<% email = unescape( user[1], unentities ) %>
|
||||
%if render_quick_find and not email.upper().startswith( curr_anchor ):
|
||||
<% anchored = False %>
|
||||
%endif
|
||||
<tr>
|
||||
<td>
|
||||
%if render_quick_find and email.upper().startswith( curr_anchor ):
|
||||
%if not anchored:
|
||||
<a name="${curr_anchor}"></a>
|
||||
<hr/>
|
||||
<div style="float: right;"><a href="#TOP">quick find</a></div>
|
||||
<br/>
|
||||
<% anchored = True %>
|
||||
%endif
|
||||
<input type="checkbox" name="members" value="${user[0]}"/> ${email}
|
||||
%elif render_quick_find:
|
||||
%for anchor in anchors[ anchor_loc: ]:
|
||||
%if email.upper().startswith( anchor ):
|
||||
%if not anchored:
|
||||
<a name="${anchor}"></a>
|
||||
<hr/>
|
||||
<div style="float: right;"><a href="#TOP">quick find</a></div>
|
||||
<br/>
|
||||
<%
|
||||
curr_anchor = anchor
|
||||
anchored = True
|
||||
%>
|
||||
%endif
|
||||
<input type="checkbox" name="members" value="${user[0]}"/> ${email}
|
||||
<%
|
||||
anchor_loc = anchors.index( anchor )
|
||||
break
|
||||
%>
|
||||
%endif
|
||||
%endfor
|
||||
%else:
|
||||
<input type="checkbox" name="members" value="${user[0]}"/> ${email}
|
||||
%endif
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</td>
|
||||
</tr>
|
||||
%endif
|
||||
<tr><td><center><button name="create_group_button" value="group_create">Create</button></center></td></tr>
|
||||
</form>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -0,0 +1,73 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%def name="title()">Permitted Actions on Datasets</%def>
|
||||
<div class="toolForm">
|
||||
<div class="form-row">
|
||||
<a href="${h.url_for( controller='admin', action='libraries' )}">Libraries</a> |
|
||||
<a href="${h.url_for( controller='admin', action='groups' )}">Groups</a> |
|
||||
<tr><td><a href="${h.url_for( controller='admin', action='users' )}">Users</a></td></tr>
|
||||
</div>
|
||||
<h3 align="center">Manage Permitted Actions on Datasets for Group '${group.name}'</h3>
|
||||
<table align="center" class="colored">
|
||||
%if msg:
|
||||
<tr><td colspan="3"><p class="ok_bgr">${msg}</p></td></tr>
|
||||
%endif
|
||||
<tr><td colspan="3"> </td>
|
||||
%if len( group.datasets ) == 0:
|
||||
<tr><td colspan="3">The group you selected has no associated datasets.</td></tr>
|
||||
%else:
|
||||
<tr class="header">
|
||||
<td>Association Names/Info</td>
|
||||
<td>Permitted Actions</td>
|
||||
</tr>
|
||||
<% ctr = 0 %>
|
||||
<form name="group_dataset_permitted_actions_edit" action="${h.url_for( controller='admin',
|
||||
action='group_dataset_permitted_actions_edit',
|
||||
group_id=group.id )}" method="post" >
|
||||
<input type="hidden" name="gdas" value="${ ','.join( [ str(gda.id) for gda in gdas ] ) }"/>
|
||||
%for gda in gdas:
|
||||
<% permissions = trans.app.security_agent.get_dataset_permissions( gda, group.id ) %>
|
||||
%if ctr % 2 == 1:
|
||||
<tr class="odd_row">
|
||||
%else:
|
||||
<tr class="tr">
|
||||
%endif
|
||||
<td>
|
||||
%if gda.dataset.library_associations:
|
||||
<strong>Library name(s):</strong><br/>
|
||||
%endif
|
||||
<ul>
|
||||
%for da in gda.dataset.library_associations:
|
||||
<li>${da.name} (${da.info})</li>
|
||||
%endfor
|
||||
</ul>
|
||||
%if gda.dataset.history_associations:
|
||||
<strong>History name(s):</strong><br/>
|
||||
%endif
|
||||
<ul>
|
||||
%for da in gda.dataset.history_associations:
|
||||
<li>${da.name} (${da.info})</li>
|
||||
%endfor
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
%for pa in trans.app.model.Dataset.permitted_actions:
|
||||
<% pa_val = trans.app.security_agent.permitted_actions.__dict__[pa] %>
|
||||
<input type="checkbox" name="gda_actions_${gda.id}" value="${pa}"
|
||||
%if pa_val in permissions[1]:
|
||||
checked
|
||||
%endif
|
||||
/>
|
||||
${pa_val}<br/>${trans.app.security_agent.get_permitted_action_description(pa)}<br/>
|
||||
<br/>
|
||||
%endfor
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<% ctr += 1 %>
|
||||
%endfor
|
||||
<tr><td colspan="3"><center><button name="group_dataset_permitted_actions_edit_button" value="group_dataset_permitted_actions_edit">Update</button></center></td></tr>
|
||||
</form>
|
||||
%endif
|
||||
</table>
|
||||
</div>
|
||||
@@ -0,0 +1,54 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%
|
||||
from galaxy.web.controllers.admin import entities, unentities
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
%>
|
||||
|
||||
<% gn = unescape( group_name, unentities ) %>
|
||||
|
||||
<%def name="title()">Group Members</%def>
|
||||
|
||||
%if msg:
|
||||
<div class="donemessage">${msg}</div>
|
||||
%endif
|
||||
|
||||
<h2>Members of Group '${gn}'</h2>
|
||||
|
||||
%if not deleted:
|
||||
<ul class="manage-table-actions">
|
||||
<li>
|
||||
<a class="action-button" href="${h.url_for( controller='admin', action='group_members_edit', group_id=group_id, group_name=group_name )}">
|
||||
Manage group membership
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
%endif
|
||||
|
||||
%if len( members ) == 0:
|
||||
|
||||
Group '${gn}' contains no members
|
||||
|
||||
%else:
|
||||
|
||||
<table cellpadding="0" cellspacing="0" width="100%" class="colored">
|
||||
<tr class="header"><td>Username</td></tr>
|
||||
<% ctr = 0 %>
|
||||
%for member in members:
|
||||
<% email = unescape( member[1], unentities ) %>
|
||||
%if ctr % 2 == 1:
|
||||
<tr class="odd_row">
|
||||
%else:
|
||||
<tr class="tr">
|
||||
%endif
|
||||
<td><a href="${h.url_for( controller='admin',
|
||||
action='specified_users_groups',
|
||||
user_id=member[0],
|
||||
user_email=member[1] )}">${email}</a></td>
|
||||
</tr>
|
||||
<% ctr += 1 %>
|
||||
%endfor
|
||||
</table>
|
||||
|
||||
%endif
|
||||
@@ -0,0 +1,112 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%
|
||||
from galaxy.web.controllers.admin import entities, unentities
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
%>
|
||||
|
||||
<%def name="title()">Manage Group Membership</%def>
|
||||
|
||||
%if msg:
|
||||
<div class="donemessage">${msg}</div>
|
||||
%endif
|
||||
|
||||
<% gn = unescape( group_name, unentities ) %>
|
||||
|
||||
<h2>Members of group '${gn}'</h2>
|
||||
|
||||
<table cellpadding="0" cellspacing="0" width="100%" class="colored">
|
||||
<tr><td> </td></tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0">
|
||||
<form name="group_create" action="${h.url_for( controller='admin', action='update_group_members', group_id=group_id, group_name=group_name )}" method="post" >
|
||||
%if len( users ) == 0:
|
||||
<tr><td>There are no Galaxy users</td></tr>
|
||||
%else:
|
||||
<tr>
|
||||
<td>
|
||||
|<a href="#A">A</a>|<a href="#B">B</a>|<a href="#C">C</a>|<a href="#D">D</a>|<a href="#E">E</a>|<a href="#F">F</a>
|
||||
|<a href="#G">G</a>|<a href="#H">H</a>|<a href="#I">I</a>|<a href="#J">J</a>|<a href="#K">K</a>|<a href="#L">L</a>
|
||||
|<a href="#M">M</a>|<a href="#N">N</a>|<a href="#O">O</a>|<a href="#P">P</a>|<a href="#Q">Q</a>|<a href="#R">R</a>
|
||||
|<a href="#S">S</a>|<a href="#T">T</a>|<a href="#U">U</a>|<a href="#V">V</a>|<a href="#W">W</a>|<a href="#X">X</a>
|
||||
|<a href="#Y">Y</a>|<a href="#Z">Z</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<%
|
||||
ctr = 0
|
||||
anchors = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
|
||||
anchor_loc = 0
|
||||
anchored = False
|
||||
curr_anchor = 'A'
|
||||
%>
|
||||
%for user in users:
|
||||
<%
|
||||
email = unescape( user[1], unentities )
|
||||
check = False
|
||||
%>
|
||||
%for member in members:
|
||||
<% member_email = unescape( member[1], unentities ) %>
|
||||
%if email == member_email:
|
||||
<%
|
||||
check = True
|
||||
break
|
||||
%>
|
||||
%endif
|
||||
%endfor
|
||||
%if not email.upper().startswith( curr_anchor ):
|
||||
<% anchored = False %>
|
||||
%endif
|
||||
%if ctr % 2 == 1:
|
||||
<tr class="odd_row">
|
||||
%else:
|
||||
<tr class="tr">
|
||||
%endif
|
||||
<td>
|
||||
%if email.upper().startswith( curr_anchor ):
|
||||
%if not anchored:
|
||||
<a name="${curr_anchor}"><hr/></a><br/>
|
||||
<% anchored = True %>
|
||||
%endif
|
||||
%if check:
|
||||
<input type="checkbox" name="members" value="${user[0]}" checked/> ${email}
|
||||
%else:
|
||||
<input type="checkbox" name="members" value="${user[0]}"/> ${email}
|
||||
%endif
|
||||
%else:
|
||||
%for anchor in anchors[ anchor_loc: ]:
|
||||
%if email.upper().startswith( anchor ):
|
||||
%if not anchored:
|
||||
<a name="${anchor}"><hr/></a><br/>
|
||||
<%
|
||||
curr_anchor = anchor
|
||||
anchored = True
|
||||
%>
|
||||
%endif
|
||||
%if check:
|
||||
<input type="checkbox" name="members" value="${user[0]}" checked/> ${email}
|
||||
%else:
|
||||
<input type="checkbox" name="members" value="${user[0]}"/> ${email}
|
||||
%endif
|
||||
<%
|
||||
anchor_loc = anchors.index( anchor )
|
||||
break
|
||||
%>
|
||||
%endif
|
||||
%endfor
|
||||
%endif
|
||||
</td>
|
||||
<% ctr += 1 %>
|
||||
%endfor
|
||||
</td>
|
||||
</tr>
|
||||
%endif
|
||||
<tr><td><center><button name="group_members_edit_button" value="update_group_members">Update Membership</button></center></td></tr>
|
||||
</form>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -0,0 +1,137 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%
|
||||
from galaxy.web.controllers.admin import entities, unentities
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
%>
|
||||
|
||||
## 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='mark_group_deleted', group_id=group[0] )}">Mark group deleted</a></td>
|
||||
</%def>
|
||||
|
||||
<%def name="title()">Groups</%def>
|
||||
|
||||
%if msg:
|
||||
<div class="donemessage">${msg}</div>
|
||||
%endif
|
||||
|
||||
<h2>Groups</h2>
|
||||
|
||||
<ul class="manage-table-actions">
|
||||
<li>
|
||||
<a class="action-button" href="${h.url_for( controller='admin', action='create_group' )}">
|
||||
Create a new group
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="action-button" href="${h.url_for( controller='admin', action='deleted_groups' )}">
|
||||
Manage deleted groups
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
%if len( groups ) == 0:
|
||||
There are no Galaxy groups
|
||||
%else:
|
||||
<table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
|
||||
|
||||
<%
|
||||
render_quick_find = len( groups ) > 50
|
||||
ctr = 0
|
||||
%>
|
||||
%if render_quick_find:
|
||||
<%
|
||||
anchors = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
|
||||
anchor_loc = 0
|
||||
anchored = False
|
||||
curr_anchor = 'A'
|
||||
%>
|
||||
<tr style="background: #EEE">
|
||||
<td colspan="6" style="text-align: center; border-bottom: 1px solid #D8B365">
|
||||
Jump to letter:
|
||||
%for a in anchors:
|
||||
| <a href="#${a}">${a}</a>
|
||||
%endfor
|
||||
</td>
|
||||
</tr>
|
||||
%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:
|
||||
<% group_name = unescape( group[1], unentities ) %>
|
||||
%if render_quick_find and not group_name.upper().startswith( curr_anchor ):
|
||||
<% anchored = False %>
|
||||
%endif
|
||||
<tr>
|
||||
%if ctr % 2 == 1:
|
||||
<div class="odd_row">
|
||||
%endif
|
||||
%if render_quick_find and group_name.upper().startswith( curr_anchor ):
|
||||
%if not anchored:
|
||||
<tr>
|
||||
<td colspan="6" class=panel-body">
|
||||
<a name="${curr_anchor}"></a>
|
||||
<div style="float: right;"><a href="#TOP">quick find</a></div>
|
||||
<% anchored = True %>
|
||||
</td>
|
||||
</tr>
|
||||
%endif
|
||||
${render_row( group_name, group )}
|
||||
%elif render_quick_find:
|
||||
%for anchor in anchors[ anchor_loc: ]:
|
||||
%if group_name.upper().startswith( anchor ):
|
||||
%if not anchored:
|
||||
<tr>
|
||||
<td colspan="6" class="panel-body">
|
||||
<a name="${anchor}"></a>
|
||||
<div style="float: right;"><a href="#TOP">quick find</a></div>
|
||||
<%
|
||||
curr_anchor = anchor
|
||||
anchored = True
|
||||
%>
|
||||
</td>
|
||||
</tr>
|
||||
%endif
|
||||
${render_row( group_name, group )}
|
||||
<%
|
||||
anchor_loc = anchors.index( anchor )
|
||||
break
|
||||
%>
|
||||
%endif
|
||||
%endfor
|
||||
%else:
|
||||
${render_row( group_name, group )}
|
||||
%endif
|
||||
%if ctr % 2 == 1:
|
||||
</div>
|
||||
%endif
|
||||
<% ctr += 1 %>
|
||||
</tr>
|
||||
%endfor
|
||||
%endif
|
||||
</table>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%def name="title()">Dataset Security</%def>
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Dataset Security</div>
|
||||
<table align="center" class="colored">
|
||||
%if msg:
|
||||
<tr><td><p class="ok_bgr">${msg}</p></td></tr>
|
||||
%endif
|
||||
<tr><td><a href="${h.url_for( controller='admin', action='groups' )}">Groups</a></td></tr>
|
||||
<tr><td><a href="${h.url_for( controller='admin', action='users' )}">Users</a></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -0,0 +1,72 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%
|
||||
from galaxy.web.controllers.admin import entities, unentities
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
%>
|
||||
|
||||
<% email = unescape( user_email, unentities ) %>
|
||||
|
||||
<%def name="title()">Group Membership</%def>
|
||||
|
||||
%if msg:
|
||||
<div class="donemessage">${msg}</div>
|
||||
%endif
|
||||
|
||||
<h2>Groups of which '${email}' is a member</h2>
|
||||
|
||||
%if len( groups ) == 0:
|
||||
|
||||
User '${email}' belongs to no groups
|
||||
|
||||
%else:
|
||||
|
||||
<table class="colored" cellpadding="0" cellspacing="0" width="100%">
|
||||
|
||||
<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">
|
||||
%else:
|
||||
<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
|
||||
|
||||
</table>
|
||||
|
||||
%endif
|
||||
@@ -0,0 +1,85 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%
|
||||
from galaxy.web.controllers.admin import entities, unentities
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
%>
|
||||
|
||||
<%def name="title()">Users</%def>
|
||||
|
||||
%if msg:
|
||||
<div class="donemessage">${msg}</div>
|
||||
%endif
|
||||
|
||||
<h2>Users</h2>
|
||||
|
||||
%if len( users ) == 0:
|
||||
There are no Galaxy users
|
||||
%else:
|
||||
<table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
|
||||
<%
|
||||
render_quick_find = len( users ) > 50
|
||||
%>
|
||||
%if render_quick_find:
|
||||
<%
|
||||
anchors = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
|
||||
anchor_loc = 0
|
||||
anchored = False
|
||||
curr_anchor = 'A'
|
||||
%>
|
||||
<tr style="background: #EEE">
|
||||
<td style="border-bottom: 1px solid #D8B365; text-align: center;">
|
||||
Jump to letter:
|
||||
%for a in anchors:
|
||||
| <a href="#${a}">${a}</a>
|
||||
%endfor
|
||||
</td>
|
||||
</tr>
|
||||
%endif
|
||||
<tr class="header"><td>Email address</td></tr>
|
||||
%for ctr, user in enumerate( users ):
|
||||
<% email = unescape( user[1], unentities ) %>
|
||||
%if render_quick_find and not email.upper().startswith( curr_anchor ):
|
||||
<% anchored = False %>
|
||||
%endif
|
||||
<tr
|
||||
%if ctr % 2 == 0:
|
||||
class="odd_row"
|
||||
%endif
|
||||
>
|
||||
<td>
|
||||
%if render_quick_find and email.upper().startswith( curr_anchor ):
|
||||
%if not anchored:
|
||||
<a name="${curr_anchor}"></a>
|
||||
<div style="float: right;"><a href="#TOP">top</a></div>
|
||||
<% anchored = True %>
|
||||
%endif
|
||||
<a href="${h.url_for( controller='admin', action='specified_users_groups', user_id=user[0], user_email=user[1] )}">${email}</a>
|
||||
%elif render_quick_find:
|
||||
%for anchor in anchors[ anchor_loc: ]:
|
||||
%if email.upper().startswith( anchor ):
|
||||
%if not anchored:
|
||||
<a name="${anchor}"></a>
|
||||
<div style="float: right;"><a href="#TOP">top</a></div>
|
||||
<%
|
||||
curr_anchor = anchor
|
||||
anchored = True
|
||||
%>
|
||||
%endif
|
||||
<a href="${h.url_for( controller='admin', action='specified_users_groups', user_id=user[0], user_email=user[1] )}">${email}</a>
|
||||
<%
|
||||
anchor_loc = anchors.index( anchor )
|
||||
break
|
||||
%>
|
||||
%endif
|
||||
%endfor
|
||||
%else:
|
||||
<a href="${h.url_for( controller='admin', action='specified_users_groups', user_id=user[0], user_email=user[1] )}">${email}</a>
|
||||
%endif
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</table>
|
||||
|
||||
%endif
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
<%inherit file="/base_panels.mako"/>
|
||||
|
||||
<%def name="init()">
|
||||
<%
|
||||
self.has_left_panel=True
|
||||
self.has_right_panel=False
|
||||
self.active_view="admin"
|
||||
%>
|
||||
</%def>
|
||||
|
||||
<%def name="stylesheets()">
|
||||
|
||||
${parent.stylesheets()}
|
||||
|
||||
## TODO: Clean up these styles and move into panel_layout.css (they are
|
||||
## used here and in the editor).
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
#left {
|
||||
background: #C1C9E5 url(${h.url_for('/static/style/menu_bg.png')}) top repeat-x;
|
||||
}
|
||||
|
||||
div.toolMenu {
|
||||
margin: 5px;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
div.toolSectionPad {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 5px;
|
||||
font-size: 0px;
|
||||
}
|
||||
div.toolSectionDetailsInner {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
div.toolSectionTitle {
|
||||
padding-bottom: 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
div.toolMenuGroupHeader {
|
||||
font-weight: bold;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
color: #333;
|
||||
font-style: italic;
|
||||
border-bottom: dotted #333 1px;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
div.toolTitle {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
margin-left: 16px;
|
||||
margin-right: 10px;
|
||||
display: list-item;
|
||||
list-style: square outside;
|
||||
}
|
||||
a:link, a:visited, a:active
|
||||
{
|
||||
color: #303030;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
</%def>
|
||||
|
||||
<%def name="left_panel()">
|
||||
<div class="unified-panel-header" unselectable="on">
|
||||
<div class='unified-panel-header-inner'>Administration</div>
|
||||
</div>
|
||||
<div class="unified-panel-body" style="overflow: auto;">
|
||||
<div class="toolMenu">
|
||||
<div class="toolSectionList">
|
||||
<div class="toolSectionTitle">
|
||||
<span>Security</span>
|
||||
</div>
|
||||
<div class="toolSectionBody">
|
||||
<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>
|
||||
</div>
|
||||
<div class="toolSectionPad"></div>
|
||||
<div class="toolSectionTitle">
|
||||
<span>Data</span>
|
||||
</div>
|
||||
<div class="toolSectionBody">
|
||||
<div class="toolSectionBg">
|
||||
<div class="toolTitle"><a href="${h.url_for( action='libraries' )}" target="galaxy_main">Manage libraries</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toolSectionPad"></div>
|
||||
<div class="toolSectionTitle">
|
||||
<span>Tools</span>
|
||||
</div>
|
||||
<div class="toolSectionBody">
|
||||
<div class="toolSectionBg">
|
||||
<div class="toolTitle"><a href="${h.url_for( action='reload_tool' )}" target="galaxy_main">Reload a tool's configuration</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
<%def name="center_panel()">
|
||||
|
||||
<iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src=""> </iframe>
|
||||
|
||||
</%def>
|
||||
@@ -0,0 +1,179 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%namespace file="common.mako" import="render_dataset" />
|
||||
|
||||
<%def name="title()">Import from Library</%def>
|
||||
<%def name="stylesheets()">
|
||||
<link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
|
||||
<link href="${h.url_for('/static/style/library.css')}" rel="stylesheet" type="text/css" />
|
||||
</%def>
|
||||
|
||||
<script type="text/javascript">
|
||||
//var q = jQuery.noConflict();
|
||||
$( document ).ready( function () {
|
||||
// Hide all the folder contents
|
||||
$("ul").filter("ul#subFolder").hide();
|
||||
// Handle the hide/show triangles
|
||||
$("li.libraryOrFolderRow").wrap( "<a href='#' class='expandLink'></a>" ).click( function() {
|
||||
var contents = $(this).parent().next("ul");
|
||||
if ( this.id == "libraryRow" ) {
|
||||
var icon_open = "${h.url_for( '/static/images/silk/book_open.png' )}";
|
||||
var icon_closed = "${h.url_for( '/static/images/silk/book.png' )}";
|
||||
} else {
|
||||
var icon_open = "${h.url_for( '/static/images/silk/folder_page.png' )}";
|
||||
var icon_closed = "${h.url_for( '/static/images/silk/folder.png' )}";
|
||||
}
|
||||
if ( contents.is(":visible") ) {
|
||||
contents.slideUp("fast");
|
||||
$(this).children().find("img.expanderIcon").each( function() { this.src = "${h.url_for( '/static/images/silk/resultset_next.png' )}"; });
|
||||
$(this).children().find("img.rowIcon").each( function() { this.src = icon_closed; });
|
||||
} else {
|
||||
contents.slideDown("fast");
|
||||
$(this).children().find("img.expanderIcon").each( function() { this.src = "${h.url_for( '/static/images/silk/resultset_bottom.png' )}"; });
|
||||
$(this).children().find("img.rowIcon").each( function() { this.src = icon_open; });
|
||||
}
|
||||
});
|
||||
// Hide all dataset bodies
|
||||
$("div.historyItemBody").hide();
|
||||
// Handle the dataset body hide/show link.
|
||||
$("div.historyItemWrapper").each( function() {
|
||||
var id = this.id;
|
||||
var li = $(this).parent();
|
||||
var body = $(this).children( "div.historyItemBody" );
|
||||
var peek = body.find( "pre.peek" )
|
||||
$(this).children( ".historyItemTitleBar" ).find( ".historyItemTitle" ).wrap( "<a href='#'></a>" ).click( function() {
|
||||
if ( body.is(":visible") ) {
|
||||
if ( $.browser.mozilla ) { peek.css( "overflow", "hidden" ) }
|
||||
body.slideUp( "fast" );
|
||||
li.removeClass( "datasetHighlighted" );
|
||||
}
|
||||
else {
|
||||
body.slideDown( "fast", function() {
|
||||
if ( $.browser.mozilla ) { peek.css( "overflow", "auto" ); }
|
||||
});
|
||||
li.addClass( "datasetHighlighted" );
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
function checkForm() {
|
||||
if ( $("select#with-selected-select option:selected").text() == "delete" ) {
|
||||
if ( confirm( "Are you sure you want to delete these datasets?" ) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<%def name="render_folder( parent, parent_pad )">
|
||||
<%
|
||||
##if not trans.app.security_agent.check_folder_contents( trans.user, parent ):
|
||||
## return ""
|
||||
pad = parent_pad + 20
|
||||
if parent_pad == 0:
|
||||
expander = "/static/images/silk/resultset_bottom.png"
|
||||
folder = "/static/images/silk/folder_page.png"
|
||||
subfolder = False
|
||||
else:
|
||||
expander = "/static/images/silk/resultset_next.png"
|
||||
folder = "/static/images/silk/folder.png"
|
||||
subfolder = True
|
||||
%>
|
||||
<li class="folderRow libraryOrFolderRow" style="padding-left: ${pad}px;">
|
||||
<div class="rowTitle">
|
||||
<img src="${h.url_for( expander )}" class="expanderIcon"/><img src="${h.url_for( folder )}" class="rowIcon"/>
|
||||
${parent.name}
|
||||
%if parent.description:
|
||||
<i>- ${parent.description}</i>
|
||||
%endif
|
||||
<a id="folder-${parent.id}-popup" class="popup-arrow" style="display: none;">▼</a>
|
||||
</div>
|
||||
<div popupmenu="folder-${parent.id}-popup">
|
||||
<a class="action-button" href="${h.url_for( action='dataset', folder_id=parent.id )}">Add new dataset to this folder</a>
|
||||
<a class="action-button" href="${h.url_for( action='folder', new=True, id=parent.id )}">Create a new subfolder in this folder</a>
|
||||
<a class="action-button" href="${h.url_for( action='folder', rename=True, id=parent.id )}">Rename this folder</a>
|
||||
%if subfolder:
|
||||
<a class="action-button" confirm="Are you sure you want to delete folder '${parent.name}'?" href="${h.url_for( action='folder', delete=True, id=parent.id )}">Remove this folder and its contents</a>
|
||||
%endif
|
||||
</div>
|
||||
</li>
|
||||
%if subfolder:
|
||||
<ul id="subFolder">
|
||||
%else:
|
||||
<ul>
|
||||
%endif
|
||||
%for folder in parent.active_folders:
|
||||
${render_folder( folder, pad )}
|
||||
%endfor
|
||||
%for dataset in parent.active_datasets:
|
||||
##%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset=dataset.dataset ):
|
||||
<li class="datasetRow" style="padding-left: ${pad + 18}px;">${render_dataset( dataset )}</li>
|
||||
##%endif
|
||||
%endfor
|
||||
</ul>
|
||||
</%def>
|
||||
|
||||
<h2>Libraries</h2>
|
||||
|
||||
%if message:
|
||||
<%
|
||||
try:
|
||||
messagetype
|
||||
except:
|
||||
messagetype = "done"
|
||||
%>
|
||||
<p />
|
||||
<div class="${messagetype}message">
|
||||
${message}
|
||||
</div>
|
||||
<p />
|
||||
%endif
|
||||
|
||||
<ul class="manage-table-actions">
|
||||
<li>
|
||||
<a class="action-button" href="${h.url_for( action='library', new=True )}">
|
||||
<img src="${h.url_for( '/static/images/silk/add.png' )}" />
|
||||
<span>Create a new library</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form name="update_multiple_datasets" action="${h.url_for( action='datasets' )}" onSubmit="javascript:return checkForm();" method="post">
|
||||
<ul>
|
||||
%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>
|
||||
<th width="*">
|
||||
<img src="${h.url_for( '/static/images/silk/resultset_bottom.png' )}" class="expanderIcon"/><img src="${h.url_for( '/static/images/silk/book_open.png' )}" class="rowIcon"/>
|
||||
${library.name}
|
||||
%if library.description:
|
||||
<i>- ${library.description}</i>
|
||||
%endif
|
||||
<a id="library-${library.id}-popup" class="popup-arrow" style="display: none;">▼</a>
|
||||
<div popupmenu="library-${library.id}-popup">
|
||||
<a class="action-button" href="${h.url_for( action='library', rename=True, id=library.id )}">Rename this library</a>
|
||||
<a class="action-button" confirm="Are you sure you want to delete library '${library.name}'?" href="${h.url_for( action='library', delete=True, id=library.id )}">Remove this library and its contents</a>
|
||||
</div>
|
||||
</th>
|
||||
<th width="100">Format</th>
|
||||
<th width="50">Db</th>
|
||||
<th width="200">Info</th>
|
||||
</tr></table></div></li>
|
||||
<ul>
|
||||
${render_folder( library.root_folder, 0 )}
|
||||
</ul>
|
||||
<br/>
|
||||
##%endif
|
||||
%endfor
|
||||
</ul>
|
||||
<div style="float: right;">
|
||||
With selected datasets:
|
||||
<select name="action" id="with-selected-select">
|
||||
<option value="None" selected></option>
|
||||
<option value="edit">edit permissions</option>
|
||||
<option value="delete">delete</option>
|
||||
</select>
|
||||
<input type="submit" class="primary-button" name="with-selected" id="with-selected-submit" value="go"/>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,253 @@
|
||||
<%def name="render_permissions_forms( data_obj )">
|
||||
<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#group_" + this.value).hide();
|
||||
});
|
||||
// handle events
|
||||
q("input.groupCheckbox").click( function() {
|
||||
if ( q(this).is(":checked") ) {
|
||||
q("div#group_" + this.value).slideDown("fast");
|
||||
} else {
|
||||
q("div#group_" + this.value).slideUp("fast");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<%
|
||||
redirect = None
|
||||
id = None
|
||||
if isinstance( data_obj, trans.app.model.LibraryFolderDatasetAssociation ):
|
||||
dataset = data_obj.dataset
|
||||
redirect = ("lid", data_obj.id)
|
||||
elif isinstance( data_obj, list ):
|
||||
dataset = data_obj[0].dataset
|
||||
id = ",".join( [ str(d.dataset.id) for d in data_obj ] )
|
||||
if isinstance( data_obj[0], trans.app.model.LibraryFolderDatasetAssociation ):
|
||||
redirect = ("lid", ",".join( [ str(d.id) for d in data_obj ] ) )
|
||||
else:
|
||||
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="toolFormBody">
|
||||
<form name="edit_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
|
||||
<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/>
|
||||
</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
|
||||
<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>
|
||||
</div>
|
||||
<div class="form-row"><input type="submit" name="create_group_associations" value="Save"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<p/>
|
||||
|
||||
</%def>
|
||||
|
||||
<%doc>
|
||||
Shamelessly stolen from history... this needs to be cleaned up to remove a
|
||||
bunch of stuff that doesn't apply to library datasets (like state, etc).
|
||||
</%doc>
|
||||
|
||||
## Render the dataset `data`
|
||||
<%def name="render_dataset( data )">
|
||||
<%
|
||||
if data.state in ['no state','',None]:
|
||||
data_state = "queued"
|
||||
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:
|
||||
<div class="historyItemWrapper historyItem historyItem-${data_state}" id="historyItem-${data.id}">
|
||||
%endif
|
||||
|
||||
## Header row for history items (name, state, action buttons)
|
||||
|
||||
<div style="overflow: hidden;" class="historyItemTitleBar">
|
||||
<div style="float: left; padding-right: 3px;">
|
||||
<div style='display: none;' id="progress-${data.id}">
|
||||
<img src="${h.url_for('/static/style/data_running.gif')}" border="0" align="middle" >
|
||||
</div>
|
||||
%if data_state == 'running':
|
||||
<div><img src="${h.url_for('/static/style/data_running.gif')}" border="0" align="middle"></div>
|
||||
%elif data_state != 'ok':
|
||||
<div><img src="${h.url_for( "/static/style/data_%s.png" % data_state )}" border="0" align="middle"></div>
|
||||
%endif
|
||||
</div>
|
||||
<%doc>
|
||||
<div style="float: right;">
|
||||
<a href="${h.url_for( controller='dataset', dataset_id=data.id, action='display', filename='index')}" target="galaxy_main"><img src="${h.url_for('/static/images/eye_icon.png')}" rollover="${h.url_for('/static/images/eye_icon_dark.png')}" width='16' height='16' alt='display data' title='display data' class='displayButton' border='0'></a>
|
||||
<a href="${h.url_for( action='edit', id=data.id )}" target="galaxy_main"><img src="${h.url_for('/static/images/pencil_icon.png')}" rollover="${h.url_for('/static/images/pencil_icon_dark.png')}" width='16' height='16' alt='edit attributes' title='edit attributes' class='editButton' border='0'></a>
|
||||
<a href="${h.url_for( action='delete', id=data.id )}" class="historyItemDelete" id="historyItemDelter-${data.id}"><img src="${h.url_for('/static/images/delete_icon.png')}" rollover="${h.url_for('/static/images/delete_icon_dark.png')}" width='16' height='16' alt='delete' class='deleteButton' border='0'></a>
|
||||
</div>
|
||||
</%doc>
|
||||
<table cellspacing="0" cellpadding="0" border="0" width="100%"><tr>
|
||||
<td width="*">
|
||||
<input type="checkbox" name="dataset_ids" value="${data.id}"/>
|
||||
<span class="historyItemTitle"><b>${data.display_name()}</b></span>
|
||||
<a id="dataset-${data.id}-popup" class="popup-arrow" style="display: none;">▼</a>
|
||||
<div popupmenu="dataset-${data.id}-popup">
|
||||
<a class="action-button" href="${h.url_for( action='dataset', id=data.id )}">Edit this dataset's attributes and permissions</a>
|
||||
<a class="action-button" confirm="Are you sure you want to delete dataset '${data.name}'?" href="${h.url_for( action='dataset', delete=True, id=data.id )}">Remove this dataset</a>
|
||||
</div>
|
||||
</td>
|
||||
<td width="100">${data.ext}</td>
|
||||
<td width="50"><span class="${data.dbkey}">${data.dbkey}</span></td>
|
||||
<td width="200">${data.info}</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
|
||||
## Body for history items, extra info and actions, data "peek"
|
||||
|
||||
<div id="info${data.id}" class="historyItemBody">
|
||||
<div>
|
||||
${data.blurb}
|
||||
</div>
|
||||
<div>
|
||||
%if data.has_data:
|
||||
<a href="${h.url_for( action='display', id=data.id, tofile='yes', toext='data.ext' )}" target="_blank">save</a>
|
||||
%for display_app in data.datatype.get_display_types():
|
||||
<% display_links = data.datatype.get_display_links( data, display_app, app, request.base ) %>
|
||||
%if len( display_links ) > 0:
|
||||
| ${data.datatype.get_display_label(display_app)}
|
||||
%for display_name, display_link in display_links:
|
||||
<a target="_blank" href="${display_link}">${display_name}</a>
|
||||
%endfor
|
||||
%endif
|
||||
%endfor
|
||||
%endif
|
||||
</div>
|
||||
%if data.peek != "no peek":
|
||||
<div><pre id="peek${data.id}" class="peek">${data.display_peek()}</pre></div>
|
||||
%endif
|
||||
## Recurse for child datasets
|
||||
%if len( data.children ) > 0:
|
||||
## FIXME: This should not be in the template, there should
|
||||
## be a 'visible_children' method on dataset.
|
||||
<%
|
||||
children = []
|
||||
for child in data.children:
|
||||
if child.visible:
|
||||
children.append( child )
|
||||
%>
|
||||
%if len( children ) > 0:
|
||||
<div>
|
||||
There are ${len( children )} secondary datasets.
|
||||
%for idx, child in enumerate(children):
|
||||
${render_dataset( child, idx + 1 )}
|
||||
%endfor
|
||||
</div>
|
||||
%endif
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
@@ -0,0 +1,92 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%namespace file="common.mako" import="render_permissions_forms" />
|
||||
|
||||
<%def name="title()">Edit Dataset Attributes</%def>
|
||||
|
||||
<%def name="datatype( dataset, datatypes )">
|
||||
<select name="datatype">
|
||||
## $datatypes.sort()
|
||||
%for ext in datatypes:
|
||||
%if dataset.ext == ext:
|
||||
<option value="${ext}" selected="yes">${ext}</option>
|
||||
%else:
|
||||
<option value="${ext}">${ext}</option>
|
||||
%endif
|
||||
%endfor
|
||||
</select>
|
||||
</%def>
|
||||
|
||||
${render_permissions_forms( dataset )}
|
||||
|
||||
%if not isinstance( dataset, list ):
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Edit Attributes</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="edit_attributes" action="${h.url_for( controller='admin', action='dataset' )}" method="post">
|
||||
<input type="hidden" name="id" value="${dataset.id}">
|
||||
<div class="form-row">
|
||||
<label>Name:</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<input type="text" name="name" value="${dataset.name}" size="40">
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Info:</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<input type="text" name="info" value="${dataset.info}" size="40">
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
%for element in metadata:
|
||||
<div class="form-row">
|
||||
<label>${element.spec.desc}:</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
${element.get_html()}
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
%endfor
|
||||
<div class="form-row">
|
||||
<input type="submit" name="save" value="Save">
|
||||
</div>
|
||||
</form>
|
||||
<form name="auto_detect" action="${h.url_for( controller='admin', action='dataset' )}" method="post">
|
||||
<input type="hidden" name="id" value="${dataset.id}">
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<input type="submit" name="detect" value="Auto-detect">
|
||||
</div>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
This will inspect the dataset and attempt to correct the above column values
|
||||
if they are not accurate.
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<p/>
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Change data type</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="change_datatype" action="${h.url_for( controller='admin', action='dataset' )}" method="post">
|
||||
<input type="hidden" name="id" value="${dataset.id}">
|
||||
<div class="form-row">
|
||||
<label>New Type:</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
${datatype( dataset, datatypes )}
|
||||
</div>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
This will change the datatype of the existing dataset
|
||||
but <i>not</i> modify its contents. Use this if Galaxy
|
||||
has incorrectly guessed the type of your dataset.
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="submit" name="change" value="Save">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<p/>
|
||||
%endif
|
||||
<a href="${h.url_for( controller='admin', action='library_browser' )}">Return to the library browser</a>
|
||||
@@ -0,0 +1,115 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<% import os %>
|
||||
|
||||
<%def name="title()">Create New Library Dataset</%def>
|
||||
%if msg:
|
||||
<p class="ok_bgr">${msg}</p></td></tr>
|
||||
%endif
|
||||
<div class="toolForm" id="new_dataset">
|
||||
<div class="toolFormTitle">Create a new Library Dataset</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="tool_form" action="${h.url_for( controller='admin', action='dataset' )}" enctype="multipart/form-data" method="post">
|
||||
<input type="hidden" name="folder_id" value="${folder_id}">
|
||||
<div class="form-row">
|
||||
<label>File:</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;"><input type="file" name="file_data"></div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>URL/Text:</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;"><textarea name="url_paste" rows="5" cols="35"></textarea></div>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
Here you may specify a list of URLs (one per line) or paste the contents of a file.
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
%if trans.app.config.library_import_dir is not None:
|
||||
<div class="form-row">
|
||||
<label>Server Directory</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<select name="server_dir">
|
||||
<option>None</option>
|
||||
%for dir in os.listdir( trans.app.config.library_import_dir ):
|
||||
<option>${dir}</option>
|
||||
%endfor
|
||||
</select>
|
||||
</div>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
You may also choose to upload all files in a subdirectory of <strong>${trans.app.config.library_import_dir}</strong> on the Galaxy server.
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
%endif
|
||||
<div class="form-row">
|
||||
<label>Convert spaces to tabs:</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;"><div><input type="checkbox" name="space_to_tab" value="Yes">Yes</div></div>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
Use this option if you are entering intervals by hand.
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>File Format:</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<select name="extension">
|
||||
<option value="auto" selected>Auto-detect</option>
|
||||
%for file_format in file_formats:
|
||||
<option value="${file_format}">${file_format}</option>
|
||||
%endfor
|
||||
</select>
|
||||
</div>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
Which format? See help below
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Genome:</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<select name="dbkey">
|
||||
%for dbkey in dbkeys:
|
||||
%if dbkey[1] == last_used_build:
|
||||
<option value="${dbkey[1]}" selected>${dbkey[0]}</option>
|
||||
%else:
|
||||
<option value="${dbkey[1]}">${dbkey[0]}</option>
|
||||
%endif
|
||||
%endfor
|
||||
</select>
|
||||
</div>
|
||||
<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>
|
||||
%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.
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
<div class="form-row">
|
||||
<input type="submit" class="primary-button" name="create_dataset" value="Add Dataset to Folder">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%
|
||||
from galaxy.web.controllers.admin import entities, unentities
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
%>
|
||||
|
||||
<%def name="title()">Specified Users Group Libraries{</%def>
|
||||
<%
|
||||
gn = unescape( group_name, unentities )
|
||||
email = unescape( user_email, unentities )
|
||||
%>
|
||||
<div class="toolForm">
|
||||
<div class="form-row">
|
||||
<a href="${h.url_for( controller='admin', action='libraries' )}">Libraries</a> |
|
||||
<a href="${h.url_for( controller='admin', action='groups' )}">Groups</a> |
|
||||
<a href="${h.url_for( controller='admin', action='users' )}">Users</a>
|
||||
</div>
|
||||
<div class="toolFormTitle">Libraries containing datasets associated with group '${gn}' that user '${email}' can access</div>
|
||||
<div class="toolFormBody">
|
||||
%for library in libraries:
|
||||
<div class="form-row">
|
||||
<a href="${h.url_for( controller='admin', action='library', id=library.id )}">${library.name}</a>
|
||||
</div>
|
||||
%endfor
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,29 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
%if msg:
|
||||
<div class="donemessage">${msg}</div>
|
||||
%endif
|
||||
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Reload Tool</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="tool_reload" action="${h.url_for( controller='admin', action='tool_reload' )}" method="post" >
|
||||
<div class="form-row">
|
||||
<label>
|
||||
Tool to reload:
|
||||
</label>
|
||||
<select name="tool_id">
|
||||
%for i, section in enumerate( toolbox.sections ):
|
||||
<optgroup label="${section.name}">
|
||||
%for t in section.tools:
|
||||
<option value="${t.id}">${t.name}</option>
|
||||
%endfor
|
||||
%endfor
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<button name="action" value="tool_reload">Reload</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,33 +0,0 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%def name="title()">Galaxy Administration</%def>
|
||||
|
||||
<table align="center" width="70%" class="border" cellpadding="5" cellspacing="5">
|
||||
<tr>
|
||||
<td>
|
||||
<h3 align="center">Galaxy Administration</h3>
|
||||
%if msg:
|
||||
<p class="ok_bgr">${msg}</p>
|
||||
%endif
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<form method="post" action="admin">
|
||||
<p>Admin password: <input type="password" name="passwd" size="8"></p>
|
||||
<p>
|
||||
Reload tool:
|
||||
<select name="tool_id">
|
||||
%for i, section in enumerate( toolbox.sections ):
|
||||
<optgroup label="${section.name}">
|
||||
%for t in section.tools:
|
||||
<option value="${t.id}">${t.name}</option>
|
||||
%endfor
|
||||
%endfor
|
||||
</select>
|
||||
<button name="action" value="tool_reload">Reload</button>
|
||||
</p>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
## This needs to be on the first line, otherwise IE6 goes into quirks mode
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<%
|
||||
self.has_left_panel=True
|
||||
self.has_right_panel=True
|
||||
self.message_box_visible=False
|
||||
self.message_box_class=""
|
||||
self.active_view=None
|
||||
%>
|
||||
|
||||
<%def name="init()">
|
||||
## Override
|
||||
</%def>
|
||||
|
||||
## Default title
|
||||
<%def name="title()">Galaxy</%def>
|
||||
|
||||
@@ -8,6 +20,22 @@
|
||||
<%def name="stylesheets()">
|
||||
<link rel="stylesheet" type="text/css" href="${h.url_for('/static/style/reset.css')}" />
|
||||
<link rel="stylesheet" type="text/css" href="${h.url_for('/static/style/panel_layout.css')}" />
|
||||
<style type="text/css">
|
||||
#center {
|
||||
%if not self.has_left_panel:
|
||||
left: 0;
|
||||
%endif
|
||||
%if not self.has_right_panel:
|
||||
right: 0;
|
||||
%endif
|
||||
}
|
||||
%if self.message_box_visible:
|
||||
#left, #left-border, #center, #right-border, #right
|
||||
{
|
||||
top: 64px;
|
||||
}
|
||||
%endif
|
||||
</style>
|
||||
</%def>
|
||||
|
||||
## Default javascripts
|
||||
@@ -27,19 +55,30 @@
|
||||
<script type="text/javascript" src="${h.url_for('/static/scripts/galaxy.panels.js')}"></script>
|
||||
<script type="text/javascript">
|
||||
ensure_dd_helper();
|
||||
var lp = make_left_panel( $("#left"), $("#center"), $("#left-border" ) );
|
||||
var rp = make_right_panel( $("#right"), $("#center"), $("#right-border" ) );
|
||||
handle_minwidth_hint = rp.handle_minwidth_hint;
|
||||
%if self.has_left_panel:
|
||||
var lp = make_left_panel( $("#left"), $("#center"), $("#left-border" ) );
|
||||
%endif
|
||||
%if self.has_right_panel:
|
||||
var rp = make_right_panel( $("#right"), $("#center"), $("#right-border" ) );
|
||||
handle_minwidth_hint = rp.handle_minwidth_hint;
|
||||
%endif
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
## Masthead
|
||||
<%def name="masthead()">
|
||||
<iframe name="galaxy_masthead" src="${h.url_for( 'masthead' )}" width="38" height="100%" frameborder="0" scroll="no" style="margin: 0; border: 0 none; width: 100%; height: 38px; overflow: hidden;"> </iframe>
|
||||
<iframe name="galaxy_masthead" src="${h.url_for( controller='root', action='masthead', active_view=self.active_view )}" width="38" height="100%" frameborder="0" scroll="no" style="margin: 0; border: 0 none; width: 100%; height: 38px; overflow: hidden;"> </iframe>
|
||||
</%def>
|
||||
|
||||
## Messagebox
|
||||
<%def name="message_box_content()">
|
||||
</%def>
|
||||
|
||||
## Document
|
||||
<html lang="en">
|
||||
|
||||
${self.init()}
|
||||
|
||||
<head>
|
||||
<title>${self.title()}</title>
|
||||
${self.javascripts()}
|
||||
@@ -53,17 +92,26 @@
|
||||
<div id="masthead">
|
||||
${self.masthead()}
|
||||
</div>
|
||||
<div id="messagebox" class="panel-${self.message_box_class}-message">
|
||||
%if self.message_box_visible:
|
||||
${self.message_box_content()}
|
||||
%endif
|
||||
</div>
|
||||
%if self.has_left_panel:
|
||||
<div id="left">
|
||||
${self.left_panel()}
|
||||
</div>
|
||||
<div id="left-border"><div id="left-border-inner" style="display: none;"></div></div>
|
||||
%endif
|
||||
<div id="center">
|
||||
${self.center_panel()}
|
||||
</div>
|
||||
%if self.has_right_panel:
|
||||
<div id="right-border"><div id="right-border-inner" style="display: none;"></div></div>
|
||||
<div id="right">
|
||||
${self.right_panel()}
|
||||
</div>
|
||||
%endif
|
||||
## Allow other body level elements
|
||||
${next.body()}
|
||||
</body>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%def name="title()">Your saved histories</%def>
|
||||
<%def name="title()">Edit Dataset Attributes</%def>
|
||||
|
||||
|
||||
<%def name="datatype( dataset, datatypes )">
|
||||
@@ -15,11 +15,19 @@
|
||||
</select>
|
||||
</%def>
|
||||
|
||||
<%
|
||||
if isinstance( data, trans.app.model.HistoryDatasetAssociation ):
|
||||
id_name = 'id'
|
||||
elif isinstance( data, trans.app.model.LibraryFolderDatasetAssociation ):
|
||||
id_name = 'lid'
|
||||
%>
|
||||
|
||||
%if ( id_name == 'id' or trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_EDIT_METADATA, dataset = data ) ):
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Edit Attributes</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="edit_attributes" action="${h.url_for( action='edit' )}" method="post">
|
||||
<input type="hidden" name="id" value="${data.id}">
|
||||
<input type="hidden" name="${id_name}" value="${data.id}">
|
||||
<div class="form-row">
|
||||
<label>
|
||||
Name:
|
||||
@@ -56,7 +64,7 @@
|
||||
</div>
|
||||
</form>
|
||||
<form name="auto_detect" action="${h.url_for( action='edit' )}" method="post">
|
||||
<input type="hidden" name="id" value="${data.id}">
|
||||
<input type="hidden" name="${id_name}" value="${data.id}">
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<input type="submit" name="detect" value="Auto-detect">
|
||||
</div>
|
||||
@@ -70,39 +78,41 @@
|
||||
|
||||
<p />
|
||||
|
||||
<% converters = data.get_converter_types() %>
|
||||
%if len( converters ) > 0:
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Convert to new format</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="convert_data" action="${h.url_for( action='edit' )}" method="post">
|
||||
<input type="hidden" name="id" value="${data.id}">
|
||||
<div class="form-row">
|
||||
<label>
|
||||
Convert to:
|
||||
</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<select name="target_type">
|
||||
%for key, value in converters.items():
|
||||
<option value="${key}">${value.name[8:]}</option>
|
||||
%endfor
|
||||
</select>
|
||||
%if id_name == 'id':
|
||||
<% converters = data.get_converter_types() %>
|
||||
%if len( converters ) > 0:
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Convert to new format</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="convert_data" action="${h.url_for( action='edit' )}" method="post">
|
||||
<input type="hidden" name="${id_name}" value="${data.id}">
|
||||
<div class="form-row">
|
||||
<label>
|
||||
Convert to:
|
||||
</label>
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<select name="target_type">
|
||||
%for key, value in converters.items():
|
||||
<option value="${key}">${value.name[8:]}</option>
|
||||
%endfor
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
This will create a new dataset with the contents of this
|
||||
dataset converted to a new format.
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
This will create a new dataset with the contents of this
|
||||
dataset converted to a new format.
|
||||
<div class="form-row">
|
||||
<input type="submit" name="convert_data" value="Convert">
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="submit" name="convert_data" value="Convert">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p />
|
||||
%endif
|
||||
%endif
|
||||
|
||||
|
||||
@@ -110,7 +120,7 @@
|
||||
<div class="toolFormTitle">Change data type</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="change_datatype" action="${h.url_for( action='edit' )}" method="post">
|
||||
<input type="hidden" name="id" value="${data.id}">
|
||||
<input type="hidden" name="${id_name}" value="${data.id}">
|
||||
<div class="form-row">
|
||||
<label>
|
||||
New Type:
|
||||
@@ -132,3 +142,104 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p />
|
||||
%else:
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">View Attributes</div>
|
||||
<div class="toolFormBody">
|
||||
<div class="form-row">
|
||||
<strong>Name:</strong> ${data.name}
|
||||
<div style="clear: both"></div>
|
||||
<strong>Info:</strong> ${data.info}
|
||||
<div style="clear: both"></div>
|
||||
<strong>Data Format:</strong> ${data.ext}
|
||||
<div style="clear: both"></div>
|
||||
%for element in metadata:
|
||||
<strong>${element.spec.desc}:</strong> ${element.value[0]}
|
||||
<div style="clear: both"></div>
|
||||
%endfor
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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
|
||||
|
||||
@@ -21,9 +21,11 @@ $(function(){
|
||||
cls += " form-row-error"
|
||||
%>
|
||||
<div class="${cls}">
|
||||
%if input.use_label:
|
||||
<label>
|
||||
${input.label}:
|
||||
</label>
|
||||
%endif
|
||||
<div style="float: left; width: 250px; margin-right: 10px;">
|
||||
<input type="${input.type}" name="${input.name}" value="${input.value}" size="40">
|
||||
</div>
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
<li><a href="${h.url_for('/history_new')}">Create</a> a new empty history</li>
|
||||
%endif
|
||||
%if app.config.enable_beta_features:
|
||||
<li><a href="${h.url_for( controller='workflow', action='build_from_current_history' )}">Construct workflow</a> from the current history</li>
|
||||
<li><a href="${h.url_for( controller='workflow', action='build_from_current_history' )}">Construct workflow</a> from the current history</li>
|
||||
%endif
|
||||
<li><a href="${h.url_for( action='history_set_default_permitted_actions' )}">Change default permitted actions</a> for the current history</li>
|
||||
<li><a href="${h.url_for( action='history_share' )}" target="galaxy_main">Share</a> current history</div>
|
||||
%endif
|
||||
<li><a href="${h.url_for( action='history_delete', id=history.id )}" confirm="Are you sure you want to delete the current history?">Delete</a> current history</div>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%def name="title()">Change Default History Permitted Actions</%def>
|
||||
|
||||
%if trans.user:
|
||||
<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 Default History Permitted Actions</div>
|
||||
<div class="toolFormBody">
|
||||
<form name="set_permitted_actions" method="post">
|
||||
<div class="form-row">
|
||||
<% user_groups = [ assoc.group for assoc in trans.user.groups ] %>
|
||||
<% cur_groups = [ assoc.group for assoc in trans.get_history().default_groups ] %>
|
||||
%for group in user_groups:
|
||||
<input type="checkbox" name="group_${group.id}" class="groupCheckbox"
|
||||
%if group in cur_groups:
|
||||
<% assoc = filter( lambda x: x.group_id == group.id, trans.get_history().default_groups )[0] %>
|
||||
checked
|
||||
%else:
|
||||
<% assoc = None %>
|
||||
%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
|
||||
|
||||
<div style="clear: both"></div>
|
||||
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
This will change the default permitted actions assigned
|
||||
to new datasets in your current history. You may also
|
||||
specify the defaults for new histories via the
|
||||
<a href="${h.url_for(controller='user')}">user options</a>.
|
||||
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="submit" name="set_permitted_actions" value="Save">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
%endif
|
||||
@@ -0,0 +1,144 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%namespace file="common.mako" import="render_dataset" />
|
||||
|
||||
<%def name="title()">Import from Library</%def>
|
||||
<%def name="stylesheets()">
|
||||
<link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
|
||||
<link href="${h.url_for('/static/style/library.css')}" rel="stylesheet" type="text/css" />
|
||||
</%def>
|
||||
|
||||
<script type="text/javascript">
|
||||
var q = jQuery.noConflict();
|
||||
q( document ).ready( function () {
|
||||
// Hide all the folder contents
|
||||
q("ul").filter("ul#subFolder").hide();
|
||||
// Handle the hide/show triangles
|
||||
q("li.libraryOrFolderRow").wrap( "<a href='#' class='expandLink'></a>" ).click( function() {
|
||||
var contents = q(this).parent().next("ul");
|
||||
if ( this.id == "libraryRow" ) {
|
||||
var icon_open = "${h.url_for( '/static/images/silk/book_open.png' )}";
|
||||
var icon_closed = "${h.url_for( '/static/images/silk/book.png' )}";
|
||||
} else {
|
||||
var icon_open = "${h.url_for( '/static/images/silk/folder_page.png' )}";
|
||||
var icon_closed = "${h.url_for( '/static/images/silk/folder.png' )}";
|
||||
}
|
||||
if ( contents.is(":visible") ) {
|
||||
contents.slideUp("fast");
|
||||
q(this).children().find("img.expanderIcon").each( function() { this.src = "${h.url_for( '/static/images/silk/resultset_next.png' )}"; });
|
||||
q(this).children().find("img.rowIcon").each( function() { this.src = icon_closed; });
|
||||
} else {
|
||||
contents.slideDown("fast");
|
||||
q(this).children().find("img.expanderIcon").each( function() { this.src = "${h.url_for( '/static/images/silk/resultset_bottom.png' )}"; });
|
||||
q(this).children().find("img.rowIcon").each( function() { this.src = icon_open; });
|
||||
}
|
||||
});
|
||||
// Hide all dataset bodies
|
||||
q("div.historyItemBody").hide();
|
||||
// Handle the dataset body hide/show link.
|
||||
q("div.historyItemWrapper").each( function() {
|
||||
var id = this.id;
|
||||
var li = q(this).parent();
|
||||
var body = q(this).children( "div.historyItemBody" );
|
||||
var peek = body.find( "pre.peek" )
|
||||
q(this).children( ".historyItemTitleBar" ).find( ".historyItemTitle" ).wrap( "<a href='#'></a>" ).click( function() {
|
||||
if ( body.is(":visible") ) {
|
||||
if ( q.browser.mozilla ) { peek.css( "overflow", "hidden" ) }
|
||||
body.slideUp( "fast" );
|
||||
li.removeClass( "datasetHighlighted" );
|
||||
}
|
||||
else {
|
||||
body.slideDown( "fast", function() {
|
||||
if ( q.browser.mozilla ) { peek.css( "overflow", "auto" ); }
|
||||
});
|
||||
li.addClass( "datasetHighlighted" );
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<![if gte IE 7]>
|
||||
<script type="text/javascript">
|
||||
q( document ).ready( function() {
|
||||
// Add rollover effect to any image with a 'rollover' attribute
|
||||
preload_images = {}
|
||||
q( "img[@rollover]" ).each( function() {
|
||||
var r = q(this).attr('rollover');
|
||||
var s = q(this).attr('src');
|
||||
preload_images[r] = true;
|
||||
q(this).hover(
|
||||
function() { q(this).attr( 'src', r ) },
|
||||
function() { q(this).attr( 'src', s ) }
|
||||
)
|
||||
})
|
||||
for ( r in preload_images ) { q( "<img>" ).attr( "src", r ) }
|
||||
})
|
||||
</script>
|
||||
<![endif]>
|
||||
|
||||
<%def name="render_folder( parent, parent_pad )">
|
||||
<%
|
||||
if not trans.app.security_agent.check_folder_contents( trans.user, parent ):
|
||||
return ""
|
||||
pad = parent_pad + 20
|
||||
if parent_pad == 0:
|
||||
expander = "/static/images/silk/resultset_bottom.png"
|
||||
folder = "/static/images/silk/folder_page.png"
|
||||
subfolder = False
|
||||
else:
|
||||
expander = "/static/images/silk/resultset_next.png"
|
||||
folder = "/static/images/silk/folder.png"
|
||||
subfolder = True
|
||||
%>
|
||||
<li class="folderRow libraryOrFolderRow" style="padding-left: ${pad}px;">
|
||||
<div class="rowTitle">
|
||||
<img src="${h.url_for( expander )}" class="expanderIcon"/><img src="${h.url_for( folder )}" class="rowIcon"/>
|
||||
${parent.name}
|
||||
%if parent.description:
|
||||
<i>- ${parent.description}</i>
|
||||
%endif
|
||||
</div>
|
||||
</li>
|
||||
%if subfolder:
|
||||
<ul id="subFolder">
|
||||
%else:
|
||||
<ul>
|
||||
%endif
|
||||
%for folder in parent.active_folders:
|
||||
${render_folder( folder, pad )}
|
||||
%endfor
|
||||
%for dataset in parent.active_datasets:
|
||||
%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset=dataset.dataset ):
|
||||
<li class="datasetRow" style="padding-left: ${pad + 18}px;">${render_dataset( dataset )}</li>
|
||||
%endif
|
||||
%endfor
|
||||
</ul>
|
||||
</%def>
|
||||
|
||||
<h2>Libraries</h2>
|
||||
<form name="import_from_library" action="${h.url_for( '/library/import_datasets' )}" method="post">
|
||||
<ul>
|
||||
%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>
|
||||
<th width="*">
|
||||
<img src="${h.url_for( '/static/images/silk/resultset_bottom.png' )}" class="expanderIcon"/><img src="${h.url_for( '/static/images/silk/book_open.png' )}" class="rowIcon"/>
|
||||
${library.name}
|
||||
%if library.description:
|
||||
<i>- ${library.description}</i>
|
||||
%endif
|
||||
</th>
|
||||
<th width="100">Format</th>
|
||||
<th width="50">Db</th>
|
||||
<th width="200">Info</th>
|
||||
</tr></table></div></li>
|
||||
<ul>
|
||||
${render_folder( library.root_folder, 0 )}
|
||||
</ul>
|
||||
<br/>
|
||||
%endif
|
||||
%endfor
|
||||
</ul>
|
||||
<input type="submit" class="primary-button" name="import_dataset" value="Import selected datasets"/>
|
||||
</form>
|
||||
@@ -0,0 +1,107 @@
|
||||
<%doc>
|
||||
Shamelessly stolen from history... this needs to be cleaned up to remove a
|
||||
bunch of stuff that doesn't apply to library datasets (like state, etc).
|
||||
</%doc>
|
||||
|
||||
## Render the dataset `data`
|
||||
<%def name="render_dataset( data )">
|
||||
<%
|
||||
if data.state in ['no state','',None]:
|
||||
data_state = "queued"
|
||||
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:
|
||||
<div class="historyItemWrapper historyItem historyItem-${data_state}" id="historyItem-${data.id}">
|
||||
%endif
|
||||
|
||||
## Header row for history items (name, state, action buttons)
|
||||
|
||||
<div style="overflow: hidden;" class="historyItemTitleBar">
|
||||
<div style="float: left; padding-right: 3px;">
|
||||
<div style='display: none;' id="progress-${data.id}">
|
||||
<img src="${h.url_for('/static/style/data_running.gif')}" border="0" align="middle" >
|
||||
</div>
|
||||
%if data_state == 'running':
|
||||
<div><img src="${h.url_for('/static/style/data_running.gif')}" border="0" align="middle"></div>
|
||||
%elif data_state != 'ok':
|
||||
<div><img src="${h.url_for( "/static/style/data_%s.png" % data_state )}" border="0" align="middle"></div>
|
||||
%endif
|
||||
</div>
|
||||
<%doc>
|
||||
<div style="float: right;">
|
||||
<a href="${h.url_for( controller='dataset', dataset_id=data.id, action='display', filename='index')}" target="galaxy_main"><img src="${h.url_for('/static/images/eye_icon.png')}" rollover="${h.url_for('/static/images/eye_icon_dark.png')}" width='16' height='16' alt='display data' title='display data' class='displayButton' border='0'></a>
|
||||
<a href="${h.url_for( action='edit', id=data.id )}" target="galaxy_main"><img src="${h.url_for('/static/images/pencil_icon.png')}" rollover="${h.url_for('/static/images/pencil_icon_dark.png')}" width='16' height='16' alt='edit attributes' title='edit attributes' class='editButton' border='0'></a>
|
||||
<a href="${h.url_for( action='delete', id=data.id )}" class="historyItemDelete" id="historyItemDelter-${data.id}"><img src="${h.url_for('/static/images/delete_icon.png')}" rollover="${h.url_for('/static/images/delete_icon_dark.png')}" width='16' height='16' alt='delete' class='deleteButton' border='0'></a>
|
||||
</div>
|
||||
</%doc>
|
||||
<table cellspacing="0" cellpadding="0" border="0" width="100%"><tr>
|
||||
<td width="*">
|
||||
<div style="float: right; padding-right: 2px;">
|
||||
<a href="${h.url_for( controller='root', action='edit', lid=data.id )}">
|
||||
<img src="${h.url_for('/static/images/pencil_icon.png')}"
|
||||
rollover="${h.url_for('/static/images/pencil_icon_dark.png')}"
|
||||
width='16' height='16' alt='view or edit attributes' title='view or edit attributes'
|
||||
class='editButton' style='vertical-align: middle' border='0'>
|
||||
</a>
|
||||
</div>
|
||||
<input type="checkbox" name="import_ids" value="${data.id}"/>
|
||||
<span class="historyItemTitle"><b>${data.display_name()}</b></span>
|
||||
</td>
|
||||
<td width="100">${data.ext}</td>
|
||||
<td width="50"><span class="${data.dbkey}">${data.dbkey}</span></td>
|
||||
<td width="200">${data.info}</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
|
||||
## Body for history items, extra info and actions, data "peek"
|
||||
|
||||
<div id="info${data.id}" class="historyItemBody">
|
||||
%if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ):
|
||||
<div>You do not have permission to view this dataset.</div>
|
||||
%else:
|
||||
<div>
|
||||
${data.blurb}
|
||||
</div>
|
||||
<div>
|
||||
%if data.has_data:
|
||||
<a href="${h.url_for( action='display', id=data.id, tofile='yes', toext='data.ext' )}" target="_blank">save</a>
|
||||
%for display_app in data.datatype.get_display_types():
|
||||
<% display_links = data.datatype.get_display_links( data, display_app, app, request.base ) %>
|
||||
%if len( display_links ) > 0:
|
||||
| ${data.datatype.get_display_label(display_app)}
|
||||
%for display_name, display_link in display_links:
|
||||
<a target="_blank" href="${display_link}">${display_name}</a>
|
||||
%endfor
|
||||
%endif
|
||||
%endfor
|
||||
%endif
|
||||
</div>
|
||||
%if data.peek != "no peek":
|
||||
<div><pre id="peek${data.id}" class="peek">${data.display_peek()}</pre></div>
|
||||
%endif
|
||||
%endif
|
||||
## Recurse for child datasets
|
||||
%if len( data.children ) > 0:
|
||||
## FIXME: This should not be in the template, there should
|
||||
## be a 'visible_children' method on dataset.
|
||||
<%
|
||||
children = []
|
||||
for child in data.children:
|
||||
if child.visible:
|
||||
children.append( child )
|
||||
%>
|
||||
%if len( children ) > 0:
|
||||
<div>
|
||||
There are ${len( children )} secondary datasets.
|
||||
%for idx, child in enumerate(children):
|
||||
${render_dataset( child, idx + 1 )}
|
||||
%endfor
|
||||
</div>
|
||||
%endif
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
@@ -6,7 +6,11 @@
|
||||
else:
|
||||
data_state = data.state
|
||||
%>
|
||||
<div class="historyItemWrapper historyItem historyItem-${data_state}" id="historyItem-${data.id}">
|
||||
%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
|
||||
|
||||
## Header row for history items (name, state, action buttons)
|
||||
|
||||
@@ -32,7 +36,9 @@
|
||||
## Body for history items, extra info and actions, data "peek"
|
||||
|
||||
<div id="info${data.id}" class="historyItemBody">
|
||||
%if data_state == "queued":
|
||||
%if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ):
|
||||
<div>You do not have permission to view this dataset.</div>
|
||||
%elif data_state == "queued":
|
||||
<div>Job is waiting to run</div>
|
||||
%elif data_state == "running":
|
||||
<div>Job is currently running</div>
|
||||
@@ -100,4 +106,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</%def>
|
||||
</%def>
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<%inherit file="/base_panels.mako"/>
|
||||
|
||||
<%def name="init()">
|
||||
<%
|
||||
self.has_left_panel=True
|
||||
self.has_right_panel=True
|
||||
self.active_view="analysis"
|
||||
%>
|
||||
</%def>
|
||||
|
||||
<%def name="left_panel()">
|
||||
<div class="unified-panel-header" unselectable="on">
|
||||
<div class='unified-panel-header-inner'>Tools</div>
|
||||
|
||||
@@ -9,32 +9,56 @@
|
||||
<link href="${h.url_for('/static/style/masthead.css')}" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body class="mastheadPage">
|
||||
<body class="mastheadPage" scroll="no">
|
||||
<div id="tab-bar-bottom"></div>
|
||||
<table width="100%" cellspacing="0" border="0">
|
||||
<tr valign="middle"><td width="26px"><a target="_blank" href="${wiki_url}">
|
||||
<img border="0" src="${h.url_for('/static/images/galaxyIcon_noText.png')}"></a></td>
|
||||
<td align="left" valign="middle"><div class="pageTitle">Galaxy${brand}</div></td>
|
||||
<td align="right" valign="middle">
|
||||
|
||||
Info: <a href="${bugs_email}">report bugs</a>
|
||||
| <a target="_blank" href="${wiki_url}">wiki</a>
|
||||
| <a target="_blank" href="${screencasts_url}">screencasts</a>
|
||||
| <a target="_blank" href="${blog_url}">blog</a>
|
||||
View: <span class="link-group">
|
||||
<span
|
||||
%if active_view == "analysis":
|
||||
class="active-link"
|
||||
%endif
|
||||
><a target="_parent" href="${h.url_for( controller='root', action='index' )}">analysis</a></span>
|
||||
| <span
|
||||
%if active_view == "workflow":
|
||||
class="active-link"
|
||||
%endif
|
||||
><a target="_parent" href="${h.url_for( controller='workflow', action='index' )}">workflow</a></span>
|
||||
%if admin_user == "true":
|
||||
| <span
|
||||
%if active_view == "admin":
|
||||
class="active-link"
|
||||
%endif
|
||||
><a target="_parent" href="${h.url_for( controller='admin', action='index' )}">admin</a></span>
|
||||
%endif
|
||||
|
||||
</span>
|
||||
|
||||
<span class="link-group">
|
||||
Info: <span><a href="${bugs_email}">report bugs</a></span>
|
||||
| <span><a target="_blank" href="${wiki_url}">wiki</a></span>
|
||||
| <span><a target="_blank" href="${screencasts_url}">screencasts</a></span>
|
||||
</span>
|
||||
<!-- | <a target="mainframe" href="/static/index_frame_tools.html">tools</a>
|
||||
| <a target="mainframe" href="/static/index_frame_history.html">history</a> -->
|
||||
|
||||
<span class="link-group">
|
||||
%if app.config.use_remote_user:
|
||||
Logged in as ${t.user.email}
|
||||
%else:
|
||||
%if t.user:
|
||||
Logged in as ${t.user.email}: <a target="galaxy_main" href="${h.url_for( controller='user', action='index' )}">manage</a>
|
||||
| <a target="galaxy_main" href="${h.url_for( controller='user', action='logout' )}">logout</a>
|
||||
Logged in as ${t.user.email}: <span><a target="galaxy_main" href="${h.url_for( controller='user', action='index' )}">manage</a></span>
|
||||
| <span><a target="galaxy_main" href="${h.url_for( controller='user', action='logout' )}">logout</a></span>
|
||||
%else:
|
||||
Account: <a target="galaxy_main" href="${h.url_for( controller='user', action='create' )}">create</a>
|
||||
| <a target="galaxy_main" href="${h.url_for( controller='user', action='login' )}">login</a>
|
||||
Account: <span><a target="galaxy_main" href="${h.url_for( controller='user', action='create' )}">create</a></span>
|
||||
| <span><a target="galaxy_main" href="${h.url_for( controller='user', action='login' )}">login</a></span>
|
||||
%endif
|
||||
%endif
|
||||
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -83,25 +83,22 @@
|
||||
## configure which of their stored workflows appear in the tools menu).
|
||||
|
||||
%if app.config.enable_beta_features:
|
||||
<div class="toolSectionPad"></div>
|
||||
<div class="toolSectionPad"></div>
|
||||
<div class="toolSectionTitle" id="title_XXinternalXXworkflow">
|
||||
<span>Workflow <i>(beta)</i></span>
|
||||
</div>
|
||||
<div id="XXinternalXXworkflow" class="toolSectionBody">
|
||||
<div class="toolSectionBg">
|
||||
<div class="toolTitle">
|
||||
<a href="${h.url_for( controller='workflow', action='index' )}" target="galaxy_main">Manage</a> workflows
|
||||
</div>
|
||||
%if t.user:
|
||||
%if t.user and t.user.stored_workflow_menu_entries:
|
||||
<div class="toolSectionPad"></div>
|
||||
<div class="toolSectionPad"></div>
|
||||
<div class="toolSectionTitle" id="title_XXinternalXXworkflow">
|
||||
<span>Your workflows</span>
|
||||
</div>
|
||||
<div id="XXinternalXXworkflow" class="toolSectionBody">
|
||||
<div class="toolSectionBg">
|
||||
%for m in t.user.stored_workflow_menu_entries:
|
||||
<div class="toolTitle">
|
||||
<a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(m.stored_workflow_id) )}" target="galaxy_main">${m.stored_workflow.name}</a>
|
||||
</div>
|
||||
%endfor
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
%endif
|
||||
%endif
|
||||
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<ul>
|
||||
<li><a href="${h.url_for( action='change_password' )}">Change your password</a></li>
|
||||
<li><a href="${h.url_for( action='change_email' )}">Update your email address</a></li>
|
||||
<li><a href="${h.url_for( action='set_default_permitted_actions' )}">Change default permitted actions</a> for new histories</li>
|
||||
<li><a href="${h.url_for( action='logout' )}">Logout</a></li>
|
||||
</ul>
|
||||
%else:
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%def name="title()">Change Default History Permitted Actions</%def>
|
||||
|
||||
%if trans.user:
|
||||
<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 Default Permitted Actions for new Histories </div>
|
||||
<div class="toolFormBody">
|
||||
<form name="set_permitted_actions" method="post">
|
||||
<div class="form-row">
|
||||
<% user_groups = [ assoc.group for assoc in trans.user.groups ] %>
|
||||
<% cur_groups = [ assoc.group for assoc in trans.user.default_groups ] %>
|
||||
%for group in user_groups:
|
||||
<input type="checkbox" name="group_${group.id}" class="groupCheckbox"
|
||||
%if group in cur_groups:
|
||||
<% assoc = filter( lambda x: x.group_id == group.id, trans.user.default_groups )[0] %>
|
||||
checked
|
||||
%else:
|
||||
<% assoc = None %>
|
||||
%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
|
||||
|
||||
<div style="clear: both"></div>
|
||||
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
This will change the default permitted actions assigned
|
||||
to new datasets in new histories. You may also specify
|
||||
per-history defaults via the
|
||||
<a href="${h.url_for(controller='root', action='history_options')}">history options</a>.
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="submit" name="set_permitted_actions" value="Save">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
%endif
|
||||
@@ -1,6 +1,18 @@
|
||||
<%inherit file="/base_panels.mako"/>
|
||||
|
||||
<%def name="title()">Galaxy Workflow Editor</%def>
|
||||
<%def name="init()">
|
||||
<%
|
||||
self.active_view="workflow"
|
||||
self.message_box_visible=True
|
||||
self.message_box_class="warning"
|
||||
%>
|
||||
</%def>
|
||||
|
||||
<%def name="message_box_content()">
|
||||
Workflow support is currently in <b><i>beta</i></b> testing.
|
||||
Workflows may not work with all tools, may fail unexpectedly, and may
|
||||
not be compatible with future updates to <b>Galaxy</b>.
|
||||
</%def>
|
||||
|
||||
<%def name="late_javascripts()">
|
||||
<script type='text/javascript' src="/static/scripts/galaxy.panels.js"> </script>
|
||||
@@ -229,7 +241,7 @@
|
||||
}
|
||||
|
||||
var close_editor = function() {
|
||||
<% next_url = h.url_for( controller='root', m_c='workflow' ) %>
|
||||
<% next_url = h.url_for( controller='workflow', action='index' ) %>
|
||||
if ( workflow && workflow.has_changes ) {
|
||||
do_close = function() {
|
||||
window.onbeforeunload = undefined;
|
||||
@@ -301,11 +313,12 @@
|
||||
|
||||
<%def name="stylesheets()">
|
||||
|
||||
${parent.stylesheets()}
|
||||
|
||||
## Also include "base.css" for styling tool menu and forms (details)
|
||||
## Include "base.css" for styling tool menu and forms (details)
|
||||
<link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
|
||||
|
||||
## But make sure styles for the layout take precedence
|
||||
${parent.stylesheets()}
|
||||
|
||||
<style type="text/css">
|
||||
body { margin: 0; padding: 0; overflow: hidden; }
|
||||
|
||||
@@ -486,11 +499,6 @@
|
||||
</td></tr></table>
|
||||
</div>
|
||||
|
||||
<%def name="masthead()">
|
||||
<div style="float: right; color: black; padding: 3px;"><div class="warningmessagesmall" style="display: inline-block; min-height: 15px;">Workflow support is currently in <b><i>beta</i></b></div></div>
|
||||
<div class="title"><b>Galaxy workflow editor</b></div>
|
||||
</%def>
|
||||
|
||||
<%def name="left_panel()">
|
||||
<div class="unified-panel-header" unselectable="on">
|
||||
<div class="unified-panel-header-inner">
|
||||
|
||||
@@ -1,105 +1,23 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%inherit file="/base_panels.mako"/>
|
||||
|
||||
<%def name="title()">Workflow home</%def>
|
||||
<%def name="init()">
|
||||
<%
|
||||
self.has_left_panel=False
|
||||
self.has_right_panel=False
|
||||
self.active_view="workflow"
|
||||
self.message_box_visible=True
|
||||
self.message_box_class="warning"
|
||||
%>
|
||||
</%def>
|
||||
|
||||
<div class="warningmessage">
|
||||
<%def name="message_box_content()">
|
||||
Workflow support is currently in <b><i>beta</i></b> testing.
|
||||
Workflows may not work with all tools, may fail unexpectedly, and may
|
||||
not be compatible with future updates to <b>Galaxy</b>.
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
%if message:
|
||||
<%
|
||||
try:
|
||||
messagetype
|
||||
except:
|
||||
messagetype = "done"
|
||||
%>
|
||||
<p />
|
||||
<div class="${messagetype}message">
|
||||
${message}
|
||||
</div>
|
||||
%endif
|
||||
<%def name="center_panel()">
|
||||
|
||||
<h2>Your workflows</h2>
|
||||
<iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${h.url_for( controller="workflow", action="list" )}"> </iframe>
|
||||
|
||||
<div style="float: right; margin-top: -2.5em;">
|
||||
<a class="action-button" href="${h.url_for( action='create' )}">
|
||||
<img src="${h.url_for('/static/images/silk/add.png')}" />
|
||||
<span>Add a new workflow</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
%if workflows:
|
||||
<table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr class="header">
|
||||
<th>Name</th>
|
||||
<th># of Steps</th>
|
||||
## <th>Last Updated</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
%for i, workflow in enumerate( workflows ):
|
||||
<tr>
|
||||
<td>
|
||||
<a href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name}</a>
|
||||
<a id="wf-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
|
||||
</td>
|
||||
<td>${len(workflow.latest_workflow.steps)}</td>
|
||||
## <td>${str(workflow.update_time)[:19]}</td>
|
||||
<td>
|
||||
<div popupmenu="wf-${i}-popup">
|
||||
<a class="action-button" href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">Run</a>
|
||||
<a class="action-button" href="${h.url_for( action='editor', id=trans.security.encode_id(workflow.id) )}" target="_parent">Edit</a>
|
||||
<a class="action-button" href="${h.url_for( action='rename', id=trans.security.encode_id(workflow.id) )}">Rename</a>
|
||||
<a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(workflow.id) )}">Share</a>
|
||||
<a class="action-button" confirm="Are you sure you want to delete workflow '${workflow.name}'?" href="${h.url_for( action='delete', id=trans.security.encode_id(workflow.id) )}">Delete</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</table>
|
||||
%else:
|
||||
|
||||
You have no workflows.
|
||||
|
||||
%endif
|
||||
|
||||
<h2>Workflows shared with you by others</h2>
|
||||
|
||||
%if shared_by_others:
|
||||
<table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr class="header">
|
||||
<th>Name</th>
|
||||
<th>Owner</th>
|
||||
<th># of Steps</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
%for i, association in enumerate( shared_by_others ):
|
||||
<% workflow = association.stored_workflow %>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name}</a>
|
||||
<a id="shared-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
|
||||
</td>
|
||||
<td>${workflow.user.email}</td>
|
||||
<td>${len(workflow.latest_workflow.steps)}</td>
|
||||
<td>
|
||||
<div popupmenu="shared-${i}-popup">
|
||||
<a class="action-button" href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">Run</a>
|
||||
<a class="action-button" href="${h.url_for( action='clone', id=trans.security.encode_id(workflow.id) )}">Clone</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</table>
|
||||
%else:
|
||||
|
||||
No workflows have been shared with you.
|
||||
|
||||
%endif
|
||||
|
||||
<h2>Other options</h2>
|
||||
|
||||
<a class="action-button" href="${h.url_for( action='configure_menu' )}">
|
||||
<span>Configure your workflow menu</span>
|
||||
</a>
|
||||
</%def>
|
||||
@@ -0,0 +1,101 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
|
||||
<%def name="title()">Workflow home</%def>
|
||||
|
||||
%if message:
|
||||
<%
|
||||
try:
|
||||
messagetype
|
||||
except:
|
||||
messagetype = "done"
|
||||
%>
|
||||
<p />
|
||||
<div class="${messagetype}message">
|
||||
${message}
|
||||
</div>
|
||||
%endif
|
||||
|
||||
<h2>Your workflows</h2>
|
||||
|
||||
<ul class="manage-table-actions">
|
||||
<li>
|
||||
<a class="action-button" href="${h.url_for( action='create' )}">
|
||||
<img src="${h.url_for('/static/images/silk/add.png')}" />
|
||||
<span>Add a new workflow</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
%if workflows:
|
||||
<table class="mange-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr class="header">
|
||||
<th>Name</th>
|
||||
<th># of Steps</th>
|
||||
## <th>Last Updated</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
%for i, workflow in enumerate( workflows ):
|
||||
<tr>
|
||||
<td>
|
||||
<a href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name}</a>
|
||||
<a id="wf-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
|
||||
</td>
|
||||
<td>${len(workflow.latest_workflow.steps)}</td>
|
||||
## <td>${str(workflow.update_time)[:19]}</td>
|
||||
<td>
|
||||
<div popupmenu="wf-${i}-popup">
|
||||
<a class="action-button" href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">Run</a>
|
||||
<a class="action-button" href="${h.url_for( action='editor', id=trans.security.encode_id(workflow.id) )}" target="_parent">Edit</a>
|
||||
<a class="action-button" href="${h.url_for( action='rename', id=trans.security.encode_id(workflow.id) )}">Rename</a>
|
||||
<a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(workflow.id) )}">Share</a>
|
||||
<a class="action-button" confirm="Are you sure you want to delete workflow '${workflow.name}'?" href="${h.url_for( action='delete', id=trans.security.encode_id(workflow.id) )}">Delete</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</table>
|
||||
%else:
|
||||
|
||||
You have no workflows.
|
||||
|
||||
%endif
|
||||
|
||||
<h2>Workflows shared with you by others</h2>
|
||||
|
||||
%if shared_by_others:
|
||||
<table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr class="header">
|
||||
<th>Name</th>
|
||||
<th>Owner</th>
|
||||
<th># of Steps</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
%for i, association in enumerate( shared_by_others ):
|
||||
<% workflow = association.stored_workflow %>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name}</a>
|
||||
<a id="shared-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
|
||||
</td>
|
||||
<td>${workflow.user.email}</td>
|
||||
<td>${len(workflow.latest_workflow.steps)}</td>
|
||||
<td>
|
||||
<div popupmenu="shared-${i}-popup">
|
||||
<a class="action-button" href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">Run</a>
|
||||
<a class="action-button" href="${h.url_for( action='clone', id=trans.security.encode_id(workflow.id) )}">Clone</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</table>
|
||||
%else:
|
||||
|
||||
No workflows have been shared with you.
|
||||
|
||||
%endif
|
||||
|
||||
<h2>Other options</h2>
|
||||
|
||||
<a class="action-button" href="${h.url_for( action='configure_menu' )}">
|
||||
<span>Configure your workflow menu</span>
|
||||
</a>
|
||||
@@ -9,6 +9,9 @@ import twill.commands as tc
|
||||
from twill.other_packages._mechanize_dist import ClientForm
|
||||
from elementtree import ElementTree
|
||||
|
||||
from galaxy.web.controllers.admin import entities, unentities
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
|
||||
buffer = StringIO.StringIO()
|
||||
|
||||
#Force twill to log to a buffer -- FIXME: Should this go to stdout and be captured by nose?
|
||||
@@ -30,7 +33,7 @@ class TwillTestCase( unittest.TestCase ):
|
||||
self.home()
|
||||
self.set_history()
|
||||
|
||||
"""Functions associated with files"""
|
||||
# Functions associated with files
|
||||
def files_diff( self, file1, file2 ):
|
||||
"""Checks the contents of 2 files for differences"""
|
||||
if not filecmp.cmp( file1, file2 ):
|
||||
@@ -82,7 +85,7 @@ class TwillTestCase( unittest.TestCase ):
|
||||
errmsg += str( err )
|
||||
raise AssertionError( errmsg )
|
||||
|
||||
"""Functions associated with histories"""
|
||||
# Functions associated with histories
|
||||
def check_history_for_errors( self ):
|
||||
"""Raises an exception if there are errors in a history"""
|
||||
self.visit_page( "history" )
|
||||
@@ -209,7 +212,7 @@ class TwillTestCase( unittest.TestCase ):
|
||||
def view_stored_histories( self ):
|
||||
self.visit_page( "history_available" )
|
||||
|
||||
"""Functions associated with datasets (history items) and meta data"""
|
||||
# Functions associated with datasets (history items) and meta data
|
||||
def get_job_stderr( self, id ):
|
||||
self.visit_page( "dataset/stderr?id=%s" % id )
|
||||
return self.last_page()
|
||||
@@ -360,7 +363,7 @@ class TwillTestCase( unittest.TestCase ):
|
||||
genome_build = elem.get('dbkey')
|
||||
self.assertTrue( genome_build == dbkey )
|
||||
|
||||
"""Functions associated with user accounts"""
|
||||
# Functions associated with user accounts
|
||||
def create( self, email='test@bx.psu.edu', password='testuser', confirm='testuser' ):
|
||||
self.visit_page( "user/create?email=%s&password=%s&confirm=%s" %(email, password, confirm) )
|
||||
try:
|
||||
@@ -380,7 +383,7 @@ class TwillTestCase( unittest.TestCase ):
|
||||
self.check_page_for_string( "You are no longer logged in" )
|
||||
self.home() #Reset our URL for future tests
|
||||
|
||||
"""Functions associated with browsers, cookies, HTML forms and page visits"""
|
||||
# Functions associated with browsers, cookies, HTML forms and page visits
|
||||
def check_page_for_string( self, patt ):
|
||||
"""Looks for 'patt' in the current browser page"""
|
||||
page = self.last_page()
|
||||
@@ -502,7 +505,7 @@ class TwillTestCase( unittest.TestCase ):
|
||||
tc.go("%s" % url)
|
||||
tc.code( 200 )
|
||||
|
||||
"""Functions associated with Galaxy tools"""
|
||||
# Functions associated with Galaxy tools
|
||||
def run_tool( self, tool_id, **kwd ):
|
||||
tool_id = tool_id.replace(" ", "+")
|
||||
"""Runs the tool 'tool_id' and passes it the key/values from the *kwd"""
|
||||
@@ -525,3 +528,73 @@ class TwillTestCase( unittest.TestCase ):
|
||||
else:
|
||||
break
|
||||
self.assertNotEqual(count, maxiter)
|
||||
|
||||
# Dataset Security stuff
|
||||
def create_group( self, name='New Test Group', priority='10' ):
|
||||
"""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.submit( "create_group_button" )
|
||||
except AssertionError, err:
|
||||
errmsg = 'Exception caught attempting to create group: %s' % str( err )
|
||||
raise AssertionError( errmsg )
|
||||
self.home()
|
||||
return form
|
||||
def add_group_member( self, group_id='', group_name='' ):
|
||||
"""Add a member to an existing group"""
|
||||
# twill version 0.9 does not allow for this test
|
||||
self.visit_url( "%s/admin/group_members_edit?group_id=%s&group_name=%s" % ( self.url, group_id, group_name ) )
|
||||
self.check_page_for_string( 'Members of' )
|
||||
try:
|
||||
tc.fv( "1", "", "2" ) # 1-based form field 2 is the 2nd check box named 'members', user id 2 is test2@bx.psu.edu
|
||||
tc.submit( "group_members_edit_button" )
|
||||
except AssertionError, err:
|
||||
errmsg = 'Exception caught attempting to create group: %s' % str( err )
|
||||
raise AssertionError( errmsg )
|
||||
self.home()
|
||||
def mark_group_deleted( self, group_id='' ):
|
||||
"""Delete an existing group"""
|
||||
self.visit_url( "%s/admin/mark_group_deleted?group_id=%s" % ( self.url, group_id ) )
|
||||
self.last_page()
|
||||
self.check_page_for_string( 'The group has been marked as deleted' )
|
||||
self.home()
|
||||
def undelete_group( self, group_id='' ):
|
||||
"""Undelete an existing group"""
|
||||
self.visit_url( "%s/admin/undelete_group?group_id=%s" % ( self.url, group_id ) )
|
||||
self.last_page()
|
||||
self.check_page_for_string( 'The group has been marked as not deleted' )
|
||||
self.home()
|
||||
def purge_group( self, group=None ):
|
||||
"""Purge an existing group"""
|
||||
if not group.deleted:
|
||||
self.mark_group_deleted( group_id=group.id )
|
||||
group_id = str( group.id )
|
||||
group_name = group.name.replace( ' ', '+' )
|
||||
self.visit_url( "%s/admin/deleted_groups" % self.url )
|
||||
self.check_page_for_string( '%s' % group.name )
|
||||
self.visit_url( "%s/admin/purge_group?group_id=%s" % ( self.url, group_id ) )
|
||||
self.last_page()
|
||||
self.check_page_for_string( 'The group has been purged from the database' )
|
||||
self.home()
|
||||
|
||||
# Library stuff
|
||||
def create_library( self, name='', description='' ):
|
||||
"""Create a new library"""
|
||||
name = name.replace( ' ', '+' )
|
||||
description = description.replace( ' ', '+' )
|
||||
try:
|
||||
self.visit_url( "%s/admin/library?name=%s&description=%s&create_library=None" % ( self.url, name, description ) )
|
||||
except AssertionError, err:
|
||||
errmsg = 'Exception caught attempting to create library: %s' % str( err )
|
||||
raise AssertionError( errmsg )
|
||||
self.home()
|
||||
|
||||
@@ -73,6 +73,7 @@ def setup():
|
||||
test_conf = "test.conf",
|
||||
log_destination = "stdout",
|
||||
use_heartbeat=False,
|
||||
admin_users = 'test@bx.psu.edu',
|
||||
global_conf= { "__file__": "universe_wsgi.ini.sample" } )
|
||||
|
||||
log.info( "Embedded Universe application started" )
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import galaxy.model
|
||||
from base.twilltestcase import TwillTestCase
|
||||
|
||||
s = 'You must have Galaxy administrator privileges to use this feature.'
|
||||
|
||||
class TestHistory( TwillTestCase ):
|
||||
def test_00_admin_features_when_not_logged_in( self ):
|
||||
"""Testing admin_features when not logged in"""
|
||||
self.logout()
|
||||
self.visit_url( "%s/admin" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/reload_tool?tool_id=upload1" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/dataset_security" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/groups" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/create_group" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/group_members_edit" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/update_group_members" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/group_dataset_permitted_actions_edit" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/mark_group_deleted" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/purge_group" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/users" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/libraries" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/library" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/folder" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
self.visit_url( "%s/admin/dataset" % self.url )
|
||||
self.check_page_for_string( s )
|
||||
def test_05_login_as_admin( self ):
|
||||
"""Testing logging in as an admin user"""
|
||||
self.login( email='test@bx.psu.edu' ) #This is configured as our admin user
|
||||
self.visit_page( "admin" )
|
||||
self.check_page_for_string( 'Administration' )
|
||||
self.logout()
|
||||
# Need to ensure that we have 2 users
|
||||
self.login( email='test2@bx.psu.edu' ) # This will not be an admin user
|
||||
self.visit_page( "admin" )
|
||||
self.check_page_for_string( s )
|
||||
def test_10_create_group( self ):
|
||||
"""Testing creating new group with 1 members"""
|
||||
self.login( email='test@bx.psu.edu' )
|
||||
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.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
|
||||
#def test_15_add_group_member( self ):
|
||||
# """Testing adding a member to an existing group"""
|
||||
# group = galaxy.model.Group.get_by( name='New Test Group' )
|
||||
# group_id = str( group.id )
|
||||
# group_name = group.name.replace( ' ', '+' )
|
||||
# self.add_group_member( group_id=group_id, group_name=group_name )
|
||||
# self.visit_page( 'admin/group_members?group_id=%s&group_name=%s' % ( group_id, group_name ) )
|
||||
# self.check_page_for_string( 'test@bx.psu.edu' )
|
||||
# self.check_page_for_string( 'test2@bx.psu.edu' )
|
||||
def test_20_delete_group( self ):
|
||||
"""Testing deleting a group"""
|
||||
self.visit_page( "admin/groups" )
|
||||
self.check_page_for_string( "group_name=New+Test+Group" )
|
||||
group = galaxy.model.Group.get_by( name='New Test Group' )
|
||||
group_id = str( group.id )
|
||||
self.mark_group_deleted( group_id=group_id )
|
||||
def test_25_undelete_group( self ):
|
||||
"""Testing undeleting a deleted group"""
|
||||
group = galaxy.model.Group.get_by( name='New Test Group' )
|
||||
group_id = str( group.id )
|
||||
self.undelete_group( group_id=group_id )
|
||||
def test_30_purge_group( self ):
|
||||
"""Testing purging a group"""
|
||||
group = galaxy.model.Group.get_by( name='New Test Group' )
|
||||
self.purge_group( group=group )
|
||||
|
||||
def test_20_create_library( self ):
|
||||
"""Testing creating new library"""
|
||||
self.create_library( name='New Test Library', description='New test Library Description' )
|
||||
self.visit_page( 'admin/libraries' )
|
||||
self.check_page_for_string( "New Test Library" )
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<toolbox>
|
||||
<section name="Get Data" id="getext">
|
||||
<tool file="data_source/upload.xml"/>
|
||||
<tool file="data_source/access_libraries.xml" />
|
||||
<tool file="data_source/ucsc_tablebrowser.xml" />
|
||||
<tool file="data_source/ucsc_tablebrowser_test.xml" />
|
||||
<tool file="data_source/ucsc_tablebrowser_archaea.xml" />
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<tool name="Access Libraries" id="library_access1">
|
||||
<description>stored locally</description>
|
||||
<inputs action="library/browse" method="get">
|
||||
<param name="bogus_param" type="hidden" value="needed" />
|
||||
</inputs>
|
||||
</tool>
|
||||
@@ -5,7 +5,8 @@ from shutil import copyfile
|
||||
|
||||
#post processing, set build for data and add additional data to history
|
||||
def exec_after_process(app, inp_data, out_data, param_dict, tool, stdout, stderr):
|
||||
history = out_data.items()[0][1].history
|
||||
base_dataset = out_data.items()[0][1]
|
||||
history = base_dataset.history
|
||||
if history == None:
|
||||
print "unknown history!"
|
||||
return
|
||||
@@ -37,6 +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.model.flush()
|
||||
try:
|
||||
copyfile(filepath,newdata.file_name)
|
||||
|
||||
@@ -84,7 +84,8 @@ from galaxy import datatypes, config, jobs
|
||||
from shutil import copyfile
|
||||
|
||||
def exec_after_process(app, inp_data, out_data, param_dict, tool, stdout, stderr):
|
||||
history = out_data.items()[0][1].history
|
||||
base_dataset = out_data.items()[0][1]
|
||||
history = base_dataset.history
|
||||
if history == None:
|
||||
print "unknown history!"
|
||||
return
|
||||
@@ -128,6 +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 )
|
||||
history.add_dataset( newdata )
|
||||
app.model.flush()
|
||||
try:
|
||||
|
||||
@@ -27,12 +27,12 @@ def exec_after_process(app, inp_data, out_data, param_dict, tool, stdout, stderr
|
||||
fields = line.split("\t")
|
||||
dbkey = fields[1]
|
||||
filepath = fields[2]
|
||||
|
||||
newdata = app.model.HistoryDatasetAssociation( create_dataset = True )
|
||||
newdata.extension = "bed"
|
||||
newdata.name = basic_name + " (" + dbkey + ")"
|
||||
newdata.flush()
|
||||
history.add_dataset( newdata )
|
||||
app.security_agent.set_dataset_permissions( newdata.dataset, output_data.dataset.groups )
|
||||
newdata.flush()
|
||||
history.flush()
|
||||
app.model.flush()
|
||||
|
||||
@@ -77,8 +77,12 @@ use_lint = false
|
||||
# NEVER enable this on a public site (even test or QA)
|
||||
use_interactive = true
|
||||
|
||||
# Admin Password
|
||||
admin_pass = galaxy
|
||||
# Admin Users - this should be a comma-separated list of valid Galaxy users
|
||||
#admin_users = user1@bx.psu.edu,user2@bx.psu.edu
|
||||
|
||||
# Files in directories under this directory can be directly imported through
|
||||
# the library admin's "add dataset" tool
|
||||
## library_import_dir = /var/opt/galaxy/import
|
||||
|
||||
# path to sendmail
|
||||
sendmail_path = /usr/sbin/sendmail
|
||||
|
||||
Reference in New Issue
Block a user