# HG changeset patch # User Marcin Kuzminski # Date 2011-12-20 23:53:01 # Node ID 631caf880b876a094f5a9c84ecaf29c664cd3bb2 # Parent 2afa6b8c2adeab2c03da0b169b7675f23f063a5d implements #329 - api function for adding a users_group into repo - fixed found issues on API with missing params detection - updated docs for api diff --git a/docs/api/api.rst b/docs/api/api.rst --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -223,8 +223,8 @@ OUTPUT:: } 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 @@ -302,14 +302,14 @@ OUTPUT:: "active" : "", "admin" :  "", "ldap" : "", - "permission" : "repository_(read|write|admin)" + "permission" : "repository.(read|write|admin)" }, … { "id" : "", "name" : "", "active": "", - "permission" : "repository_(read|write|admin)" + "permission" : "repository.(read|write|admin)" }, … ] @@ -356,10 +356,27 @@ INPUT:: args: { "repo_name" : "", "user_name" : "", - "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 : "" + method : "add_users_group_to_repo" + args: { + "repo_name" : "", + "group_name" : "", + "perm" : "(None|repository.(read|write|admin))", + } \ No newline at end of file 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 @@ -46,6 +46,7 @@ from rhodecode.lib.auth import AuthUser log = logging.getLogger('JSONRPC') + class JSONRPCError(BaseException): def __init__(self, message): @@ -67,19 +68,18 @@ def jsonrpc_error(message, code=None): return resp - class JSONRPCController(WSGIController): """ A WSGI-speaking JSON-RPC controller class - + See the 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): @@ -111,7 +111,7 @@ class JSONRPCController(WSGIController): 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))) @@ -120,10 +120,10 @@ class JSONRPCController(WSGIController): 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) @@ -146,13 +146,14 @@ class JSONRPCController(WSGIController): # 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 @@ -167,21 +168,23 @@ class JSONRPCController(WSGIController): (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 @@ -190,6 +193,7 @@ class JSONRPCController(WSGIController): status = [] headers = [] exc_info = [] + def change_content(new_status, new_headers, new_exc_info=None): status.append(new_status) headers.extend(new_headers) 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 @@ -60,41 +60,47 @@ class ApiController(JSONRPCController): """" Get a user by username - :param apiuser - :param username + :param apiuser: + :param username: """ user = User.get_by_username(username) if not user: return None - return dict(id=user.user_id, + return dict( + id=user.user_id, + username=user.username, + firstname=user.name, + lastname=user.lastname, + email=user.email, + active=user.active, + admin=user.admin, + ldap=user.ldap_dn + ) + + @HasPermissionAllDecorator('hg.admin') + def get_users(self, apiuser): + """" + Get all users + + :param apiuser: + """ + + result = [] + for user in User.getAll(): + result.append( + dict( + id=user.user_id, username=user.username, firstname=user.name, lastname=user.lastname, email=user.email, active=user.active, admin=user.admin, - ldap=user.ldap_dn) - - @HasPermissionAllDecorator('hg.admin') - def get_users(self, apiuser): - """" - Get all users - - :param apiuser - """ - - result = [] - for user in User.getAll(): - result.append(dict(id=user.user_id, - username=user.username, - firstname=user.name, - lastname=user.lastname, - email=user.email, - active=user.active, - admin=user.admin, - ldap=user.ldap_dn)) + ldap=user.ldap_dn + ) + ) return result @HasPermissionAllDecorator('hg.admin') @@ -131,8 +137,8 @@ class ApiController(JSONRPCController): """" Get users group by name - :param apiuser - :param group_name + :param apiuser: + :param group_name: """ users_group = UsersGroup.get_by_group_name(group_name) @@ -161,7 +167,7 @@ class ApiController(JSONRPCController): """" Get all users groups - :param apiuser + :param apiuser: """ result = [] @@ -210,9 +216,9 @@ class ApiController(JSONRPCController): """" Add a user to a group - :param apiuser - :param group_name - :param user_name + :param apiuser: + :param group_name: + :param user_name: """ try: @@ -238,8 +244,8 @@ class ApiController(JSONRPCController): """" Get repository by name - :param apiuser - :param repo_name + :param apiuser: + :param repo_name: """ repo = Repository.get_by_repo_name(repo_name) @@ -250,45 +256,59 @@ class ApiController(JSONRPCController): for user in repo.repo_to_perm: perm = user.permission.permission_name user = user.user - members.append(dict(type_="user", - id=user.user_id, - username=user.username, - firstname=user.name, - lastname=user.lastname, - email=user.email, - active=user.active, - admin=user.admin, - ldap=user.ldap_dn, - permission=perm)) + members.append( + dict( + type_="user", + id=user.user_id, + username=user.username, + firstname=user.name, + lastname=user.lastname, + email=user.email, + active=user.active, + admin=user.admin, + ldap=user.ldap_dn, + permission=perm + ) + ) for users_group in repo.users_group_to_perm: perm = users_group.permission.permission_name users_group = users_group.users_group - members.append(dict(type_="users_group", - id=users_group.users_group_id, - name=users_group.users_group_name, - active=users_group.users_group_active, - permission=perm)) + members.append( + dict( + type_="users_group", + id=users_group.users_group_id, + name=users_group.users_group_name, + active=users_group.users_group_active, + permission=perm + ) + ) - return dict(id=repo.repo_id, - name=repo.repo_name, - type=repo.repo_type, - description=repo.description, - members=members) + return dict( + id=repo.repo_id, + name=repo.repo_name, + type=repo.repo_type, + description=repo.description, + members=members + ) @HasPermissionAnyDecorator('hg.admin') def get_repos(self, apiuser): """" Get all repositories - :param apiuser + :param apiuser: """ result = [] for repository in Repository.getAll(): - result.append(dict(id=repository.repo_id, - name=repository.repo_name, - type=repository.repo_type, - description=repository.description)) + result.append( + dict( + id=repository.repo_id, + name=repository.repo_name, + type=repository.repo_type, + description=repository.description + ) + ) return result @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository') @@ -297,12 +317,12 @@ class ApiController(JSONRPCController): """ Create a repository - :param apiuser - :param name - :param description - :param type - :param private - :param owner_name + :param apiuser: + :param name: + :param description: + :param type: + :param private: + :param owner_name: """ try: @@ -321,18 +341,27 @@ class ApiController(JSONRPCController): for g in groups: group = RepoGroup.get_by_group_name(g) if not group: - group = ReposGroupModel().create(dict(group_name=g, - group_description='', - group_parent_id=parent_id)) + group = ReposGroupModel().create( + dict( + group_name=g, + group_description='', + group_parent_id=parent_id + ) + ) parent_id = group.group_id - RepoModel().create(dict(repo_name=real_name, - repo_name_full=name, - description=description, - private=private, - repo_type=repo_type, - repo_group=parent_id, - clone_uri=None), owner) + RepoModel().create( + dict( + repo_name=real_name, + repo_name_full=name, + description=description, + private=private, + repo_type=repo_type, + repo_group=parent_id, + clone_uri=None + ), + owner + ) Session.commit() except Exception: log.error(traceback.format_exc()) @@ -343,16 +372,16 @@ class ApiController(JSONRPCController): """ Add permission for a user to a repository - :param apiuser - :param repo_name - :param user_name - :param perm + :param apiuser: + :param repo_name: + :param user_name: + :param perm: """ try: repo = Repository.get_by_repo_name(repo_name) if repo is None: - raise JSONRPCError('unknown repository %s' % repo) + raise JSONRPCError('unknown repository %s' % repo) try: user = User.get_by_username(user_name) @@ -362,8 +391,54 @@ class ApiController(JSONRPCController): RepositoryPermissionModel()\ .update_or_delete_user_permission(repo, user, perm) Session.commit() + + return dict( + msg='Added perm: %s for %s in repo: %s' % ( + perm, user_name, repo_name + ) + ) except Exception: log.error(traceback.format_exc()) - raise JSONRPCError('failed to edit permission %(repo)s for %(user)s' - % dict(user=user_name, repo=repo_name)) + raise JSONRPCError( + 'failed to edit permission %(repo)s for %(user)s' % dict( + user=user_name, repo=repo_name + ) + ) + + @HasPermissionAnyDecorator('hg.admin') + def add_users_group_to_repo(self, apiuser, repo_name, group_name, perm): + """ + Add permission for a users group to a repository + + :param apiuser: + :param repo_name: + :param group_name: + :param perm: + """ + + try: + repo = Repository.get_by_repo_name(repo_name) + if repo is None: + raise JSONRPCError('unknown repository %s' % repo) + try: + user_group = UsersGroup.get_by_group_name(group_name) + except NoResultFound: + raise JSONRPCError('unknown users group %s' % user_group) + + RepositoryPermissionModel()\ + .update_or_delete_users_group_permission(repo, user_group, + perm) + Session.commit() + return dict( + msg='Added perm: %s for %s in repo: %s' % ( + perm, group_name, repo_name + ) + ) + except Exception: + log.error(traceback.format_exc()) + raise JSONRPCError( + 'failed to edit permission %(repo)s for %(usergr)s' % dict( + usergr=group_name, repo=repo_name + ) + ) diff --git a/rhodecode/model/repo_permission.py b/rhodecode/model/repo_permission.py --- a/rhodecode/model/repo_permission.py +++ b/rhodecode/model/repo_permission.py @@ -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 + :copyright: (C) 2009-2011 Marcin Kuzminski :license: GPLv3, see COPYING for more details. """ # This program is free software: you can redistribute it and/or modify @@ -25,7 +26,7 @@ import logging from rhodecode.model import BaseModel -from rhodecode.model.db import UserRepoToPerm, Permission +from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, Permission log = logging.getLogger(__name__) @@ -39,6 +40,15 @@ class RepositoryPermissionModel(BaseMode .scalar() def update_user_permission(self, repository, user, permission): + + #TODO: REMOVE THIS !! + ################################ + import ipdb;ipdb.set_trace() + print 'setting ipdb debuggin for rhodecode.model.repo_permission.RepositoryPermissionModel.update_user_permission' + ################################ + + + permission = Permission.get_by_key(permission) current = self.get_user_permission(repository, user) if current: @@ -56,8 +66,41 @@ class RepositoryPermissionModel(BaseMode if current: self.sa.delete(current) + 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) + + def delete_users_group_permission(self, repository, users_group): + current = self.get_users_group_permission(repository, users_group) + if current: + self.sa.delete(current) + 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) \ No newline at end of file