changeset 1794:702e29ce1e9b

backporting #329 into stable
author Marcin Kuzminski <marcin@python-works.com>
date Wed, 21 Dec 2011 02:05:31 +0200
parents 8355c17fb6aa
children c60c54e7d211
files docs/api/api.rst rhodecode/controllers/api/__init__.py rhodecode/model/repo_permission.py
diffstat 3 files changed, 107 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/docs/api/api.rst	Wed Nov 02 23:23:53 2011 +0200
+++ b/docs/api/api.rst	Wed Dec 21 02:05:31 2011 +0200
@@ -11,7 +11,7 @@
 <your_server>/_admin/api
 
 
-All clients need to send JSON data in such format::
+All clients are required to send JSON-RPC spec JSON data::
 
     {
         "api_key":"<api_key>",
@@ -32,7 +32,7 @@
     api_key can be found in your user account page
 
 
-RhodeCode API will return always a JSON formatted answer::
+RhodeCode API will return always a JSON-RPC response::
 
     {
         "result": "<result>",
@@ -220,8 +220,8 @@
             }
     error:  null
 
-add_user_to_users_groups
-------------------------
+add_user_to_users_group
+-----------------------
 
 Adds a user to a users group. This command can be executed only using api_key
 belonging to user with admin rights
@@ -299,14 +299,14 @@
 	                                "active" :     "<bool>",
 	                                "admin" :      "<bool>",
 	                                "ldap" :       "<ldap_dn>",
-	                                "permission" : "repository_(read|write|admin)"
+	                                "permission" : "repository.(read|write|admin)"
 	                              },

                                   {
                                     "id" :       "<usersgroupid>",
                                     "name" :     "<usersgroupname>",
                                     "active":    "<bool>",
-                                    "permission" : "repository_(read|write|admin)"
+                                    "permission" : "repository.(read|write|admin)"
                                   },

                                 ]
@@ -353,10 +353,27 @@
     args:     {
                 "repo_name" :  "<reponame>",
                 "user_name" :  "<username>",
-                "perm" :       "(None|repository_(read|write|admin))",
+                "perm" :       "(None|repository.(read|write|admin))",
               }
 
 OUTPUT::
 
     result: None
     error:  null
+
+add_users_group_to_repo
+-----------------------
+
+Add a users group to a repository. This command can be executed only using 
+api_key belonging to user with admin rights. If "perm" is None, group will 
+be removed from the repository.
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "add_users_group_to_repo"
+    args:     {
+                "repo_name" :  "<reponame>",
+                "group_name" :  "<groupname>",
+                "perm" :       "(None|repository.(read|write|admin))",
+              }
\ No newline at end of file
--- a/rhodecode/controllers/api/__init__.py	Wed Nov 02 23:23:53 2011 +0200
+++ b/rhodecode/controllers/api/__init__.py	Wed Dec 21 02:05:31 2011 +0200
@@ -4,7 +4,7 @@
     ~~~~~~~~~~~~~~~~~~~~~~~~~
 
     JSON RPC controller
-    
+
     :created_on: Aug 20, 2011
     :author: marcink
     :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
@@ -36,7 +36,7 @@
 from paste.response import replace_header
 
 from pylons.controllers import WSGIController
-from pylons.controllers.util import Response
+
 
 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
 HTTPBadRequest, HTTPError
@@ -46,33 +46,40 @@
 
 log = logging.getLogger('JSONRPC')
 
+
 class JSONRPCError(BaseException):
 
     def __init__(self, message):
         self.message = message
+        super(JSONRPCError, self).__init__()
 
     def __str__(self):
         return str(self.message)
 
 
 def jsonrpc_error(message, code=None):
-    """Generate a Response object with a JSON-RPC error body"""
-    return Response(body=json.dumps(dict(result=None,
-                                         error=message)))
+    """
+    Generate a Response object with a JSON-RPC error body
+    """
+    from pylons.controllers.util import Response
+    resp = Response(body=json.dumps(dict(result=None, error=message)),
+                    status=code,
+                    content_type='application/json')
+    return resp
 
 
 class JSONRPCController(WSGIController):
     """
      A WSGI-speaking JSON-RPC controller class
-    
+
      See the specification:
      <http://json-rpc.org/wiki/specification>`.
-   
+
      Valid controller return values should be json-serializable objects.
-    
+
      Sub-classes should catch their exceptions and raise JSONRPCError
      if they want to pass meaningful errors to the client.
-    
+
      """
 
     def _get_method_args(self):
@@ -104,24 +111,27 @@
         try:
             json_body = json.loads(urllib.unquote_plus(raw_body))
         except ValueError, e:
-            #catch JSON errors Here
+            # catch JSON errors Here
             return jsonrpc_error(message="JSON parse error ERR:%s RAW:%r" \
                                  % (e, urllib.unquote_plus(raw_body)))
 
-        #check AUTH based on API KEY
+        # check AUTH based on API KEY
         try:
             self._req_api_key = json_body['api_key']
+            self._req_id = json_body['id']
             self._req_method = json_body['method']
-            self._req_params = json_body['args']
+            self._request_params = json_body['args']
             log.debug('method: %s, params: %s',
                       self._req_method,
-                      self._req_params)
+                      self._request_params)
         except KeyError, e:
             return jsonrpc_error(message='Incorrect JSON query missing %s' % e)
 
-        #check if we can find this session using api_key
+        # check if we can find this session using api_key
         try:
             u = User.get_by_api_key(self._req_api_key)
+            if u is None:
+                return jsonrpc_error(message='Invalid API KEY')
             auth_u = AuthUser(u.user_id, self._req_api_key)
         except Exception, e:
             return jsonrpc_error(message='Invalid API KEY')
@@ -136,13 +146,14 @@
         # self.kargs and dispatch control to WGIController
         argspec = inspect.getargspec(self._func)
         arglist = argspec[0][1:]
-        defaults = argspec[3] or []
+        defaults = map(type, argspec[3] or [])
         default_empty = types.NotImplementedType
 
-        kwarglist = list(izip_longest(reversed(arglist), reversed(defaults),
-                                fillvalue=default_empty))
+        # kw arguments required by this method
+        func_kwargs = dict(izip_longest(reversed(arglist), reversed(defaults),
+                                        fillvalue=default_empty))
 
-        # this is little trick to inject logged in user for 
+        # this is little trick to inject logged in user for
         # perms decorators to work they expect the controller class to have
         # rhodecode_user attribute set
         self.rhodecode_user = auth_u
@@ -157,21 +168,23 @@
                                  (self._func.__name__, USER_SESSION_ATTR))
 
         # get our arglist and check if we provided them as args
-        for arg, default in kwarglist:
+        for arg, default in func_kwargs.iteritems():
             if arg == USER_SESSION_ATTR:
-                # USER_SESSION_ATTR is something translated from api key and 
+                # USER_SESSION_ATTR is something translated from api key and
                 # this is checked before so we don't need validate it
                 continue
 
-            # skip the required param check if it's default value is 
+            # skip the required param check if it's default value is
             # NotImplementedType (default_empty)
-            if not self._req_params or (type(default) == default_empty
-                                        and arg not in self._req_params):
-                return jsonrpc_error(message=('Missing non optional %s arg '
-                                              'in JSON DATA') % arg)
+            if (default == default_empty and arg not in self._request_params):
+                return jsonrpc_error(
+                    message=(
+                        'Missing non optional `%s` arg in JSON DATA' % arg
+                    )
+                )
 
-        self._rpc_args = {USER_SESSION_ATTR:u}
-        self._rpc_args.update(self._req_params)
+        self._rpc_args = {USER_SESSION_ATTR: u}
+        self._rpc_args.update(self._request_params)
 
         self._rpc_args['action'] = self._req_method
         self._rpc_args['environ'] = environ
@@ -180,6 +193,7 @@
         status = []
         headers = []
         exc_info = []
+
         def change_content(new_status, new_headers, new_exc_info=None):
             status.append(new_status)
             headers.extend(new_headers)
@@ -212,7 +226,8 @@
         if self._error is not None:
             raw_response = None
 
-        response = dict(result=raw_response, error=self._error)
+        response = dict(result=raw_response,
+                        error=self._error)
 
         try:
             return json.dumps(response)
--- a/rhodecode/model/repo_permission.py	Wed Nov 02 23:23:53 2011 +0200
+++ b/rhodecode/model/repo_permission.py	Wed Dec 21 02:05:31 2011 +0200
@@ -6,8 +6,9 @@
     repository permission model for RhodeCode
 
     :created_on: Oct 1, 2011
-    :author: nvinot
+    :author: nvinot, marcink
     :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
     :license: GPLv3, see COPYING for more details.
 """
 # This program is free software: you can redistribute it and/or modify
@@ -24,11 +25,13 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import logging
-from rhodecode.model.db import BaseModel, RepoToPerm, Permission
+from rhodecode.model.db import BaseModel, RepoToPerm, Permission,\
+    UsersGroupRepoToPerm
 from rhodecode.model.meta import Session
 
 log = logging.getLogger(__name__)
 
+
 class RepositoryPermissionModel(BaseModel):
     def get_user_permission(self, repository, user):
         return RepoToPerm.query() \
@@ -56,8 +59,43 @@
             Session.delete(current)
             Session.commit()
 
+    def get_users_group_permission(self, repository, users_group):
+        return UsersGroupRepoToPerm.query() \
+                .filter(UsersGroupRepoToPerm.users_group == users_group) \
+                .filter(UsersGroupRepoToPerm.repository == repository) \
+                .scalar()
+
+    def update_users_group_permission(self, repository, users_group,
+                                      permission):
+        permission = Permission.get_by_key(permission)
+        current = self.get_users_group_permission(repository, users_group)
+        if current:
+            if not current.permission is permission:
+                current.permission = permission
+        else:
+            p = UsersGroupRepoToPerm()
+            p.users_group = users_group
+            p.repository = repository
+            p.permission = permission
+            self.sa.add(p)
+        Session.commit()
+
+    def delete_users_group_permission(self, repository, users_group):
+        current = self.get_users_group_permission(repository, users_group)
+        if current:
+            self.sa.delete(current)
+        Session.commit()
+
     def update_or_delete_user_permission(self, repository, user, permission):
         if permission:
             self.update_user_permission(repository, user, permission)
         else:
             self.delete_user_permission(repository, user)
+
+    def update_or_delete_users_group_permission(self, repository, user_group,
+                                              permission):
+        if permission:
+            self.update_users_group_permission(repository, user_group,
+                                               permission)
+        else:
+            self.delete_users_group_permission(repository, user_group)