1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/1bd67f03d4f1/ changeset: 1bd67f03d4f1 user: greg date: 2013-02-20 20:55:26 summary: Add the API framework to the Galaxy Tool Shed. affected #: 10 files diff -r 0fb1af8ce7410cd48c9259962a4e0da528ff4ef6 -r 1bd67f03d4f12d0f6cddacb57a6402cf306f8f55 lib/galaxy/webapps/community/api/repository_revisions.py --- /dev/null +++ b/lib/galaxy/webapps/community/api/repository_revisions.py @@ -0,0 +1,34 @@ +from galaxy import web, util, logging +from galaxy.web.base.controller import BaseController, BaseAPIController +from galaxy.web.framework.helpers import is_true + +import pkg_resources +pkg_resources.require( "Routes" ) +import routes + +log = logging.getLogger( __name__ ) + +class RepositoryRevisionsController( BaseAPIController ): + """RESTful controller for interactions with tool shed repositories.""" + @web.expose_api + def index( self, trans, downloadable=True, **kwd ): + """ + GET /api/repository_revisions + Displays a collection (list) of repository revisions. + """ + rval = [] + downloadable = util.string_as_bool( downloadable ) + try: + query = trans.sa_session.query( trans.app.model.RepositoryMetadata ) \ + .filter( trans.app.model.RepositoryMetadata.table.c.downloadable == downloadable ) \ + .order_by( trans.app.model.RepositoryMetadata.table.c.repository_id ) \ + .all() + for repository_metadata in query: + item = repository_metadata.get_api_value( value_mapper={ 'id' : trans.security.encode_id } ) + item[ 'url' ] = web.url_for( 'repository_revision', id=trans.security.encode_id( repository_metadata.id ) ) + rval.append( item ) + except Exception, e: + rval = "Error in repository_revisions API" + log.error( rval + ": %s" % str( e ) ) + trans.response.status = 500 + return rval diff -r 0fb1af8ce7410cd48c9259962a4e0da528ff4ef6 -r 1bd67f03d4f12d0f6cddacb57a6402cf306f8f55 lib/galaxy/webapps/community/buildapp.py --- a/lib/galaxy/webapps/community/buildapp.py +++ b/lib/galaxy/webapps/community/buildapp.py @@ -69,6 +69,9 @@ webapp.add_route( '/:controller/:action', action='index' ) webapp.add_route( '/:action', controller='repository', action='index' ) webapp.add_route( '/repos/*path_info', controller='hg', action='handle_request', path_info='/' ) + # Add the web API + webapp.add_api_controllers( 'galaxy.webapps.community.api', app ) + webapp.api_mapper.resource( 'repository_revision', 'repository_revisions', path_prefix='/api' ) webapp.finalize_config() # Wrap the webapp in some useful middleware if kwargs.get( 'middleware', True ): diff -r 0fb1af8ce7410cd48c9259962a4e0da528ff4ef6 -r 1bd67f03d4f12d0f6cddacb57a6402cf306f8f55 lib/galaxy/webapps/community/framework/middleware/remoteuser.py --- a/lib/galaxy/webapps/community/framework/middleware/remoteuser.py +++ b/lib/galaxy/webapps/community/framework/middleware/remoteuser.py @@ -75,6 +75,9 @@ elif path_info.startswith( '/api/' ): # The API handles its own authentication via keys return self.app( environ, start_response ) + elif path_info.startswith( '/user/api_keys' ): + # api_keys can be managed when remote_user is in use. + pass else: title = "Access to this Galaxy tool shed is denied" message = """ diff -r 0fb1af8ce7410cd48c9259962a4e0da528ff4ef6 -r 1bd67f03d4f12d0f6cddacb57a6402cf306f8f55 lib/galaxy/webapps/community/model/__init__.py --- a/lib/galaxy/webapps/community/model/__init__.py +++ b/lib/galaxy/webapps/community/model/__init__.py @@ -9,14 +9,20 @@ from galaxy.util.bunch import Bunch from galaxy.util.hash_util import new_secure_hash from galaxy.web.form_builder import * +from galaxy.model.item_attrs import APIItem from galaxy import eggs eggs.require('mercurial') from mercurial import hg, ui log = logging.getLogger( __name__ ) - -class User( object ): + +class APIKeys( object ): + pass + +class User( object, APIItem ): + api_collection_visible_keys = ( 'id', 'email' ) + api_element_visible_keys = ( 'id', 'email', 'username' ) def __init__( self, email=None, password=None ): self.email = email self.password = password @@ -47,12 +53,16 @@ def nice_total_disk_usage( self ): return 0 -class Group( object ): +class Group( object, APIItem ): + api_collection_visible_keys = ( 'id', 'name' ) + api_element_visible_keys = ( 'id', 'name' ) def __init__( self, name = None ): self.name = name self.deleted = False -class Role( object ): +class Role( object, APIItem ): + api_collection_visible_keys = ( 'id', 'name' ) + api_element_visible_keys = ( 'id', 'name', 'description', 'type' ) private_id = None types = Bunch( PRIVATE = 'private', @@ -103,7 +113,9 @@ self.is_valid = is_valid self.prev_session_id = prev_session_id -class Repository( object ): +class Repository( object, APIItem ): + api_collection_visible_keys = ( 'id', 'name' ) + api_element_visible_keys = ( 'id', 'name', 'description' ) file_states = Bunch( NORMAL = 'n', NEEDS_MERGING = 'm', MARKED_FOR_REMOVAL = 'r', @@ -155,7 +167,9 @@ fp.write( line ) fp.close() -class RepositoryMetadata( object ): +class RepositoryMetadata( object, APIItem ): + api_collection_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'malicious', 'downloadable' ) + api_element_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'malicious', 'downloadable' ) def __init__( self, repository_id=None, changeset_revision=None, metadata=None, tool_versions=None, malicious=False, downloadable=False ): self.repository_id = repository_id self.changeset_revision = changeset_revision @@ -163,8 +177,26 @@ self.tool_versions = tool_versions or dict() self.malicious = malicious self.downloadable = downloadable + def get_api_value( self, view='collection', value_mapper=None ): + if value_mapper is None: + value_mapper = {} + rval = {} + try: + visible_keys = self.__getattribute__( 'api_' + view + '_visible_keys' ) + except AttributeError: + 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 ] ) + except AttributeError: + rval[ key ] = None + return rval -class RepositoryReview( object ): +class RepositoryReview( object, APIItem ): + api_collection_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'user_id', 'rating' ) + api_element_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'user_id', 'rating' ) approved_states = Bunch( NO='no', YES='yes' ) def __init__( self, repository_id=None, changeset_revision=None, user_id=None, rating=None, deleted=False ): self.repository_id = repository_id @@ -173,7 +205,9 @@ self.rating = rating self.deleted = deleted -class ComponentReview( object ): +class ComponentReview( object, APIItem ): + api_collection_visible_keys = ( 'id', 'repository_review_id', 'component_id', 'private', 'approved', 'rating', 'deleted' ) + api_element_visible_keys = ( 'id', 'repository_review_id', 'component_id', 'private', 'approved', 'rating', 'deleted' ) approved_states = Bunch( NO='no', YES='yes', NA='not_applicable' ) def __init__( self, repository_review_id=None, component_id=None, comment=None, private=False, approved=False, rating=None, deleted=False ): self.repository_review_id = repository_review_id @@ -204,7 +238,9 @@ def set_item( self, repository ): self.repository = repository -class Category( object ): +class Category( object, APIItem ): + api_collection_visible_keys = ( 'id', 'name', 'description', 'deleted' ) + api_element_visible_keys = ( 'id', 'name', 'description', 'deleted' ) def __init__( self, name=None, description=None, deleted=False ): self.name = name self.description = description diff -r 0fb1af8ce7410cd48c9259962a4e0da528ff4ef6 -r 1bd67f03d4f12d0f6cddacb57a6402cf306f8f55 lib/galaxy/webapps/community/model/mapping.py --- a/lib/galaxy/webapps/community/model/mapping.py +++ b/lib/galaxy/webapps/community/model/mapping.py @@ -39,6 +39,12 @@ # Return the current time in UTC without any timezone information now = datetime.datetime.utcnow +APIKeys.table = Table( "api_keys", metadata, + Column( "id", Integer, primary_key=True ), + Column( "create_time", DateTime, default=now ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "key", TrimmedString( 32 ), index=True, unique=True ) ) + User.table = Table( "galaxy_user", metadata, Column( "id", Integer, primary_key=True), Column( "create_time", DateTime, default=now ), @@ -186,7 +192,11 @@ # With the tables defined we can define the mappers and setup the relationships between the model objects. assign_mapper( context, User, User.table, properties=dict( active_repositories=relation( Repository, primaryjoin=( ( Repository.table.c.user_id == User.table.c.id ) & ( not_( Repository.table.c.deleted ) ) ), order_by=( Repository.table.c.name ) ), - galaxy_sessions=relation( GalaxySession, order_by=desc( GalaxySession.table.c.update_time ) ) ) ) + galaxy_sessions=relation( GalaxySession, order_by=desc( GalaxySession.table.c.update_time ) ), + api_keys=relation( APIKeys, backref="user", order_by=desc( APIKeys.table.c.create_time ) ) ) ) + +assign_mapper( context, APIKeys, APIKeys.table, + properties = {} ) assign_mapper( context, Group, Group.table, properties=dict( users=relation( UserGroupAssociation ) ) ) diff -r 0fb1af8ce7410cd48c9259962a4e0da528ff4ef6 -r 1bd67f03d4f12d0f6cddacb57a6402cf306f8f55 lib/galaxy/webapps/community/model/migrate/versions/0015_add_api_keys_table.py --- /dev/null +++ b/lib/galaxy/webapps/community/model/migrate/versions/0015_add_api_keys_table.py @@ -0,0 +1,46 @@ +""" +Migration script to add the api_keys table. +""" +import datetime, sys, logging +from sqlalchemy import * +from sqlalchemy.orm import * +from migrate import * +from migrate.changeset import * +from galaxy.model.custom_types import * + +log = logging.getLogger( __name__ ) +log.setLevel(logging.DEBUG) +handler = logging.StreamHandler( sys.stdout ) +format = "%(name)s %(levelname)s %(asctime)s %(message)s" +formatter = logging.Formatter( format ) +handler.setFormatter( formatter ) +log.addHandler( handler ) + +now = datetime.datetime.utcnow + +metadata = MetaData( migrate_engine ) +db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) ) + +metadata = MetaData( migrate_engine ) + +APIKeys_table = Table( "api_keys", metadata, + Column( "id", Integer, primary_key=True ), + Column( "create_time", DateTime, default=now ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "key", TrimmedString( 32 ), index=True, unique=True ) ) + +def upgrade(): + print __doc__ + metadata.reflect() + try: + APIKeys_table.create() + except Exception, e: + log.debug( "Creating api_keys table failed: %s" % str( e ) ) + +def downgrade(): + # Load existing tables + metadata.reflect() + try: + APIKeys_table.drop() + except Exception, e: + log.debug( "Dropping api_keys table failed: %s" % str( e ) ) diff -r 0fb1af8ce7410cd48c9259962a4e0da528ff4ef6 -r 1bd67f03d4f12d0f6cddacb57a6402cf306f8f55 templates/user/index.mako --- a/templates/user/index.mako +++ b/templates/user/index.mako @@ -25,6 +25,7 @@ %endif %else: <li><a href="${h.url_for( controller='user', action='manage_user_info', cntrller=cntrller )}">${_('Manage your information')}</a></li> + <li><a href="${h.url_for( controller='user', action='api_keys', cntrller=cntrller )}">${_('Manage your API keys')}</a></li><li><a href="${h.url_for( controller='repository', action='manage_email_alerts', cntrller=cntrller )}">${_('Manage your email alerts')}</a></li><li><a href="${h.url_for( controller='user', action='logout', logout_all=True )}" target="_top">${_('Logout')}</a> ${_('of all user sessions')}</li> %endif diff -r 0fb1af8ce7410cd48c9259962a4e0da528ff4ef6 -r 1bd67f03d4f12d0f6cddacb57a6402cf306f8f55 templates/webapps/community/base_panels.mako --- a/templates/webapps/community/base_panels.mako +++ b/templates/webapps/community/base_panels.mako @@ -105,6 +105,7 @@ menu_options.append( [ _('Logout'), app.config.remote_user_logout_href, "_top" ] ) else: menu_options.append( [ _('Preferences'), h.url_for( controller='/user', action='index', cntrller='user' ), "galaxy_main" ] ) + menu_options.append( [ _('API Keys'), h.url_for( controller='/user', action='api_keys', cntrller='user' ), "galaxy_main" ] ) logout_url = h.url_for( controller='/user', action='logout' ) menu_options.append( [ 'Logout', logout_url, "_top" ] ) menu_options.append( None ) diff -r 0fb1af8ce7410cd48c9259962a4e0da528ff4ef6 -r 1bd67f03d4f12d0f6cddacb57a6402cf306f8f55 templates/webapps/galaxy/user/api_keys.mako --- a/templates/webapps/galaxy/user/api_keys.mako +++ b/templates/webapps/galaxy/user/api_keys.mako @@ -30,11 +30,14 @@ (invalidates old key) %endif <div class="toolParamHelp" style="clear: both;"> - An API key will allow you to access Galaxy via its web - API (documentation forthcoming). Please note that - <strong>this key acts as an alternate means to access - your account, and should be treated with the same care - as your login password</strong>. + <% + if trans.webapp.name == 'galaxy': + webapp_str = 'Galaxy' + else: + webapp_str = 'the Tool Shed' + %> + An API key will allow you to access ${webapp_str} via its web API. Please note that <strong>this key acts as an alternate means + to access your account and should be treated with the same care as your login password</strong>. </div></div></form> 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.