changeset 1500:256e729a94cd beta

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
author Marcin Kuzminski <marcin@python-works.com>
date Fri, 30 Sep 2011 18:03:20 +0300
parents 182f5bd3b49d
children a828b83dfa4b
files docs/api/api.rst rhodecode/controllers/api/__init__.py rhodecode/controllers/api/api.py rhodecode/model/db.py
diffstat 4 files changed, 160 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/docs/api/api.rst	Fri Sep 30 01:50:21 2011 +0300
+++ b/docs/api/api.rst	Fri Sep 30 18:03:20 2011 +0300
@@ -6,12 +6,12 @@
 
 
 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 @@
         "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 @@
     }
 
 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 @@
 ----
 
 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    
--- a/rhodecode/controllers/api/__init__.py	Fri Sep 30 01:50:21 2011 +0300
+++ b/rhodecode/controllers/api/__init__.py	Fri Sep 30 18:03:20 2011 +0300
@@ -136,25 +136,29 @@
 
         # 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 @@
         """
         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 @@
             return func
         else:
             raise AttributeError("No such method: %s" % self._req_method)
+
--- a/rhodecode/controllers/api/api.py	Fri Sep 30 01:50:21 2011 +0300
+++ b/rhodecode/controllers/api/api.py	Fri Sep 30 18:03:20 2011 +0300
@@ -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 @@
     """
 
     @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 @@
             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
--- a/rhodecode/model/db.py	Fri Sep 30 01:50:21 2011 +0300
+++ b/rhodecode/model/db.py	Fri Sep 30 18:03:20 2011 +0300
@@ -38,12 +38,13 @@
 
 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 @@
         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 @@
 
             Session.add(new_users_group)
             Session.commit()
+            return new_users_group
         except:
             log.error(traceback.format_exc())
             Session.rollback()