diff --git a/community_datatypes_conf.xml.sample b/community_datatypes_conf.xml.sample
index 88b446dc5b8..5373e562f0b 100644
--- a/community_datatypes_conf.xml.sample
+++ b/community_datatypes_conf.xml.sample
@@ -2,8 +2,6 @@
+
-
-
-
diff --git a/lib/galaxy/webapps/community/controllers/admin.py b/lib/galaxy/webapps/community/controllers/admin.py
index a1bc411257e..218c03f5c72 100644
--- a/lib/galaxy/webapps/community/controllers/admin.py
+++ b/lib/galaxy/webapps/community/controllers/admin.py
@@ -299,7 +299,7 @@ class GroupListGrid( grids.Grid ):
class AdminToolListGrid( ToolListGrid ):
class StateColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- state = tool.state()
+ state = tool.state
if state == 'approved':
state_color = 'ok'
elif state == 'rejected':
@@ -441,7 +441,7 @@ class AdminController( BaseController, Admin ):
# Called from the ToolStateColumn link
tool_id = kwd.get( 'id', None )
tool = get_tool( trans, tool_id )
- kwd[ 'f-state' ] = tool.state()
+ kwd[ 'f-state' ] = tool.state
elif operation == "tools_by_category":
# Eliminate the current filters if any exist.
for k, v in kwd.items():
@@ -547,7 +547,7 @@ class AdminController( BaseController, Admin ):
# If we're approving a tool, all previously approved versions must be set to archived
for version in get_versions( tool ):
# TODO: get latest approved version instead of all versions
- if version != tool and version.is_approved():
+ if version != tool and version.is_approved:
# Create an event with state ARCHIVED for the previously approved version of this tool
self.__create_tool_event( trans,
version,
@@ -799,30 +799,30 @@ def get_tools_by_state( trans, state ):
ids = []
if state == trans.model.Tool.states.NEW:
for tool in get_tools( trans ):
- if tool.is_new():
+ if tool.is_new:
ids.append( tool.id )
elif state == trans.model.Tool.states.ERROR:
for tool in get_tools( trans ):
- if tool.is_error():
+ if tool.is_error:
ids.append( tool.id )
elif state == trans.model.Tool.states.DELETED:
for tool in get_tools( trans ):
- if tool.is_deleted():
+ if tool.is_deleted:
ids.append( tool.id )
elif state == trans.model.Tool.states.WAITING:
for tool in get_tools( trans ):
- if tool.is_waiting():
+ if tool.is_waiting:
ids.append( tool.id )
elif state == trans.model.Tool.states.APPROVED:
for tool in get_tools( trans ):
- if tool.is_approved():
+ if tool.is_approved:
ids.append( tool.id )
elif state == trans.model.Tool.states.REJECTED:
for tool in get_tools( trans ):
- if tool.is_rejected():
+ if tool.is_rejected:
ids.append( tool.id )
elif state == trans.model.Tool.states.ARCHIVED:
for tool in get_tools( trans ):
- if tool.is_archived():
+ if tool.is_archived:
ids.append( tool.id )
return ids
diff --git a/lib/galaxy/webapps/community/controllers/common.py b/lib/galaxy/webapps/community/controllers/common.py
index 5d6123d1348..b5c2df830a2 100644
--- a/lib/galaxy/webapps/community/controllers/common.py
+++ b/lib/galaxy/webapps/community/controllers/common.py
@@ -14,6 +14,11 @@ class ToolListGrid( grids.Grid ):
class NameColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
return tool.name
+ class TypeColumn( grids.GridColumn ):
+ def get_value( self, trans, grid, tool ):
+ if tool.is_suite:
+ return 'Suite'
+ return 'Tool'
class VersionColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
return tool.version
@@ -60,6 +65,10 @@ class ToolListGrid( grids.Grid ):
model_class=model.Tool,
attach_popup=False
),
+ TypeColumn( "Type",
+ key="suite",
+ model_class=model.Tool,
+ attach_popup=False ),
VersionColumn( "Version",
key="version",
model_class=model.Tool,
@@ -229,7 +238,7 @@ class CommonController( BaseController ):
in_categories.append( ( category.id, category.name ) )
else:
out_categories.append( ( category.id, category.name ) )
- if tool.is_rejected():
+ if tool.is_rejected:
# Include the comments regarding the reason for rejection
reason_for_rejection = get_most_recent_event( tool ).comment
else:
@@ -283,7 +292,7 @@ class CommonController( BaseController ):
visible_versions = trans.app.security_agent.get_visible_versions( trans.user, trans.user_is_admin(), cntrller, tool )
categories = [ tca.category for tca in tool.categories ]
tool_file_contents = tarfile.open( tool.file_name, 'r' ).getnames()
- if tool.is_rejected():
+ if tool.is_rejected:
# Include the comments regarding the reason for rejection
reason_for_rejection = get_most_recent_event( tool ).comment
else:
diff --git a/lib/galaxy/webapps/community/controllers/tool.py b/lib/galaxy/webapps/community/controllers/tool.py
index 2fb590981c4..4a2e5aa1453 100644
--- a/lib/galaxy/webapps/community/controllers/tool.py
+++ b/lib/galaxy/webapps/community/controllers/tool.py
@@ -15,7 +15,7 @@ class ApprovedToolListGrid( ToolListGrid ):
class MyToolsListGrid( ToolListGrid ):
class StateColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- state = tool.state()
+ state = tool.state
if state == 'approved':
state_color = 'ok'
elif state == 'rejected':
@@ -64,7 +64,7 @@ class ToolCategoryListGrid( CategoryListGrid ):
viewable_tools = 0
for tca in category.tools:
tool = tca.tool
- if tool.is_approved():
+ if tool.is_approved:
viewable_tools += 1
return viewable_tools
return 0
diff --git a/lib/galaxy/webapps/community/controllers/upload.py b/lib/galaxy/webapps/community/controllers/upload.py
index 9dba8f449a3..c40edbc3f14 100644
--- a/lib/galaxy/webapps/community/controllers/upload.py
+++ b/lib/galaxy/webapps/community/controllers/upload.py
@@ -2,6 +2,7 @@ import sys, os, shutil, logging, urllib2
from galaxy.web.base.controller import *
from galaxy.web.framework.helpers import time_ago, iff, grids
from galaxy.model.orm import *
+from galaxy.web.form_builder import SelectField
from galaxy.webapps.community import datatypes
from common import get_categories, get_category, get_versions
@@ -25,12 +26,13 @@ class UploadController( BaseController ):
replace_id = params.get( 'replace_id', None )
replace_version = None
uploaded_file = None
+ upload_type = params.get( 'upload_type', 'tool' )
categories = get_categories( trans )
if not categories:
return trans.response.send_redirect( web.url_for( controller='tool',
action='browse_tools',
cntrller='tool',
- message='No categories have been configured in this instance of the Galaxy Community. An administrator needs to create some via the Administrator control panel before anything can be uploaded',
+ message='No categories have been configured in this instance of the Galaxy Tool Shed. An administrator needs to create some via the Administrator control panel before anything can be uploaded',
status='error' ) )
if params.get( 'upload_button', False ):
url_paste = params.get( 'url', '' ).strip()
@@ -50,8 +52,6 @@ class UploadController( BaseController ):
elif file_data not in ( '', None ):
uploaded_file = file_data.file
if uploaded_file:
- # TODO: tool should no longer be the default when we upload histories and workflows
- upload_type = params.get( 'upload_type', 'tool' )
datatype = trans.app.datatypes_registry.get_datatype_by_extension( upload_type )
if datatype is None:
message = 'An unknown file type was selected. This should not be possible, please report the error.'
@@ -62,6 +62,7 @@ class UploadController( BaseController ):
meta = datatype.verify( uploaded_file )
meta.user = trans.user
meta.guid = trans.app.security.get_new_guid()
+ meta.suite = upload_type == 'toolsuite'
obj = datatype.create_model_object( meta )
trans.sa_session.add( obj )
if isinstance( obj, trans.app.model.Tool ):
@@ -71,25 +72,32 @@ class UploadController( BaseController ):
if replace_id:
replace_version = trans.sa_session.query( trans.app.model.Tool ).get( trans.security.decode_id( replace_id ) )
if existing and not replace_id:
- raise UploadError( 'A tool with the same ID already exists. If you are trying to update this tool to a new version, please use the upload form on the "Edit Tool" page. Otherwise, please choose a new ID.' )
+ raise UploadError( 'A %s with the same Id already exists. If you are trying to update this %s to a new version, use the upload form on the "Edit Tool" page. Otherwise, change the Id in the %s config.' % \
+ ( obj.label, obj.label, obj.label ) )
elif replace_id and not existing:
- raise UploadError( 'Tool ids must match when uploading a new version of a tool. The new tool id does not match the old tool id (%s). Check the tool XML files.' % str( replace_version.tool_id ) )
+ raise UploadError( 'The new %s id (%s) does not match the old %s id (%s). Check the %s config files.' % \
+ ( obj.label, str( meta.id ), obj.label, str( replace_version.tool_id ), obj.label ) )
elif existing and replace_id:
if replace_version.newer_version:
# If the user has picked an old version, switch to the newest version
replace_version = get_versions( replace_version )[0]
if replace_version.tool_id != meta.id:
- raise UploadError( 'Tool ids must match when uploading a new version of a tool. The new tool id (%s) does not match the old tool id (%s). Check the tool XML files.' % ( str( meta.id ), str( replace_version.tool_id ) ) )
+ raise UploadError( 'The new %s id (%s) does not match the old %s id (%s). Check the %s config files.' % \
+ ( obj.label, str( meta.id ), obj.label, str( replace_version.tool_id ), obj.label ) )
for old_version in get_versions( replace_version ):
if old_version.version == meta.version:
- raise UploadError( 'The new version (%s) matches an old version. Check your version in the tool XML file.' % str( meta.version ) )
- if old_version.is_new():
- raise UploadError( 'There is an existing version of this tool which has not yet been submitted for approval, so either submit or delete it before uploading a new version.' % url_for( controller='common',
- action='view_tool',
- cntrller='tool',
- id=trans.security.encode_id( old_version.id ) ) )
- if old_version.is_waiting():
- raise UploadError( 'There is an existing version of this tool which is waiting for administrative approval, so contact an administrator for help.' )
+ raise UploadError( 'The new version (%s) matches an old version. Check your version in the %s config file.' % \
+ ( str( meta.version ), obj.label ) )
+ if old_version.is_new:
+ raise UploadError( 'There is an existing version of this %s which has not yet been submitted for approval, so either submit it or delete it before uploading a new version.' % \
+ ( obj.label,
+ url_for( controller='common',
+ action='view_tool',
+ cntrller='tool',
+ id=trans.security.encode_id( old_version.id ) ) ) )
+ if old_version.is_waiting:
+ raise UploadError( 'There is an existing version of this %s which is waiting for administrative approval, so contact an administrator for help.' % \
+ obj.label )
# Defer setting the id since the newer version id doesn't exist until the new Tool object is flushed
if category_ids:
for category_id in category_ids:
@@ -128,10 +136,10 @@ class UploadController( BaseController ):
replace_version = trans.sa_session.query( trans.app.model.Tool ).get( int( trans.app.security.decode_id( replace_id ) ) )
old_version = None
for old_version in get_versions( replace_version ):
- if old_version.is_new():
+ if old_version.is_new:
message = 'There is an existing version of this tool which has not been submitted for approval, so either submit or delete it before uploading a new version.'
break
- if old_version.is_waiting():
+ if old_version.is_waiting:
message = 'There is an existing version of this tool which is waiting for administrative approval, so contact an administrator for help.'
break
else:
@@ -143,13 +151,23 @@ class UploadController( BaseController ):
id=trans.app.security.encode_id( old_version.id ),
message=message,
status='error' ) )
- selected_upload_type = params.get( 'type', 'tool' )
selected_categories = [ trans.security.decode_id( id ) for id in category_ids ]
+ datatype_labels=trans.app.datatypes_registry.get_datatype_labels()
+ type_ids = [ tup[0] for tup in datatype_labels ]
+ upload_type_select_list = SelectField( 'upload_type',
+ refresh_on_change=True,
+ refresh_on_change_values=type_ids )
+ for type_id, type_label in datatype_labels:
+ if type_id == upload_type:
+ upload_type_select_list.add_option( type_label, type_id, selected = True )
+ else:
+ upload_type_select_list.add_option( type_label, type_id, selected = False )
return trans.fill_template( '/webapps/community/upload/upload.mako',
message=message,
status=status,
- selected_upload_type=selected_upload_type,
- upload_types=trans.app.datatypes_registry.get_datatypes_for_select_list(),
+ selected_upload_type=upload_type,
+ upload_type_select_list=upload_type_select_list,
+ datatype_labels=trans.app.datatypes_registry.get_datatype_labels(),
replace_id=replace_id,
selected_categories=selected_categories,
categories=get_categories( trans ) )
diff --git a/lib/galaxy/webapps/community/datatypes/__init__.py b/lib/galaxy/webapps/community/datatypes/__init__.py
index 5feca57a52e..c3bce1ceaa1 100644
--- a/lib/galaxy/webapps/community/datatypes/__init__.py
+++ b/lib/galaxy/webapps/community/datatypes/__init__.py
@@ -17,7 +17,6 @@ class DatatypeVerificationError( Exception ):
class Registry( object ):
def __init__( self, root_dir=None, config=None ):
self.datatypes_by_extension = {}
- self.sniff_order = []
if root_dir and config:
# Parse datatypes_conf.xml
tree = galaxy.util.parse_xml( config )
@@ -50,98 +49,143 @@ class Registry( object ):
log.debug( 'Added model class: %s to datatype: %s' % ( model_class, dtype ) )
except Exception, e:
log.warning( 'Error loading datatype "%s", problem: %s' % ( extension, str( e ) ) )
- # Load datatype sniffers from the config
- sniff_order = []
- sniffers = root.find( 'sniffers' )
- for elem in sniffers.findall( 'sniffer' ):
- dtype = elem.get( 'type', None )
- if dtype:
- sniff_order.append( dtype )
- for dtype in sniff_order:
- try:
- fields = dtype.split( ":" )
- datatype_module = fields[0]
- datatype_class = fields[1]
- fields = datatype_module.split( "." )
- module = __import__( fields.pop(0) )
- for mod in fields:
- module = getattr( module, mod )
- aclass = getattr( module, datatype_class )()
- included = False
- for atype in self.sniff_order:
- if not issubclass( atype.__class__, aclass.__class__ ) and isinstance( atype, aclass.__class__ ):
- included = True
- break
- if not included:
- self.sniff_order.append( aclass )
- log.debug( 'Loaded sniffer for datatype: %s' % dtype )
- except Exception, exc:
- log.warning( 'Error appending datatype %s to sniff_order, problem: %s' % ( dtype, str( exc ) ) )
def get_datatype_by_extension( self, ext ):
return self.datatypes_by_extension.get( ext, None )
- def get_datatypes_for_select_list( self ):
+ def get_datatype_labels( self ):
rval = []
for ext, datatype in self.datatypes_by_extension.items():
- rval.append( ( ext, datatype.select_name ) )
+ rval.append( ( ext, datatype.label ) )
return rval
- def sniff( self, fname ):
- for datatype in sniff_order:
- try:
- datatype.sniff( fname )
- return datatype.file_ext
- except:
- pass
class Tool( object ):
- select_name = 'Tool'
def __init__( self, model_object=None ):
self.model_object = model_object
- def verify( self, file ):
- msg = ''
+ self.label = 'Tool'
+ def verify( self, f, xml_files=[], tool_tags={} ):
+ # xml_files and tool_tags will only be received if we're called from the ToolSuite.verify() method.
try:
- tar = tarfile.open( file.name )
+ tar = tarfile.open( f.name )
except tarfile.ReadError:
- raise DatatypeVerificationError( 'The tool file is not a readable tar file' )
- xml_names = filter( lambda x: x.lower().endswith( '.xml' ), tar.getnames() )
- if not xml_names:
- raise DatatypeVerificationError( 'The tool file does not contain an XML file' )
- for xml_name in xml_names:
+ raise DatatypeVerificationError( 'The archive is not a readable tar file.' )
+ if not xml_files:
+ # Make sure we're not uploading a tool suite
+ if filter( lambda x: x.lower() == 'tool_suite.xml', tar.getnames() ):
+ raise DatatypeVerificationError( 'The archive includes a tool_suite.xml file, so set the upload type to "Tool Suite".' )
+ xml_files = filter( lambda x: x.lower().endswith( '.xml' ), tar.getnames() )
+ if not xml_files:
+ raise DatatypeVerificationError( 'The archive does not contain any xml config files.' )
+ for xml_file in xml_files:
try:
- tree = ElementTree.parse( tar.extractfile( xml_name ) )
+ tree = ElementTree.parse( tar.extractfile( xml_file ) )
root = tree.getroot()
except:
log.exception( 'fail:' )
continue
if root.tag == 'tool':
- rval = Bunch()
- try:
- rval.id = root.attrib['id']
- rval.name = root.attrib['name']
- rval.version = root.attrib['version']
- except KeyError, e:
- raise DatatypeVerificationError( 'Tool XML file does not conform to the specification. Missing required <tool> tag attribute: %s' % e )
- rval.description = ''
- desc_tag = root.find( 'description' )
- if desc_tag is not None:
- description = desc_tag.text
- if description:
- rval.description = description.strip()
- rval.message = 'Tool: %s %s, Version: %s, ID: %s' % ( str( rval.name ), str( rval.description ), str( rval.version ), str( rval.id ) )
- return rval
- else:
- raise DatatypeVerificationError( 'Unable to find a properly formatted tool XML file' )
+ if tool_tags:
+ # We are verifying the tools inside a tool suite, so the current tag should have been found in the suite_config.xml
+ # file parsed in the ToolSuite verify() method. The tool_tags dictionary should include a key matching the current
+ # tool Id, and a tuple value matching the tool name and version.
+ if root.attrib[ 'id' ] not in tool_tags:
+ raise DatatypeVerificationError( 'Tool Id (%s) is not included in the suite_config.xml file.' % \
+ ( str( root.attrib[ 'id' ] ) ) )
+ tup = tool_tags[ root.attrib[ 'id' ] ]
+ if root.attrib[ 'name' ] != tup[ 0 ]:
+ raise DatatypeVerificationError( 'Tool name (%s) differs between suite_config.xml and the tool config file for tool Id (%s).' % \
+ ( str( root.attrib[ 'name' ] ), str( root.attrib[ 'id' ] ) ) )
+ if root.attrib[ 'version' ] != tup[ 1 ]:
+ raise DatatypeVerificationError( 'Tool version (%s) differs between suite_config.xml and the tool config file for tool Id (%s).' % \
+ ( str( root.attrib[ 'version' ] ), str( root.attrib[ 'id' ] ) ) )
+ else:
+ # We are not verifying a tool suite, so we'll create a bunch for returning to the caller.
+ tool_bunch = Bunch()
+ try:
+ tool_bunch.id = root.attrib['id']
+ tool_bunch.name = root.attrib['name']
+ tool_bunch.version = root.attrib['version']
+ except KeyError, e:
+ raise DatatypeVerificationError( 'Tool XML file does not conform to the specification. Missing required <tool> tag attribute: %s' % str( e ) )
+ tool_bunch.description = ''
+ desc_tag = root.find( 'description' )
+ if desc_tag is not None:
+ description = desc_tag.text
+ if description:
+ tool_bunch.description = description.strip()
+ tool_bunch.message = 'Tool: %s %s, Version: %s, Id: %s' % \
+ ( str( tool_bunch.name ), str( tool_bunch.description ), str( tool_bunch.version ), str( tool_bunch.id ) )
+ return tool_bunch
+ else:
+ # TODO: should we verify files that are not tool configs?
+ log.debug( "The file named (%s) is not a tool config, so skipping verification." % str( xml_file ) )
def create_model_object( self, datatype_bunch ):
if self.model_object is None:
- raise Exception( 'No model object configured for %s, please check the datatype configuration file' % self.__class__.__name__ )
+ raise Exception( 'No model object configured for %s, check the datatype configuration file' % self.__class__.__name__ )
if datatype_bunch is None:
# TODO: do it automatically
raise Exception( 'Unable to create %s model object without passing in data' % self.__class__.__name__ )
o = self.model_object()
o.create_from_datatype( datatype_bunch )
return o
- def sniff( self, fname ):
+
+class ToolSuite( Tool ):
+ def __init__( self, model_object=None ):
+ self.model_object = model_object
+ self.label = 'Tool Suite'
+ def verify( self, f ):
+ """
+ A sample tool suite config:
+
+ ONTO-Toolkit is a collection of Galaxy tools which support the manipulation of bio-ontologies.
+
+ Collects the ancestor terms from a given term in the given OBO ontology
+
+
+ Collects the child terms from a given term in the given OBO ontology
+
+
+ """
try:
- self.verify( open( fname, 'r' ) )
- return True
+ tar = tarfile.open( f.name )
+ except tarfile.ReadError:
+ raise DatatypeVerificationError( 'The archive is not a readable tar file.' )
+ suite_config = filter( lambda x: x.lower() == 'tool_suite.xml', tar.getnames() )
+ if not suite_config:
+ raise DatatypeVerificationError( 'The archive does not contain the required tool_suite.xml config file. If you are uploading a single tool archive, set the upload type to "Tool".' )
+ suite_config = suite_config[ 0 ]
+ # Parse and verify suite_config
+ archive_ok = False
+ try:
+ tree = ElementTree.parse( tar.extractfile( suite_config ) )
+ root = tree.getroot()
+ archive_ok = True
except:
- return False
+ log.exception( 'fail:' )
+ if archive_ok and root.tag == 'suite':
+ suite_bunch = Bunch()
+ try:
+ suite_bunch.id = root.attrib['id']
+ suite_bunch.name = root.attrib['name']
+ suite_bunch.version = root.attrib['version']
+ except KeyError, e:
+ raise DatatypeVerificationError( 'The file named tool-suite.xml does not conform to the specification. Missing required <suite> tag attribute: %s' % str( e ) )
+ suite_bunch.description = ''
+ desc_tag = root.find( 'description' )
+ if desc_tag is not None:
+ description = desc_tag.text
+ if description:
+ suite_bunch.description = description.strip()
+ suite_bunch.message = 'Tool suite: %s %s, Version: %s, Id: %s' % \
+ ( str( suite_bunch.name ), str( suite_bunch.description ), str( suite_bunch.version ), str( suite_bunch.id ) )
+ # Create a dictionary of the tools in the suite where the keys are tool_ids and the
+ # values are tuples of tool name and version
+ tool_tags = {}
+ for elem in root.findall( 'tool' ):
+ tool_tags[ elem.attrib['id'] ] = ( elem.attrib['name'], elem.attrib['version'] )
+ else:
+ raise DatatypeVerificationError( "The file named %s is not a valid tool suite config." % str( suite_config ) )
+ # Verify all included tool config files
+ xml_files = filter( lambda x: x.lower().endswith( '.xml' ) and x.lower() != 'tool_suite.xml', tar.getnames() )
+ if not xml_files:
+ raise DatatypeVerificationError( 'The archive does not contain any tool config (xml) files.' )
+ Tool.verify( self, f, xml_files=xml_files, tool_tags=tool_tags )
+ return suite_bunch
diff --git a/lib/galaxy/webapps/community/model/__init__.py b/lib/galaxy/webapps/community/model/__init__.py
index 5e323c38e10..5ba3fb95329 100644
--- a/lib/galaxy/webapps/community/model/__init__.py
+++ b/lib/galaxy/webapps/community/model/__init__.py
@@ -1,5 +1,5 @@
"""
-Galaxy Community Space data model classes
+Galaxy Tool Shed data model classes
Naming: try to use class names that have a distinct plural form so that
the relationship cardinalities are obvious (e.g. prefer Dataset to Data)
@@ -95,7 +95,7 @@ class Tool( object ):
REJECTED = 'rejected',
ARCHIVED = 'archived' )
def __init__( self, guid=None, tool_id=None, name=None, description=None, user_description=None,
- category=None, version=None, user_id=None, external_filename=None ):
+ category=None, version=None, user_id=None, external_filename=None, suite=False ):
self.guid = guid
self.tool_id = tool_id
self.name = name or "Unnamed tool"
@@ -106,6 +106,7 @@ class Tool( object ):
self.external_filename = external_filename
self.deleted = False
self.__extension = None
+ self.suite = suite
def get_file_name( self ):
if not self.external_filename:
assert self.id is not None, "ID must be set before filename used (commit the object)"
@@ -133,6 +134,8 @@ class Tool( object ):
self.description = datatype_bunch.description
self.version = datatype_bunch.version
self.user_id = datatype_bunch.user.id
+ self.suite = datatype_bunch.suite
+ @property
def state( self ):
if self.events:
# Sort the events in ascending order by update_time
@@ -150,35 +153,47 @@ class Tool( object ):
else:
return ''
return 'No comment'
+ # Tool states
+ @property
def is_new( self ):
- return self.state() == self.states.NEW
+ return self.state == self.states.NEW
+ @property
def is_error( self ):
- return self.state() == self.states.ERROR
+ return self.state == self.states.ERROR
+ @property
def is_deleted( self ):
- return self.state() == self.states.DELETED
+ return self.state == self.states.DELETED
+ @property
def is_waiting( self ):
- return self.state() == self.states.WAITING
+ return self.state == self.states.WAITING
+ @property
def is_approved( self ):
- return self.state() == self.states.APPROVED
+ return self.state == self.states.APPROVED
+ @property
def is_rejected( self ):
- return self.state() == self.states.REJECTED
+ return self.state == self.states.REJECTED
+ @property
def is_archived( self ):
- return self.state() == self.states.ARCHIVED
+ return self.state == self.states.ARCHIVED
def get_state_message( self ):
- if self.is_new():
- return 'This is an unsubmitted version of this tool'
- if self.is_error():
- return 'This tool is in an error state'
- if self.is_deleted():
- return 'This is a deleted version of this tool'
- if self.is_waiting():
- return 'This version of this tool is awaiting administrative approval'
- if self.is_approved():
- return 'This is the latest approved version of this tool'
- if self.is_rejected():
- return 'This version of this tool has been rejected by an administrator'
- if self.is_archived():
- return 'This is an archived version of this tool'
+ if self.is_suite:
+ label = 'tool suite'
+ else:
+ label = 'tool'
+ if self.is_new:
+ return 'This is an unsubmitted version of this %s' % label
+ if self.is_error:
+ return 'This %s is in an error state' % label
+ if self.is_deleted:
+ return 'This is a deleted version of this %s' % label
+ if self.is_waiting:
+ return 'This version of this %s is awaiting administrative approval' % label
+ if self.is_approved:
+ return 'This is the latest approved version of this %s' % label
+ if self.is_rejected:
+ return 'This version of this %s has been rejected by an administrator' % label
+ if self.is_archived:
+ return 'This is an archived version of this %s' % label
@property
def extension( self ):
# if instantiated via a query, this unmapped property won't exist
@@ -202,6 +217,15 @@ class Tool( object ):
self.__extension = 'tar'
return self.__extension
@property
+ def is_suite( self ):
+ return self.suite
+ @property
+ def label( self ):
+ if self.is_suite:
+ return 'tool suite'
+ else:
+ return 'tool'
+ @property
def download_file_name( self ):
return '%s_%s.%s' % ( self.tool_id, self.version, self.extension )
@property
diff --git a/lib/galaxy/webapps/community/model/mapping.py b/lib/galaxy/webapps/community/model/mapping.py
index 62b5c89a3a9..566729a3d37 100644
--- a/lib/galaxy/webapps/community/model/mapping.py
+++ b/lib/galaxy/webapps/community/model/mapping.py
@@ -113,7 +113,8 @@ Tool.table = Table( "tool", metadata,
Column( "version", TrimmedString( 255 ) ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
Column( "external_filename" , TEXT ),
- Column( "deleted", Boolean, index=True, default=False ) )
+ Column( "deleted", Boolean, index=True, default=False ),
+ Column( "suite", Boolean, default=False, index=True ) )
Category.table = Table( "category", metadata,
Column( "id", Integer, primary_key=True ),
diff --git a/lib/galaxy/webapps/community/model/migrate/versions/0002_add_tool_suite_column.py b/lib/galaxy/webapps/community/model/migrate/versions/0002_add_tool_suite_column.py
new file mode 100644
index 00000000000..591c2e8bf32
--- /dev/null
+++ b/lib/galaxy/webapps/community/model/migrate/versions/0002_add_tool_suite_column.py
@@ -0,0 +1,48 @@
+"""
+Migration script to add the suite column to the tool table.
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+
+ # Create and initialize imported column in job table.
+ Tool_table = Table( "tool", metadata, autoload=True )
+ c = Column( "suite", Boolean, default=False, index=True )
+ try:
+ # Create
+ c.create( Tool_table )
+ assert c is Tool_table.c.suite
+
+ # Initialize.
+ if migrate_engine.name == 'mysql' or migrate_engine.name == 'sqlite':
+ default_false = "0"
+ elif migrate_engine.name == 'postgres':
+ default_false = "false"
+ db_session.execute( "UPDATE tool SET suite=%s" % default_false )
+
+ except Exception, e:
+ print "Adding suite column to the tool table failed: %s" % str( e )
+ log.debug( "Adding suite column to the tool table failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+
+ # Drop imported column from job table.
+ Tool_table = Table( "tool", metadata, autoload=True )
+ try:
+ Tool_table.c.suite.drop()
+ except Exception, e:
+ print "Dropping column suite from the tool table failed: %s" % str( e )
+ log.debug( "Dropping column suite from the tool table failed: %s" % str( e ) )
diff --git a/lib/galaxy/webapps/community/security/__init__.py b/lib/galaxy/webapps/community/security/__init__.py
index eb85f6d558e..153d429580e 100644
--- a/lib/galaxy/webapps/community/security/__init__.py
+++ b/lib/galaxy/webapps/community/security/__init__.py
@@ -1,5 +1,5 @@
"""
-Galaxy Community Space Security
+Galaxy Tool Shed Security
"""
import logging, socket, operator
from datetime import datetime, timedelta
@@ -167,14 +167,14 @@ class CommunityRBACAgent( RBACAgent ):
def can_approve_or_reject( self, user, user_is_admin, cntrller, item ):
# The current user can approve or reject the item if the user
# is an admin, and the item's state is WAITING.
- return user and user_is_admin and cntrller=='admin' and item.is_waiting()
+ return user and user_is_admin and cntrller=='admin' and item.is_waiting
def can_delete( self, user, user_is_admin, cntrller, item ):
# The current user can delete the item if they are an admin or if they uploaded the
# item and in either case the item's state is not DELETED.
if user and user_is_admin and cntrller == 'admin':
- can_delete = not item.is_deleted()
+ can_delete = not item.is_deleted
elif cntrller in [ 'tool' ]:
- can_delete = user==item.user and not item.is_deleted()
+ can_delete = user==item.user and not item.is_deleted
else:
can_delete = False
return can_delete
@@ -184,7 +184,7 @@ class CommunityRBACAgent( RBACAgent ):
if user and user_is_admin and cntrller == 'admin':
return True
elif cntrller in [ 'tool' ]:
- can_download = not( item.is_new() or item.is_waiting() )
+ can_download = not( item.is_new or item.is_waiting )
else:
can_download = False
return can_download
@@ -194,7 +194,7 @@ class CommunityRBACAgent( RBACAgent ):
if user and user_is_admin and cntrller == 'admin':
return True
if cntrller in [ 'tool' ]:
- return user and user==item.user and ( item.is_new() or item.is_rejected() )
+ return user and user==item.user and ( item.is_new or item.is_rejected )
return False
def can_purge( self, user, user_is_admin, cntrller ):
# The current user can purge the item if they are an admin.
@@ -206,7 +206,7 @@ class CommunityRBACAgent( RBACAgent ):
versions = get_versions( item )
state_ok = True
for version in versions:
- if version.is_new() or version.is_waiting():
+ if version.is_new or version.is_waiting:
state_ok = False
break
return state_ok
@@ -215,7 +215,7 @@ class CommunityRBACAgent( RBACAgent ):
# or if the item's state is APPROVED.
if user and user_is_admin and cntrller == 'admin':
return True
- if cntrller in [ 'tool' ] and item.is_approved():
+ if cntrller in [ 'tool' ] and item.is_approved:
return True
return user and user==item.user
def get_all_action_permissions( self, user, user_is_admin, cntrller, item ):
@@ -236,7 +236,7 @@ class CommunityRBACAgent( RBACAgent ):
elif cntrller in [ 'tool' ]:
visible_versions = []
for version in get_versions( item ):
- if version.is_approved() or version.is_archived() or version.user == user:
+ if version.is_approved or version.is_archived or version.user == user:
visible_versions.append( version )
else:
visible_versions = []
diff --git a/templates/webapps/community/admin/index.mako b/templates/webapps/community/admin/index.mako
index 31c9c064645..fd71484dc4d 100644
--- a/templates/webapps/community/admin/index.mako
+++ b/templates/webapps/community/admin/index.mako
@@ -1,7 +1,7 @@
<%inherit file="/webapps/community/base_panels.mako"/>
## Default title
-<%def name="title()">Galaxy Community Space Administration%def>
+<%def name="title()">Galaxy Tool Shed Administration%def>
<%def name="stylesheets()">
${parent.stylesheets()}
diff --git a/templates/webapps/community/base_panels.mako b/templates/webapps/community/base_panels.mako
index 3d9f256d6f6..01b05e34da6 100644
--- a/templates/webapps/community/base_panels.mako
+++ b/templates/webapps/community/base_panels.mako
@@ -1,7 +1,7 @@
<%inherit file="/base_panels.mako"/>
## Default title
-<%def name="title()">Galaxy Community Space%def>
+<%def name="title()">Galaxy Tool Shed%def>
## Masthead
<%def name="masthead()">
@@ -94,7 +94,7 @@