Changeset - 256e729a94cd
[Not reviewed]
beta
0 4 0
Marcin Kuzminski - 14 years ago 2011-09-30 17:03:20
marcin@python-works.com
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
4 files changed with 160 insertions and 26 deletions:
0 comments (0 inline, 0 general)
docs/api/api.rst
Show inline comments
 
@@ -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 
 
<your-server>/_admin/api
 
<your_server>/_admin/api
 

	
 

	
 
Clients need to send JSON data in such format::
 
All clients need to send JSON data in such format::
 

	
 
    {
 
        "api_key":"<api_key>",
 
@@ -19,16 +19,20 @@ Clients need to send JSON data in such f
 
        "args":{"<arg_key>":"<arg_val>"}
 
    }
 

	
 
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": "<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:"<api_key>"
 
    method: "pull"
 
    args: {"repo":<repo_name>}
 

	
 
OUTPUT::
 

	
 
    result:"Pulled from <repo_name>"
 
    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:"<api_key>"
 
    method: "create_user"
 
    args: {"username": "<username>", 
 
           "password": "<password>", 
 
           "active":   "<bool>", 
 
           "admin":    "<bool>", 
 
           "name":     "<firstname>", 
 
           "lastname": "<lastname>", 
 
           "email":    "<useremail>"}
 

	
 
OUTPUT::
 

	
 
    result:{"id": <newuserid>,
 
            "msg":"created new user <username>"}
 
    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:"<api_key>"
 
    method: "create_user"
 
    args: {"name":  "<groupname>", 
 
           "active":"<bool>"}
 

	
 
OUTPUT::
 

	
 
    result:{"id": <newusersgroupid>,
 
            "msg":"created new users group <groupname>"}
 
    error:null    
rhodecode/controllers/api/__init__.py
Show inline comments
 
@@ -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)
 

	
rhodecode/controllers/api/api.py
Show inline comments
 
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
rhodecode/model/db.py
Show inline comments
 
@@ -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()
0 comments (0 inline, 0 general)