diff --git a/lib/galaxy/webapps/tool_shed/api/users.py b/lib/galaxy/webapps/tool_shed/api/users.py
new file mode 100644
index 00000000000..2690f80153f
--- /dev/null
+++ b/lib/galaxy/webapps/tool_shed/api/users.py
@@ -0,0 +1,128 @@
+import logging
+import os
+
+from galaxy import util
+from galaxy import web
+from galaxy.web.base.controller import BaseAPIController
+from galaxy.security.validate_user_input import validate_email
+from galaxy.security.validate_user_input import validate_publicname
+from galaxy.security.validate_user_input import validate_password
+import tool_shed.util.shed_util_common as suc
+
+log = logging.getLogger( __name__ )
+
+
+class UsersController( BaseAPIController ):
+ """RESTful controller for interactions with users in the Tool Shed."""
+
+ @web.expose_api
+ def create_user( self, trans, payload, **kwd ):
+ """
+ POST /api/users/create_user
+ Returns a dictionary of information about the created user.
+
+: param key: the current Galaxy admin user's API key
+
+ The following parameters are included in the payload.
+ :param username (required): the public username of the user
+ """
+ user_dict = dict( message = '',
+ status = 'ok' )
+ # Make sure the current user's API key proves he is an admin user in this Tool Shed.
+ if trans.user_is_admin():
+ # Get the information about the user to be created from the payload.
+ email = payload.get( 'email', '' )
+ password = payload.get( 'password', '' )
+ username = payload.get( 'username', '' )
+ message = self.__validate( trans,
+ email=email,
+ password=password,
+ confirm=password,
+ username=username )
+ if message:
+ message = 'email: %s, username: %s - %s' % ( email, username, message )
+ user_dict[ 'message' ] = message
+ user_dict[ 'status' ] = 'error'
+ else:
+ # Create the user.
+ user = self.__create_user( trans, email, username, password )
+ user_dict = user.to_dict( view='element',
+ value_mapper=self.__get_value_mapper( trans ) )
+ user_dict[ 'message' ] = "User '%s' has been created." % str( user.username )
+ user_dict[ 'url' ] = web.url_for( controller='users',
+ action='show',
+ id=trans.security.encode_id( user.id ) )
+ else:
+ user_dict[ 'message' ] = 'You are not authorized to create a user in this Tool Shed.'
+ user_dict[ 'status' ] = 'error'
+ return user_dict
+
+ def __create_user( self, trans, email, username, password ):
+ user = trans.app.model.User( email=email )
+ user.set_password_cleartext( password )
+ user.username = username
+ if trans.app.config.user_activation_on:
+ user.active = False
+ else:
+ user.active = True # Activation is off, every new user is active by default.
+ trans.sa_session.add( user )
+ trans.sa_session.flush()
+ trans.app.security_agent.create_private_user_role( user )
+ return user
+
+ def __get_value_mapper( self, trans ):
+ value_mapper = { 'id' : trans.security.encode_id }
+ return value_mapper
+
+ @web.expose_api_anonymous
+ def index( self, trans, deleted=False, **kwd ):
+ """
+ GET /api/users
+ Returns a list of dictionaries that contain information about each user.
+ """
+ # Example URL: http://localhost:9009/api/users
+ user_dicts = []
+ deleted = util.asbool( deleted )
+ for user in trans.sa_session.query( trans.app.model.User ) \
+ .filter( trans.app.model.User.table.c.deleted == deleted ) \
+ .order_by( trans.app.model.User.table.c.username ):
+ user_dict = user.to_dict( view='collection',
+ value_mapper=self.__get_value_mapper( trans ) )
+ user_dict[ 'url' ] = web.url_for( controller='users',
+ action='show',
+ id=trans.security.encode_id( user.id ) )
+ user_dicts.append( user_dict )
+ return user_dicts
+
+ @web.expose_api_anonymous
+ def show( self, trans, id, **kwd ):
+ """
+ GET /api/users/{encoded_user_id}
+ Returns a dictionary of information about a user.
+
+ :param id: the encoded id of the User object.
+ """
+ # Example URL: http://localhost:9009/api/users/f9cad7b01a472135
+ user = suc.get_user( trans, id )
+ if user is None:
+ user_dict = dict( message = 'Unable to locate user record for id %s.' % ( str( id ) ),
+ status = 'error' )
+ return user_dict
+ user_dict = user.to_dict( view='element',
+ value_mapper=self.__get_value_mapper( trans ) )
+ user_dict[ 'url' ] = web.url_for( controller='users',
+ action='show',
+ id=trans.security.encode_id( user.id ) )
+ return user_dict
+
+ def __validate( self, trans, email, password, confirm, username ):
+ if not username:
+ return "A public user name is required in the Tool Shed."
+ if username in [ 'repos' ]:
+ return "The term %s is a reserved word in the Tool Shed, so it cannot be used as a public user name." % username
+ message = validate_email( trans, email )
+ if not message:
+ message = validate_password( trans, password, confirm )
+ if not message and username:
+ message = validate_publicname( trans, username )
+ return message
diff --git a/lib/galaxy/webapps/tool_shed/buildapp.py b/lib/galaxy/webapps/tool_shed/buildapp.py
index e9cd1916dff..bf157c19b6a 100644
--- a/lib/galaxy/webapps/tool_shed/buildapp.py
+++ b/lib/galaxy/webapps/tool_shed/buildapp.py
@@ -107,6 +107,13 @@ def app_factory( global_conf, **kwargs ):
name_prefix='repository_revision_',
path_prefix='/api',
parent_resources=dict( member_name='repository_revision', collection_name='repository_revisions' ) )
+ webapp.mapper.resource( 'user',
+ 'users',
+ controller='users',
+ name_prefix='user_',
+ path_prefix='/api',
+ new={ 'create_user' : 'POST' },
+ parent_resources=dict( member_name='user', collection_name='users' ) )
webapp.finalize_config()
# Wrap the webapp in some useful middleware
if kwargs.get( 'middleware', True ):
diff --git a/lib/galaxy/webapps/tool_shed/model/__init__.py b/lib/galaxy/webapps/tool_shed/model/__init__.py
index 7648bce61d0..6a8f7be5318 100644
--- a/lib/galaxy/webapps/tool_shed/model/__init__.py
+++ b/lib/galaxy/webapps/tool_shed/model/__init__.py
@@ -20,8 +20,8 @@ class APIKeys( object ):
class User( object, Dictifiable ):
- dict_collection_visible_keys = ( 'id', 'email' )
- dict_element_visible_keys = ( 'id', 'email', 'username' )
+ dict_collection_visible_keys = ( 'id', 'username' )
+ dict_element_visible_keys = ( 'id', 'username' )
def __init__( self, email=None, password=None ):
self.email = email
diff --git a/lib/tool_shed/scripts/api/create_categories.py b/lib/tool_shed/scripts/api/create_categories.py
index 7ebb3a063b1..1c908659689 100644
--- a/lib/tool_shed/scripts/api/create_categories.py
+++ b/lib/tool_shed/scripts/api/create_categories.py
@@ -9,10 +9,10 @@ will not be affected.
This script is very useful for populating a new development Tool Shed with the set of categories that
currently exist in either the test or main public Galaxy Tool Sheds. This will streamline building
-new repository hierarchies in the development Tool Shed and exportin gthem into a capsule that can be
+new repository hierarchies in the development Tool Shed and exporting them into a capsule that can be
imported into one of the public Tool Sheds.
-Here is a working example of how to use this script to retrieve the current set of repositories that are
+Here is a working example of how to use this script to retrieve the current set of categories that are
available in the test public Tool Shed and create each of them in a local development Tool Shed.
./create_categories.py -a -f http://testtoolshed.g2.bx.psu.edu -t http://localhost:9009
diff --git a/lib/tool_shed/scripts/api/create_users.py b/lib/tool_shed/scripts/api/create_users.py
new file mode 100644
index 00000000000..fd5148f7eb6
--- /dev/null
+++ b/lib/tool_shed/scripts/api/create_users.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+"""
+This script will retrieve a list of dictionaries (one for each user) from the Tool Shed defined
+by the --from_tool_shed parameter, which should be a base Tool Shed URL. It will retrieve the
+username from each dictionary and create a new user with that username in the Tool Shed defined
+by the --to_tool_shed parameter (a different base Tool Shed URL). An email and password value
+will automatically be provided for each user. Email addresses will be @test.org and
+passwords will be testuser. Users that already exist with a specified username in the Tool Shed
+in which the users are being created will not be affected.
+
+This script is very useful for populating a new development Tool Shed with the set of users that
+currently exist in either the test or main public Galaxy Tool Sheds. This will streamline building
+new repository hierarchies in the development Tool Shed and exporting them into a capsule that can
+be imported into one of the public Tool Sheds.
+
+Here is a working example of how to use this script to retrieve the current set of users that
+are available in the test public Tool Shed and create each of them in a local development Tool Shed.
+
+./create_users.py -a -f http://testtoolshed.g2.bx.psu.edu -t http://localhost:9009
+"""
+
+import os
+import sys
+import argparse
+sys.path.insert( 0, os.path.dirname( __file__ ) )
+from common import get
+from common import submit
+
+def main( options ):
+ api_key = options.api
+ from_tool_shed = options.from_tool_shed.rstrip( '/' )
+ to_tool_shed = options.to_tool_shed.rstrip( '/' )
+ # Get the users from the specified Tool Shed.
+ url = '%s/api/users' % from_tool_shed
+ user_dicts = get( url )
+ create_response_dicts = []
+ for user_dict in user_dicts:
+ username = user_dict.get( 'username', None )
+ if username is not None:
+ email = '%s@test.org' % username
+ password = 'testuser'
+ data = dict( email=email,
+ password=password,
+ username=username )
+ url = '%s/api/users/new/create_user' % to_tool_shed
+ try:
+ response = submit( url, data, api_key )
+ except Exception, e:
+ response = str( e )
+ log.exception( str( e ) )
+ create_response_dict = dict( response=response )
+ create_response_dicts.append( create_response_dict )
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser( description='Retrieve a list of users from a Tool Shed and create them in another Tool Shed.' )
+ parser.add_argument( "-a", "--api", dest="api", required=True, help="API Key for Tool Shed in which users will be created" )
+ parser.add_argument( "-f", "--from_tool_shed", dest="from_tool_shed", required=True, help="URL of Tool Shed from which to retrieve the users" )
+ parser.add_argument( "-t", "--to_tool_shed", dest="to_tool_shed", required=True, help="URL of Tool Shed in which to create the users" )
+ options = parser.parse_args()
+ main( options )