1 new changeset in galaxy-central: http://bitbucket.org/galaxy/galaxy-central/changeset/ca6db8f67477/ changeset: ca6db8f67477 user: natefoo date: 2011-09-14 20:36:38 summary: New API features: * The @web.require_admin decorator can now be used on API methods * When using model.model_class.get_api_value(), api_*_visible_keys can now be mapper attributes to other model classes (get_api_value() recursion) * Monkeypatch the route mapper to contain a resource_with_deleted() method. This works just like the existing mapper.resource() method but adds extra routes. The following is a supplement to the Routes RESTful services documentation at: https://routes.groovie.org/restful.html Using: mapper.resources_with_deleted( "message", "items" ) Would result in the same routes as in the use of resource(), with the addition of: map.connect("deleted_messages", "/messages/deleted", controller=messages, action="index", deleted=True, conditions=dict(method=["GET"]) map.connect("deleted_message", "/messages/deleted/{id}", controller=messages, action="show", deleted=True, conditions=dict(method=["GET"]) map.connect("undelete_deleted_message", "/messages/deleted/{id}/undelete", controller=messages, action="index", conditions=dict(method=["POST"]) Which adds to the convention: GET /messages/deleted => messages.index(deleted=True) => url("deleted_messages") GET /messages/deleted/1 => messages.show(id, deleted=True) => url("deleted_message", id=1) POST /messages/deleted/1/undelete => messages.undelete(id) => url("undelete_deleted_message", id=1) affected #: 3 files (1.7 KB) --- a/lib/galaxy/model/item_attrs.py Tue Sep 13 16:55:17 2011 -0400 +++ b/lib/galaxy/model/item_attrs.py Wed Sep 14 14:36:38 2011 -0400 @@ -1,4 +1,5 @@ from sqlalchemy.sql.expression import func +from sqlalchemy.orm.collections import InstrumentedList # Cannot import galaxy.model b/c it creates a circular import graph. import galaxy import logging @@ -156,6 +157,13 @@ #api_collection_visible_keys = ( 'id' ) #api_element_visible_keys = ( 'id' ) def get_api_value( self, view='collection', value_mapper = None ): + def get_value( key, item ): + try: + return item.get_api_value( view=view, value_mapper=value_mapper ) + except: + if key in value_mapper: + return value_mapper.get( key )( item ) + return item if value_mapper is None: value_mapper = {} rval = {} @@ -165,9 +173,13 @@ raise Exception( 'Unknown API view: %s' % view ) for key in visible_keys: try: - rval[key] = self.__getattribute__( key ) - if key in value_mapper: - rval[key] = value_mapper.get( key )( rval[key] ) + item = self.__getattribute__( key ) + if type( item ) == InstrumentedList: + rval[key] = [] + for i in item: + rval[key].append( get_value( key, i ) ) + else: + rval[key] = get_value( key, item ) except AttributeError: rval[key] = None return rval --- a/lib/galaxy/web/framework/__init__.py Tue Sep 13 16:55:17 2011 -0400 +++ b/lib/galaxy/web/framework/__init__.py Wed Sep 14 14:36:38 2011 -0400 @@ -117,7 +117,7 @@ return error trans.response.set_content_type( "application/json" ) trans.set_user( provided_key.user ) -# Perform api_run_as processing, possibly changing identity + # Perform api_run_as processing, possibly changing identity if 'run_as' in kwargs: if not trans.user_can_do_run_as(): error_message = 'User does not have permissions to run jobs as another user' @@ -147,13 +147,18 @@ def require_admin( func ): def decorator( self, trans, *args, **kwargs ): if not trans.user_is_admin(): + msg = "You must be an administrator to access this feature." admin_users = trans.app.config.get( "admin_users", "" ).split( "," ) + user = trans.get_user() if not admin_users: - return trans.show_error_message( "You must be logged in as an administrator to access this feature, but no administrators are set in the Galaxy configuration." ) - user = trans.get_user() - if not user: - return trans.show_error_message( "You must be logged in as an administrator to access this feature." ) - return trans.show_error_message( "You must be an administrator to access this feature." ) + msg = "You must be logged in as an administrator to access this feature, but no administrators are set in the Galaxy configuration." + elif not user: + msg = "You must be logged in as an administrator to access this feature." + trans.response.status = 403 + if trans.response.get_content_type() == 'application/json': + return msg + else: + return trans.show_error_message( msg ) return func( self, trans, *args, **kwargs ) return decorator --- a/lib/galaxy/web/framework/base.py Tue Sep 13 16:55:17 2011 -0400 +++ b/lib/galaxy/web/framework/base.py Wed Sep 14 14:36:38 2011 -0400 @@ -29,6 +29,21 @@ log = logging.getLogger( __name__ ) +def __resource_with_deleted( self, member_name, collection_name, **kwargs ): + """ + Method to monkeypatch on to routes.mapper.Mapper which does the same thing + as resource() with the addition of standardized routes for handling + elements in Galaxy's "deleted but not really deleted" fashion. + """ + collection_path = kwargs.get( 'path_prefix', '' ) + '/' + collection_name + '/deleted' + member_path = collection_path + '/:id' + self.connect( 'deleted_' + collection_name, collection_path, controller=collection_name, action='index', deleted=True ) + self.connect( 'deleted_' + member_name, member_path, controller=collection_name, action='show', deleted=True ) + self.connect( 'undelete_deleted_' + member_name, member_path + '/undelete', controller=collection_name, action='undelete', + conditions=dict( method=['POST'] ) ) + self.resource( member_name, collection_name, **kwargs ) +routes.Mapper.resource_with_deleted = __resource_with_deleted + class WebApplication( object ): """ A simple web application which maps requests to objects using routes, @@ -320,6 +335,8 @@ Sets the Content-Type header """ self.headers[ "content-type" ] = type + def get_content_type( self ): + return self.headers[ "content-type" ] def send_redirect( self, url ): """ Send an HTTP redirect response to (target `url`) Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.