# HG changeset patch # User Marcin Kuzminski # Date 2011-09-30 15:03:20 # Node ID 256e729a94cdf9118e8fde757fae5ad73d7c4d56 # Parent 182f5bd3b49d52f3f9591c84262bc2666671a92d Extended API - updated docs - created two new methods for creating users and creating users groups - changed user attribute generated from api_key to apiuser for better name compatibility with functoin parameters diff --git a/docs/api/api.rst b/docs/api/api.rst --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -6,12 +6,12 @@ API Starting from RhodeCode version 1.2 a simple API was implemented. -There's one schema for calling all api methods. API is implemented +There's a single schema for calling all api methods. API is implemented with JSON protocol both ways. An url to send API request in RhodeCode is -/_admin/api +/_admin/api -Clients need to send JSON data in such format:: +All clients need to send JSON data in such format:: { "api_key":"", @@ -19,16 +19,20 @@ Clients need to send JSON data in such f "args":{"":""} } -Simply provide api_key for access and permission validation -method is name of method to call -and args is an key:value list of arguments to pass to method +Example call for autopulling remotes repos using curl:: + curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}' + +Simply provide + - *api_key* for access and permission validation. + - *method* is name of method to call + - *args* is an key:value list of arguments to pass to method .. note:: api_key can be found in your user account page -And will receive JSON formatted answer:: +RhodeCode API will return always a JSON formatted answer:: { "result": "", @@ -36,7 +40,7 @@ And will receive JSON formatted answer:: } All responses from API will be `HTTP/1.0 200 OK`, if there's an error while -calling api **error** key from response will contain failure description +calling api *error* key from response will contain failure description and result will be null. API METHODS @@ -47,11 +51,61 @@ pull ---- Pulls given repo from remote location. Can be used to automatically keep -remote repos upto date. This command can be executed only using admin users -api_key +remote repos up to date. This command can be executed only using api_key +belonging to user with admin rights -:: +INPUT:: + api_key:"" method: "pull" args: {"repo":} +OUTPUT:: + + result:"Pulled from " + error:null + + +create_user +----------- + +Creates new user in RhodeCode. This command can be executed only using api_key +belonging to user with admin rights + +INPUT:: + + api_key:"" + method: "create_user" + args: {"username": "", + "password": "", + "active": "", + "admin": "", + "name": "", + "lastname": "", + "email": ""} + +OUTPUT:: + + result:{"id": , + "msg":"created new user "} + error:null + + +create_users_group +------------------ + +creates new users group. This command can be executed only using api_key +belonging to user with admin rights + +INPUT:: + + api_key:"" + method: "create_user" + args: {"name": "", + "active":""} + +OUTPUT:: + + result:{"id": , + "msg":"created new users group "} + error:null diff --git a/rhodecode/controllers/api/__init__.py b/rhodecode/controllers/api/__init__.py --- a/rhodecode/controllers/api/__init__.py +++ b/rhodecode/controllers/api/__init__.py @@ -136,25 +136,29 @@ class JSONRPCController(WSGIController): # this is little trick to inject logged in user for # perms decorators to work they expect the controller class to have - # rhodecode_user set + # rhodecode_user attribute set self.rhodecode_user = auth_u - if 'user' not in arglist: + # This attribute will need to be first param of a method that uses + # api_key, which is translated to instance of user at that name + USER_SESSION_ATTR = 'apiuser' + + if USER_SESSION_ATTR not in arglist: return jsonrpc_error(message='This method [%s] does not support ' - 'authentication (missing user param)' % - self._func.__name__) + 'authentication (missing %s param)' % + (self._func.__name__, USER_SESSION_ATTR)) # get our arglist and check if we provided them as args for arg in arglist: - if arg == 'user': - # user is something translated from api key and this is - # checked before + if arg == USER_SESSION_ATTR: + # USER_SESSION_ATTR is something translated from api key and + # this is checked before so we don't need validate it continue if not self._req_params or arg not in self._req_params: return jsonrpc_error(message='Missing %s arg in JSON DATA' % arg) - self._rpc_args = dict(user=u) + self._rpc_args = {USER_SESSION_ATTR:u} self._rpc_args.update(self._req_params) self._rpc_args['action'] = self._req_method @@ -183,7 +187,6 @@ class JSONRPCController(WSGIController): """ try: raw_response = self._inspect_call(self._func) - print raw_response if isinstance(raw_response, HTTPError): self._error = str(raw_response) except JSONRPCError as e: @@ -223,3 +226,4 @@ class JSONRPCController(WSGIController): return func else: raise AttributeError("No such method: %s" % self._req_method) + diff --git a/rhodecode/controllers/api/api.py b/rhodecode/controllers/api/api.py --- a/rhodecode/controllers/api/api.py +++ b/rhodecode/controllers/api/api.py @@ -1,7 +1,14 @@ +import traceback +import logging + from rhodecode.controllers.api import JSONRPCController, JSONRPCError from rhodecode.lib.auth import HasPermissionAllDecorator from rhodecode.model.scm import ScmModel +from rhodecode.model.db import User, UsersGroup + +log = logging.getLogger(__name__) + class ApiController(JSONRPCController): """ @@ -20,13 +27,13 @@ class ApiController(JSONRPCController): """ @HasPermissionAllDecorator('hg.admin') - def pull(self, user, repo): + def pull(self, apiuser, repo): """ Dispatch pull action on given repo - param user: - param repo: + :param user: + :param repo: """ try: @@ -36,5 +43,53 @@ class ApiController(JSONRPCController): raise JSONRPCError('Unable to pull changes from "%s"' % repo) + @HasPermissionAllDecorator('hg.admin') + def create_user(self, apiuser, username, password, active, admin, name, + lastname, email): + """ + Creates new user + + :param apiuser: + :param username: + :param password: + :param active: + :param admin: + :param name: + :param lastname: + :param email: + """ + + form_data = dict(username=username, + password=password, + active=active, + admin=admin, + name=name, + lastname=lastname, + email=email) + try: + u = User.create(form_data) + return {'id':u.user_id, + 'msg':'created new user %s' % name} + except Exception: + log.error(traceback.format_exc()) + raise JSONRPCError('failed to create user %s' % name) + @HasPermissionAllDecorator('hg.admin') + def create_users_group(self, apiuser, name, active): + """ + Creates an new usergroup + + :param name: + :param active: + """ + form_data = {'users_group_name':name, + 'users_group_active':active} + try: + ug = UsersGroup.create(form_data) + return {'id':ug.users_group_id, + 'msg':'created new users group %s' % name} + except Exception: + log.error(traceback.format_exc()) + raise JSONRPCError('failed to create group %s' % name) + \ No newline at end of file diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -38,12 +38,13 @@ from beaker.cache import cache_region, r from vcs import get_backend from vcs.utils.helpers import get_scm -from vcs.exceptions import RepositoryError, VCSError +from vcs.exceptions import VCSError from vcs.utils.lazy import LazyProperty -from vcs.nodes import FileNode from rhodecode.lib.exceptions import UsersGroupsAssignedException -from rhodecode.lib import str2bool, json, safe_str, get_changeset_safe +from rhodecode.lib import str2bool, json, safe_str, get_changeset_safe,\ + generate_api_key + from rhodecode.model.meta import Base, Session from rhodecode.model.caching_query import FromCache @@ -298,6 +299,25 @@ class User(Base, BaseModel): Session.commit() log.debug('updated user %s lastlogin', self.username) + @classmethod + def create(cls, form_data): + from rhodecode.lib.auth import get_crypt_password + + try: + new_user = cls() + for k, v in form_data.items(): + if k == 'password': + v = get_crypt_password(v) + setattr(new_user, k, v) + + new_user.api_key = generate_api_key(form_data['username']) + Session.add(new_user) + Session.commit() + return new_user + except: + log.error(traceback.format_exc()) + Session.rollback() + raise class UserLog(Base, BaseModel): __tablename__ = 'user_logs' @@ -362,6 +382,7 @@ class UsersGroup(Base, BaseModel): Session.add(new_users_group) Session.commit() + return new_users_group except: log.error(traceback.format_exc()) Session.rollback()