Mercurial > kallithea
changeset 3714:7e3d89d9d3a2 beta
- Manage User’s Groups: create, delete, rename, add/remove users inside.
by user group admin.
In this case, a user's group can be owned by several people thru an owner user's group.
Some refactoring of naming, permission handling logic.
- remove some code duplicity as well as inconsistent naming
line wrap: on
line diff
--- a/docs/api/api.rst Mon Apr 08 20:38:37 2013 +0200 +++ b/docs/api/api.rst Mon Apr 08 22:47:35 2013 +0200 @@ -518,8 +518,9 @@ api_key : "<api_key>" method : "create_users_group" args: { - "group_name": "<groupname>", - "active":"<bool> = Optional(True)" + "group_name": "<groupname>", + "owner" : "<onwer_name_or_id = Optional(=apiuser)>", + "active": "<bool> = Optional(True)" } OUTPUT::
--- a/rhodecode/__init__.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/__init__.py Mon Apr 08 22:47:35 2013 +0200 @@ -38,7 +38,7 @@ __version__ = ('.'.join((str(each) for each in VERSION[:3])) + '.'.join(VERSION[3:])) -__dbversion__ = 11 # defines current db version for migrations +__dbversion__ = 12 # defines current db version for migrations __platform__ = platform.system() __license__ = 'GPLv3' __py_version__ = sys.version_info
--- a/rhodecode/config/routing.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/config/routing.py Mon Apr 08 22:47:35 2013 +0200 @@ -200,6 +200,13 @@ m.connect("formatted_repos_group", "/repos_groups/{group_name:.*?}.{format}", action="show", conditions=dict(method=["GET"], function=check_group)) + + #add repo perm member + m.connect('set_repo_group_perm_member', + "/set_repo_group_perm_member/{group_name:.*?}", + action="set_repo_group_perm_member", + conditions=dict(method=["POST"], function=check_group)) + # ajax delete repository group perm user m.connect('delete_repos_group_user_perm', "/delete_repos_group_user_perm/{group_name:.*?}", @@ -279,9 +286,20 @@ action="show", conditions=dict(method=["GET"])) #EXTRAS USER ROUTES - m.connect("users_group_perm", "/users_groups_perm/{id}", + # update + m.connect("users_group_perm", "/users_groups/{id}/update_global_perm", action="update_perm", conditions=dict(method=["PUT"])) + #add user group perm member + m.connect('set_user_group_perm_member', "/users_groups/{id}/grant_perm", + action="set_user_group_perm_member", + conditions=dict(method=["POST"])) + + #ajax delete user group perm + m.connect('delete_user_group_perm_member', "/users_groups/{id}/revoke_perm", + action="delete_user_group_perm_member", + conditions=dict(method=["DELETE"])) + #ADMIN GROUP REST ROUTES rmap.resource('group', 'groups', controller='admin/groups', path_prefix=ADMIN_PREFIX)
--- a/rhodecode/controllers/admin/repos.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/controllers/admin/repos.py Mon Apr 08 22:47:35 2013 +0200 @@ -46,7 +46,7 @@ from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\ RhodeCodeSetting, RepositoryField from rhodecode.model.forms import RepoForm, RepoFieldForm, RepoPermsForm -from rhodecode.model.scm import ScmModel, GroupList +from rhodecode.model.scm import ScmModel, RepoGroupList from rhodecode.model.repo import RepoModel from rhodecode.lib.compat import json from sqlalchemy.sql.expression import func @@ -67,7 +67,7 @@ super(ReposController, self).__before__() def __load_defaults(self): - acl_groups = GroupList(RepoGroup.query().all(), + acl_groups = RepoGroupList(RepoGroup.query().all(), perm_set=['group.write', 'group.admin']) c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) @@ -214,7 +214,7 @@ if not HasReposGroupPermissionAny('group.admin', 'group.write')(group_name=gr_name): raise HTTPForbidden - acl_groups = GroupList(RepoGroup.query().all(), + acl_groups = RepoGroupList(RepoGroup.query().all(), perm_set=['group.write', 'group.admin']) c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) @@ -330,32 +330,8 @@ @HasRepoPermissionAllDecorator('repository.admin') def set_repo_perm_member(self, repo_name): form = RepoPermsForm()().to_python(request.POST) - - perms_new = form['perms_new'] - perms_updates = form['perms_updates'] - cur_repo = repo_name - - # update permissions - for member, perm, member_type in perms_updates: - if member_type == 'user': - # this updates existing one - RepoModel().grant_user_permission( - repo=cur_repo, user=member, perm=perm - ) - else: - RepoModel().grant_users_group_permission( - repo=cur_repo, group_name=member, perm=perm - ) - # set new permissions - for member, perm, member_type in perms_new: - if member_type == 'user': - RepoModel().grant_user_permission( - repo=cur_repo, user=member, perm=perm - ) - else: - RepoModel().grant_users_group_permission( - repo=cur_repo, group_name=member, perm=perm - ) + RepoModel()._update_permissions(repo_name, form['perms_new'], + form['perms_updates']) #TODO: implement this #action_logger(self.rhodecode_user, 'admin_changed_repo_permissions', # repo_name, self.ip_addr, self.sa)
--- a/rhodecode/controllers/admin/repos_groups.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/controllers/admin/repos_groups.py Mon Apr 08 22:47:35 2013 +0200 @@ -43,14 +43,15 @@ HasPermissionAll from rhodecode.lib.base import BaseController, render from rhodecode.model.db import RepoGroup, Repository +from rhodecode.model.scm import RepoGroupList from rhodecode.model.repos_group import ReposGroupModel -from rhodecode.model.forms import ReposGroupForm +from rhodecode.model.forms import ReposGroupForm, RepoGroupPermsForm from rhodecode.model.meta import Session from rhodecode.model.repo import RepoModel from webob.exc import HTTPInternalServerError, HTTPNotFound from rhodecode.lib.utils2 import str2bool, safe_int from sqlalchemy.sql.expression import func -from rhodecode.model.scm import GroupList + log = logging.getLogger(__name__) @@ -72,7 +73,7 @@ #override the choices for this form, we need to filter choices #and display only those we have ADMIN right - groups_with_admin_rights = GroupList(RepoGroup.query().all(), + groups_with_admin_rights = RepoGroupList(RepoGroup.query().all(), perm_set=['group.admin']) c.repo_groups = RepoGroup.groups_choices(groups=groups_with_admin_rights, show_empty_group=allow_empty_group) @@ -94,12 +95,12 @@ data = repo_group.get_dict() data['group_name'] = repo_group.name - # fill repository users + # fill repository group users for p in repo_group.repo_group_to_perm: data.update({'u_perm_%s' % p.user.username: p.permission.permission_name}) - # fill repository groups + # fill repository group groups for p in repo_group.users_group_to_perm: data.update({'g_perm_%s' % p.users_group.users_group_name: p.permission.permission_name}) @@ -118,7 +119,8 @@ def index(self, format='html'): """GET /repos_groups: All items in the collection""" # url('repos_groups') - group_iter = GroupList(RepoGroup.query().all(), perm_set=['group.admin']) + group_iter = RepoGroupList(RepoGroup.query().all(), + perm_set=['group.admin']) sk = lambda g: g.parents[0].group_name if g.parents else g.group_name c.groups = sorted(group_iter, key=sk) return render('admin/repos_groups/repos_groups_show.html') @@ -190,7 +192,7 @@ # method='put') # url('repos_group', group_name=GROUP_NAME) - c.repos_group = ReposGroupModel()._get_repos_group(group_name) + c.repos_group = ReposGroupModel()._get_repo_group(group_name) if HasPermissionAll('hg.admin')('group edit'): #we're global admin, we're ok and we can create TOP level groups allow_empty_group = True @@ -247,7 +249,7 @@ # method='delete') # url('repos_group', group_name=GROUP_NAME) - gr = c.repos_group = ReposGroupModel()._get_repos_group(group_name) + gr = c.repos_group = ReposGroupModel()._get_repo_group(group_name) repos = gr.repositories.all() if repos: h.flash(_('This group contains %s repositores and cannot be ' @@ -274,6 +276,24 @@ return redirect(url('repos_groups')) @HasReposGroupPermissionAnyDecorator('group.admin') + def set_repo_group_perm_member(self, group_name): + c.repos_group = ReposGroupModel()._get_repo_group(group_name) + form = RepoGroupPermsForm()().to_python(request.POST) + + recursive = form['recursive'] + # iterate over all members(if in recursive mode) of this groups and + # set the permissions ! + # this can be potentially heavy operation + ReposGroupModel()._update_permissions(c.repos_group, form['perms_new'], + form['perms_updates'], recursive) + #TODO: implement this + #action_logger(self.rhodecode_user, 'admin_changed_repo_permissions', + # repo_name, self.ip_addr, self.sa) + Session().commit() + h.flash(_('Repository Group permissions updated'), category='success') + return redirect(url('edit_repos_group', group_name=group_name)) + + @HasReposGroupPermissionAnyDecorator('group.admin') def delete_repos_group_user_perm(self, group_name): """ DELETE an existing repository group permission user @@ -337,7 +357,7 @@ """GET /repos_groups/group_name: Show a specific item""" # url('repos_group', group_name=GROUP_NAME) - c.group = c.repos_group = ReposGroupModel()._get_repos_group(group_name) + c.group = c.repos_group = ReposGroupModel()._get_repo_group(group_name) c.group_repos = c.group.repositories.all() #overwrite our cached list with current filter @@ -369,7 +389,7 @@ """GET /repos_groups/group_name/edit: Form to edit an existing item""" # url('edit_repos_group', group_name=GROUP_NAME) - c.repos_group = ReposGroupModel()._get_repos_group(group_name) + c.repos_group = ReposGroupModel()._get_repo_group(group_name) #we can only allow moving empty group if it's already a top-level #group, ie has no parents, or we're admin if HasPermissionAll('hg.admin')('group edit'):
--- a/rhodecode/controllers/admin/settings.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/controllers/admin/settings.py Mon Apr 08 22:47:35 2013 +0200 @@ -47,7 +47,7 @@ RhodeCodeSetting, PullRequest, PullRequestReviewers from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \ ApplicationUiSettingsForm, ApplicationVisualisationForm -from rhodecode.model.scm import ScmModel, GroupList +from rhodecode.model.scm import ScmModel, RepoGroupList from rhodecode.model.user import UserModel from rhodecode.model.repo import RepoModel from rhodecode.model.db import User
--- a/rhodecode/controllers/admin/users_groups.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/controllers/admin/users_groups.py Mon Apr 08 22:47:35 2013 +0200 @@ -34,18 +34,20 @@ from rhodecode.lib import helpers as h from rhodecode.lib.exceptions import UserGroupsAssignedException -from rhodecode.lib.utils2 import safe_unicode, str2bool -from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator +from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int +from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator,\ + HasUserGroupPermissionAnyDecorator from rhodecode.lib.base import BaseController, render - +from rhodecode.model.scm import UserGroupList from rhodecode.model.users_group import UserGroupModel - +from rhodecode.model.repo import RepoModel from rhodecode.model.db import User, UserGroup, UserGroupToPerm,\ UserGroupRepoToPerm, UserGroupRepoGroupToPerm -from rhodecode.model.forms import UserGroupForm +from rhodecode.model.forms import UserGroupForm, UserGroupPermsForm from rhodecode.model.meta import Session from rhodecode.lib.utils import action_logger from sqlalchemy.orm import joinedload +from webob.exc import HTTPInternalServerError log = logging.getLogger(__name__) @@ -57,17 +59,82 @@ # map.resource('users_group', 'users_groups') @LoginRequired() - @HasPermissionAllDecorator('hg.admin') def __before__(self): super(UsersGroupsController, self).__before__() c.available_permissions = config['available_permissions'] + def __load_data(self, user_group_id): + ugroup_repo_perms = UserGroupRepoToPerm.query()\ + .options(joinedload(UserGroupRepoToPerm.permission))\ + .options(joinedload(UserGroupRepoToPerm.repository))\ + .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\ + .all() + + for gr in ugroup_repo_perms: + c.users_group.permissions['repositories'][gr.repository.repo_name] \ + = gr.permission.permission_name + + ugroup_group_perms = UserGroupRepoGroupToPerm.query()\ + .options(joinedload(UserGroupRepoGroupToPerm.permission))\ + .options(joinedload(UserGroupRepoGroupToPerm.group))\ + .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\ + .all() + + for gr in ugroup_group_perms: + c.users_group.permissions['repositories_groups'][gr.group.group_name] \ + = gr.permission.permission_name + + c.group_members_obj = sorted((x.user for x in c.users_group.members), + key=lambda u: u.username.lower()) + + c.group_members = [(x.user_id, x.username) for x in c.group_members_obj] + c.available_members = sorted(((x.user_id, x.username) for x in + User.query().all()), + key=lambda u: u[1].lower()) + repo_model = RepoModel() + c.users_array = repo_model.get_users_js() + + # commented out due to not now supporting assignment for user group + # on user group + c.users_groups_array = "[]" # repo_model.get_users_groups_js() + c.available_permissions = config['available_permissions'] + + def __load_defaults(self, user_group_id): + """ + Load defaults settings for edit, and update + + :param user_group_id: + """ + user_group = UserGroup.get_or_404(user_group_id) + data = user_group.get_dict() + + ug_model = UserGroupModel() + + data.update({ + 'create_repo_perm': ug_model.has_perm(user_group, + 'hg.create.repository'), + 'fork_repo_perm': ug_model.has_perm(user_group, + 'hg.fork.repository'), + }) + + # fill user group users + for p in user_group.user_user_group_to_perm: + data.update({'u_perm_%s' % p.user.username: + p.permission.permission_name}) + + return data + def index(self, format='html'): """GET /users_groups: All items in the collection""" # url('users_groups') - c.users_groups_list = UserGroup().query().all() + + group_iter = UserGroupList(UserGroup().query().all(), + perm_set=['usergroup.admin']) + sk = lambda g: g.users_group_name + c.users_groups_list = sorted(group_iter, key=sk) return render('admin/users_groups/users_groups.html') + @HasPermissionAllDecorator('hg.admin') def create(self): """POST /users_groups: Create a new item""" # url('users_groups') @@ -76,7 +143,9 @@ try: form_result = users_group_form.to_python(dict(request.POST)) UserGroupModel().create(name=form_result['users_group_name'], - active=form_result['users_group_active']) + owner=self.rhodecode_user.user_id, + active=form_result['users_group_active']) + gr = form_result['users_group_name'] action_logger(self.rhodecode_user, 'admin_created_users_group:%s' % gr, @@ -97,45 +166,13 @@ return redirect(url('users_groups')) + @HasPermissionAllDecorator('hg.admin') def new(self, format='html'): """GET /users_groups/new: Form to create a new item""" # url('new_users_group') return render('admin/users_groups/users_group_add.html') - def _load_data(self, id): - c.users_group.permissions = { - 'repositories': {}, - 'repositories_groups': {} - } - - ugroup_repo_perms = UserGroupRepoToPerm.query()\ - .options(joinedload(UserGroupRepoToPerm.permission))\ - .options(joinedload(UserGroupRepoToPerm.repository))\ - .filter(UserGroupRepoToPerm.users_group_id == id)\ - .all() - - for gr in ugroup_repo_perms: - c.users_group.permissions['repositories'][gr.repository.repo_name] \ - = gr.permission.permission_name - - ugroup_group_perms = UserGroupRepoGroupToPerm.query()\ - .options(joinedload(UserGroupRepoGroupToPerm.permission))\ - .options(joinedload(UserGroupRepoGroupToPerm.group))\ - .filter(UserGroupRepoGroupToPerm.users_group_id == id)\ - .all() - - for gr in ugroup_group_perms: - c.users_group.permissions['repositories_groups'][gr.group.group_name] \ - = gr.permission.permission_name - - c.group_members_obj = sorted((x.user for x in c.users_group.members), - key=lambda u: u.username.lower()) - c.group_members = [(x.user_id, x.username) for x in - c.group_members_obj] - c.available_members = sorted(((x.user_id, x.username) for x in - User.query().all()), - key=lambda u: u[1].lower()) - + @HasUserGroupPermissionAnyDecorator('usergroup.admin') def update(self, id): """PUT /users_groups/id: Update an existing item""" # Forms posted to this method should contain a hidden field: @@ -146,7 +183,7 @@ # url('users_group', id=ID) c.users_group = UserGroup.get_or_404(id) - self._load_data(id) + self.__load_data(id) available_members = [safe_unicode(x[0]) for x in c.available_members] @@ -188,6 +225,7 @@ return redirect(url('edit_users_group', id=id)) + @HasUserGroupPermissionAnyDecorator('usergroup.admin') def delete(self, id): """DELETE /users_groups/id: Delete an existing item""" # Forms posted to this method should contain a hidden field: @@ -209,25 +247,71 @@ category='error') return redirect(url('users_groups')) + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + def set_user_group_perm_member(self, id): + """ + grant permission for given usergroup + + :param id: + """ + user_group = UserGroup.get_or_404(id) + form = UserGroupPermsForm()().to_python(request.POST) + + # set the permissions ! + UserGroupModel()._update_permissions(user_group, form['perms_new'], + form['perms_updates']) + #TODO: implement this + #action_logger(self.rhodecode_user, 'admin_changed_repo_permissions', + # repo_name, self.ip_addr, self.sa) + Session().commit() + h.flash(_('User Group permissions updated'), category='success') + return redirect(url('edit_users_group', id=id)) + + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + def delete_user_group_perm_member(self, id): + """ + DELETE an existing repository group permission user + + :param group_name: + """ + try: + obj_type = request.POST.get('obj_type') + obj_id = None + if obj_type == 'user': + obj_id = safe_int(request.POST.get('user_id')) + elif obj_type == 'user_group': + obj_id = safe_int(request.POST.get('user_group_id')) + + if not c.rhodecode_user.is_admin: + if obj_type == 'user' and c.rhodecode_user.user_id == obj_id: + msg = _('Cannot revoke permission for yourself as admin') + h.flash(msg, category='warning') + raise Exception('revoke admin permission on self') + if obj_type == 'user': + UserGroupModel().revoke_user_permission(user_group=id, + user=obj_id) + elif obj_type == 'user_group': + pass + Session().commit() + except Exception: + log.error(traceback.format_exc()) + h.flash(_('An error occurred during deletion of group user'), + category='error') + raise HTTPInternalServerError() + def show(self, id, format='html'): """GET /users_groups/id: Show a specific item""" # url('users_group', id=ID) + @HasUserGroupPermissionAnyDecorator('usergroup.admin') def edit(self, id, format='html'): """GET /users_groups/id/edit: Form to edit an existing item""" # url('edit_users_group', id=ID) c.users_group = UserGroup.get_or_404(id) - self._load_data(id) + self.__load_data(id) - ug_model = UserGroupModel() - defaults = c.users_group.get_dict() - defaults.update({ - 'create_repo_perm': ug_model.has_perm(c.users_group, - 'hg.create.repository'), - 'fork_repo_perm': ug_model.has_perm(c.users_group, - 'hg.fork.repository'), - }) + defaults = self.__load_defaults(id) return htmlfill.render( render('admin/users_groups/users_group_edit.html'), @@ -236,6 +320,7 @@ force_defaults=False ) + @HasUserGroupPermissionAnyDecorator('usergroup.admin') def update_perm(self, id): """PUT /users_perm/id: Update an existing item""" # url('users_group_perm', id=ID, method='put')
--- a/rhodecode/controllers/api/api.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/controllers/api/api.py Mon Apr 08 22:47:35 2013 +0200 @@ -537,12 +537,15 @@ return result @HasPermissionAllDecorator('hg.admin') - def create_users_group(self, apiuser, group_name, active=Optional(True)): + def create_users_group(self, apiuser, group_name, + owner=Optional(OAttr('apiuser')), + active=Optional(True)): """ Creates an new usergroup :param apiuser: :param group_name: + :param owner: :param active: """ @@ -550,8 +553,14 @@ raise JSONRPCError("user group `%s` already exist" % group_name) try: + if isinstance(owner, Optional): + owner = apiuser.user_id + + owner = get_user_or_error(owner) active = Optional.extract(active) - ug = UserGroupModel().create(name=group_name, active=active) + ug = UserGroupModel().create(name=group_name, + owner=owner, + active=active) Session().commit() return dict( msg='created new user group `%s`' % group_name,
--- a/rhodecode/controllers/forks.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/controllers/forks.py Mon Apr 08 22:47:35 2013 +0200 @@ -42,7 +42,7 @@ RhodeCodeUi from rhodecode.model.repo import RepoModel from rhodecode.model.forms import RepoForkForm -from rhodecode.model.scm import ScmModel, GroupList +from rhodecode.model.scm import ScmModel, RepoGroupList from rhodecode.lib.utils2 import safe_int log = logging.getLogger(__name__) @@ -55,7 +55,7 @@ super(ForksController, self).__before__() def __load_defaults(self): - acl_groups = GroupList(RepoGroup.query().all(), + acl_groups = RepoGroupList(RepoGroup.query().all(), perm_set=['group.write', 'group.admin']) c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
--- a/rhodecode/lib/auth.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/lib/auth.py Mon Apr 08 22:47:35 2013 +0200 @@ -42,7 +42,8 @@ from rhodecode.lib.utils2 import str2bool, safe_unicode from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError,\ LdapImportError -from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug +from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug,\ + get_user_group_slug from rhodecode.lib.auth_ldap import AuthLdap from rhodecode.model import meta @@ -410,7 +411,7 @@ if x[1] == 'repository.admin'] @property - def groups_admin(self): + def repository_groups_admin(self): """ Returns list of repository groups you're an admin of """ @@ -418,6 +419,14 @@ if x[1] == 'group.admin'] @property + def user_groups_admin(self): + """ + Returns list of user groups you're an admin of + """ + return [x[0] for x in self.permissions['user_groups'].iteritems() + if x[1] == 'usergroup.admin'] + + @property def ip_allowed(self): """ Checks if ip_addr used in constructor is allowed from defined list of @@ -693,7 +702,7 @@ class HasReposGroupPermissionAllDecorator(PermsDecorator): """ Checks for access permission for all given predicates for specific - repository. All of them have to be meet in order to fulfill the request + repository group. All of them have to be meet in order to fulfill the request """ def check_permissions(self): @@ -711,7 +720,7 @@ class HasReposGroupPermissionAnyDecorator(PermsDecorator): """ Checks for access permission for any of given predicates for specific - repository. In order to fulfill the request any of predicates must be meet + repository group. In order to fulfill the request any of predicates must be meet """ def check_permissions(self): @@ -726,6 +735,42 @@ return False +class HasUserGroupPermissionAllDecorator(PermsDecorator): + """ + Checks for access permission for all given predicates for specific + user group. All of them have to be meet in order to fulfill the request + """ + + def check_permissions(self): + group_name = get_user_group_slug(request) + try: + user_perms = set([self.user_perms['user_groups'][group_name]]) + except KeyError: + return False + + if self.required_perms.issubset(user_perms): + return True + return False + + +class HasUserGroupPermissionAnyDecorator(PermsDecorator): + """ + Checks for access permission for any of given predicates for specific + user group. In order to fulfill the request any of predicates must be meet + """ + + def check_permissions(self): + group_name = get_user_group_slug(request) + try: + user_perms = set([self.user_perms['user_groups'][group_name]]) + except KeyError: + return False + + if self.required_perms.intersection(user_perms): + return True + return False + + #============================================================================== # CHECK FUNCTIONS #============================================================================== @@ -865,6 +910,39 @@ return False +class HasUserGroupPermissionAny(PermsFunction): + def __call__(self, user_group_name=None, check_location=''): + self.user_group_name = user_group_name + return super(HasUserGroupPermissionAny, self).__call__(check_location) + + def check_permissions(self): + try: + self._user_perms = set( + [self.user_perms['user_groups'][self.user_group_name]] + ) + except KeyError: + return False + if self.required_perms.intersection(self._user_perms): + return True + return False + + +class HasUserGroupPermissionAll(PermsFunction): + def __call__(self, user_group_name=None, check_location=''): + self.user_group_name = user_group_name + return super(HasUserGroupPermissionAll, self).__call__(check_location) + + def check_permissions(self): + try: + self._user_perms = set( + [self.user_perms['user_groups'][self.user_group_name]] + ) + except KeyError: + return False + if self.required_perms.issubset(self._user_perms): + return True + return False + #============================================================================== # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH #==============================================================================
--- a/rhodecode/lib/db_manage.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/lib/db_manage.py Mon Apr 08 22:47:35 2013 +0200 @@ -89,7 +89,7 @@ else: destroy = ask_ok('Are you sure to destroy old database ? [y/n]') if not destroy: - sys.exit('Nothing done') + sys.exit('Nothing tables created') if destroy: Base.metadata.drop_all() @@ -127,7 +127,7 @@ 'sure You backed up your database before. ' 'Continue ? [y/n]') if not upgrade: - sys.exit('Nothing done') + sys.exit('No upgrade performed') repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))), 'rhodecode/lib/dbmigrate') @@ -292,6 +292,10 @@ def step_11(self): self.klass.update_repo_info() + def step_12(self): + self.klass.create_permissions() + self.klass.populate_default_permissions() + upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1) # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE @@ -528,7 +532,8 @@ if default is None: log.debug('missing default permission for group %s adding' % g) - ReposGroupModel()._create_default_perms(g) + perm_obj = ReposGroupModel()._create_default_perms(g) + self.sa.add(perm_obj) def reset_permissions(self, username): """
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rhodecode/lib/dbmigrate/versions/012_version_1_7_0.py Mon Apr 08 22:47:35 2013 +0200 @@ -0,0 +1,62 @@ +import logging +import datetime + +from sqlalchemy import * +from sqlalchemy.exc import DatabaseError +from sqlalchemy.orm import relation, backref, class_mapper, joinedload +from sqlalchemy.orm.session import Session +from sqlalchemy.ext.declarative import declarative_base + +from rhodecode.lib.dbmigrate.migrate import * +from rhodecode.lib.dbmigrate.migrate.changeset import * + +from rhodecode.model.meta import Base +from rhodecode.model import meta +from rhodecode.lib.dbmigrate.versions import _reset_base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + + #========================================================================== + # UserUserGroupToPerm + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_7_0 import UserUserGroupToPerm + tbl = UserUserGroupToPerm.__table__ + tbl.create() + + #========================================================================== + # UserGroupUserGroupToPerm + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_7_0 import UserGroupUserGroupToPerm + tbl = UserGroupUserGroupToPerm.__table__ + tbl.create() + + #========================================================================== + # UserGroup + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_7_0 import UserGroup + tbl = UserGroup.__table__ + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=False, default=None) + # create username column + user_id.create(table=tbl) + + #========================================================================== + # UserGroup + #========================================================================== + from rhodecode.lib.dbmigrate.schema.db_1_7_0 import RepoGroup + tbl = RepoGroup.__table__ + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=False, default=None) + # create username column + user_id.create(table=tbl) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine
--- a/rhodecode/lib/utils.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/lib/utils.py Mon Apr 08 22:47:35 2013 +0200 @@ -53,7 +53,7 @@ from rhodecode.model import meta from rhodecode.model.db import Repository, User, RhodeCodeUi, \ - UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation + UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation, UserGroup from rhodecode.model.meta import Session from rhodecode.model.repos_group import ReposGroupModel from rhodecode.lib.utils2 import safe_str, safe_unicode @@ -114,6 +114,14 @@ return _group +def get_user_group_slug(request): + _group = request.environ['pylons.routes_dict'].get('id') + _group = UserGroup.get(_group) + if _group: + _group = _group.users_group_name + return _group + + def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): """ Action logger for various actions made by users @@ -372,6 +380,7 @@ # last element is repo in nested groups structure groups = groups[:-1] rgm = ReposGroupModel(sa) + owner = User.get_first_admin() for lvl, group_name in enumerate(groups): group_name = '/'.join(groups[:lvl] + [group_name]) group = RepoGroup.get_by_group_name(group_name) @@ -382,13 +391,16 @@ break if group is None: - log.debug('creating group level: %s group_name: %s' % (lvl, - group_name)) + log.debug('creating group level: %s group_name: %s' + % (lvl, group_name)) group = RepoGroup(group_name, parent) group.group_description = desc + group.user = owner sa.add(group) - rgm._create_default_perms(group) + perm_obj = rgm._create_default_perms(group) + sa.add(perm_obj) sa.flush() + parent = group return group @@ -409,9 +421,7 @@ from rhodecode.model.scm import ScmModel sa = meta.Session() rm = RepoModel() - user = sa.query(User).filter(User.admin == True).first() - if user is None: - raise Exception('Missing administrative account!') + user = User.get_first_admin() added = [] ##creation defaults
--- a/rhodecode/model/db.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/model/db.py Mon Apr 08 22:47:35 2013 +0200 @@ -131,6 +131,11 @@ @classmethod def getAll(cls): + # deprecated and left for backward compatibility + return cls.get_all() + + @classmethod + def get_all(cls): return cls.query().all() @classmethod @@ -490,6 +495,13 @@ Session().add(self) log.debug('updated user %s lastlogin' % self.username) + @classmethod + def get_first_admin(cls): + user = User.query().filter(User.admin == True).first() + if user is None: + raise Exception('Missing administrative account!') + return user + def get_api_data(self): """ Common function for generating user related data for API @@ -616,13 +628,18 @@ users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined") users_group_to_perm = relationship('UserGroupToPerm', cascade='all') users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all') + user_user_group_to_perm = relationship('UserUserGroupToPerm ', cascade='all') + user = relationship('User') def __unicode__(self): - return u'<userGroup(%s)>' % (self.users_group_name) + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, + self.users_group_id, + self.users_group_name) @classmethod def get_by_group_name(cls, group_name, cache=False, @@ -1229,19 +1246,20 @@ group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') - parent_group = relationship('RepoGroup', remote_side=group_id) + user = relationship('User') def __init__(self, group_name='', parent_group=None): self.group_name = group_name self.parent_group = parent_group def __unicode__(self): - return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id, - self.group_name) + return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id, + self.group_name) @classmethod def groups_choices(cls, groups=None, show_empty_group=True): @@ -1397,6 +1415,11 @@ ('group.write', _('Repository group write access')), ('group.admin', _('Repository group admin access')), + ('usergroup.none', _('User group no access')), + ('usergroup.read', _('User group read access')), + ('usergroup.write', _('User group write access')), + ('usergroup.admin', _('User group admin access')), + ('hg.admin', _('RhodeCode Administrator')), ('hg.create.none', _('Repository creation disabled')), ('hg.create.repository', _('Repository creation enabled')), @@ -1422,10 +1445,15 @@ 'group.write': 3, 'group.admin': 4, + 'usergroup.none': 0, + 'usergroup.read': 1, + 'usergroup.write': 3, + 'usergroup.admin': 4, + 'hg.fork.none': 0, 'hg.fork.repository': 1, 'hg.create.none': 0, - 'hg.create.repository':1 + 'hg.create.repository': 1 } permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) @@ -1459,6 +1487,15 @@ return q.all() + @classmethod + def get_default_user_group_perms(cls, default_user_id): + q = Session().query(UserUserGroupToPerm, UserGroup, cls)\ + .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\ + .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\ + .filter(UserUserGroupToPerm.user_id == default_user_id) + + return q.all() + class UserRepoToPerm(Base, BaseModel): __tablename__ = 'repo_to_perm' @@ -1486,7 +1523,36 @@ return n def __unicode__(self): - return u'<user:%s => %s >' % (self.user, self.repository) + return u'<%s => %s >' % (self.user, self.repository) + + +class UserUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + user = relationship('User') + user_group = relationship('UserGroup') + permission = relationship('Permission') + + @classmethod + def create(cls, user, user_group, permission): + n = cls() + n.user = user + n.user_group = user_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<%s => %s >' % (self.user, self.user_group) class UserToPerm(Base, BaseModel): @@ -1533,6 +1599,36 @@ return u'<userGroup:%s => %s >' % (self.users_group, self.repository) +#TODO; not sure if this will be ever used +class UserGroupUserGroupToPerm(Base, BaseModel): + __tablename__ = 'user_group_user_group_to_perm' + __table_args__ = ( + UniqueConstraint('user_group_id', 'user_group_id', 'permission_id'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) + target_user_group_id = Column("target_users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) + user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) + + target_user_group = relationship('UserGroup', remote_side=target_user_group_id, primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id') + user_group = relationship('UserGroup', remote_side=user_group_id, primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id') + permission = relationship('Permission') + + @classmethod + def create(cls, target_user_group, user_group, permission): + n = cls() + n.target_user_group = target_user_group + n.user_group = user_group + n.permission = permission + Session().add(n) + return n + + def __unicode__(self): + return u'<UserGroup:%s => %s >' % (self.target_user_group, self.user_group) + + class UserGroupToPerm(Base, BaseModel): __tablename__ = 'users_group_to_perm' __table_args__ = (
--- a/rhodecode/model/forms.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/model/forms.py Mon Apr 08 22:47:35 2013 +0200 @@ -134,9 +134,7 @@ testValueList=True, if_missing=None, not_empty=True)) enable_locking = v.StringBoolean(if_missing=False) - recursive = v.StringBoolean(if_missing=False) - chained_validators = [v.ValidReposGroup(edit, old_data), - v.ValidPerms('group')] + chained_validators = [v.ValidReposGroup(edit, old_data)] return _ReposGroupForm @@ -207,10 +205,27 @@ class _RepoPermsForm(formencode.Schema): allow_extra_fields = True filter_extra_fields = False - chained_validators = [v.ValidPerms()] + chained_validators = [v.ValidPerms(type_='repo')] return _RepoPermsForm +def RepoGroupPermsForm(): + class _RepoGroupPermsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + recursive = v.StringBoolean(if_missing=False) + chained_validators = [v.ValidPerms(type_='repo_group')] + return _RepoGroupPermsForm + + +def UserGroupPermsForm(): + class _UserPermsForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + chained_validators = [v.ValidPerms(type_='user_group')] + return _UserPermsForm + + def RepoFieldForm(): class _RepoFieldForm(formencode.Schema): filter_extra_fields = True
--- a/rhodecode/model/repo.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/model/repo.py Mon Apr 08 22:47:35 2013 +0200 @@ -52,14 +52,33 @@ cls = Repository URL_SEPARATOR = Repository.url_sep() - def __get_users_group(self, users_group): + def _get_user_group(self, users_group): return self._get_instance(UserGroup, users_group, callback=UserGroup.get_by_group_name) - def _get_repos_group(self, repos_group): + def _get_repo_group(self, repos_group): return self._get_instance(RepoGroup, repos_group, callback=RepoGroup.get_by_group_name) + def _create_default_perms(self, repository, private): + # create default permission + default = 'repository.read' + def_user = User.get_by_username('default') + for p in def_user.user_perms: + if p.permission.permission_name.startswith('repository.'): + default = p.permission.permission_name + break + + default_perm = 'repository.none' if private else default + + repo_to_perm = UserRepoToPerm() + repo_to_perm.permission = Permission.get_by_key(default_perm) + + repo_to_perm.repository = repository + repo_to_perm.user_id = def_user.user_id + + return repo_to_perm + @LazyProperty def repos_path(self): """ @@ -336,7 +355,7 @@ owner = self._get_user(owner) fork_of = self._get_repo(fork_of) - repos_group = self._get_repos_group(repos_group) + repos_group = self._get_repo_group(repos_group) try: # repo name is just a name of repository @@ -369,26 +388,6 @@ self.sa.add(new_repo) - def _create_default_perms(): - # create default permission - repo_to_perm = UserRepoToPerm() - default = 'repository.read' - for p in User.get_by_username('default').user_perms: - if p.permission.permission_name.startswith('repository.'): - default = p.permission.permission_name - break - - default_perm = 'repository.none' if private else default - - repo_to_perm.permission_id = self.sa.query(Permission)\ - .filter(Permission.permission_name == default_perm)\ - .one().permission_id - - repo_to_perm.repository = new_repo - repo_to_perm.user_id = User.get_by_username('default').user_id - - self.sa.add(repo_to_perm) - if fork_of: if copy_fork_permissions: repo = fork_of @@ -405,9 +404,11 @@ UserGroupRepoToPerm.create(perm.users_group, new_repo, perm.permission) else: - _create_default_perms() + perm_obj = self._create_default_perms(new_repo, private) + self.sa.add(perm_obj) else: - _create_default_perms() + perm_obj = self._create_default_perms(new_repo, private) + self.sa.add(perm_obj) if not just_db: self.__create_repo(repo_name, repo_type, @@ -456,6 +457,35 @@ enable_statistics, enable_locking, enable_downloads ) + def _update_permissions(self, repo, perms_new=None, + perms_updates=None): + if not perms_new: + perms_new = [] + if not perms_updates: + perms_updates = [] + + # update permissions + for member, perm, member_type in perms_updates: + if member_type == 'user': + # this updates existing one + self.grant_user_permission( + repo=repo, user=member, perm=perm + ) + else: + self.grant_users_group_permission( + repo=repo, group_name=member, perm=perm + ) + # set new permissions + for member, perm, member_type in perms_new: + if member_type == 'user': + self.grant_user_permission( + repo=repo, user=member, perm=perm + ) + else: + self.grant_users_group_permission( + repo=repo, group_name=member, perm=perm + ) + def create_fork(self, form_data, cur_user): """ Simple wrapper into executing celery task for fork creation @@ -559,7 +589,7 @@ :param perm: Instance of Permission, or permission_name """ repo = self._get_repo(repo) - group_name = self.__get_users_group(group_name) + group_name = self._get_user_group(group_name) permission = self._get_perm(perm) # check if we have that permission already @@ -587,7 +617,7 @@ or user group name """ repo = self._get_repo(repo) - group_name = self.__get_users_group(group_name) + group_name = self._get_user_group(group_name) obj = self.sa.query(UserGroupRepoToPerm)\ .filter(UserGroupRepoToPerm.repository == repo)\
--- a/rhodecode/model/repos_group.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/model/repos_group.py Mon Apr 08 22:47:35 2013 +0200 @@ -42,11 +42,11 @@ cls = RepoGroup - def __get_users_group(self, users_group): + def _get_user_group(self, users_group): return self._get_instance(UserGroup, users_group, callback=UserGroup.get_by_group_name) - def _get_repos_group(self, repos_group): + def _get_repo_group(self, repos_group): return self._get_instance(RepoGroup, repos_group, callback=RepoGroup.get_by_group_name) @@ -61,21 +61,19 @@ def _create_default_perms(self, new_group): # create default permission - repo_group_to_perm = UserRepoGroupToPerm() default_perm = 'group.read' - for p in User.get_by_username('default').user_perms: + def_user = User.get_by_username('default') + for p in def_user.user_perms: if p.permission.permission_name.startswith('group.'): default_perm = p.permission.permission_name break - repo_group_to_perm.permission_id = self.sa.query(Permission)\ - .filter(Permission.permission_name == default_perm)\ - .one().permission_id + repo_group_to_perm = UserRepoGroupToPerm() + repo_group_to_perm.permission = Permission.get_by_key(default_perm) repo_group_to_perm.group = new_group - repo_group_to_perm.user_id = User.get_by_username('default').user_id - - self.sa.add(repo_group_to_perm) + repo_group_to_perm.user_id = def_user.user_id + return repo_group_to_perm def __create_group(self, group_name): """ @@ -143,12 +141,14 @@ def create(self, group_name, group_description, owner, parent=None, just_db=False): try: new_repos_group = RepoGroup() + new_repos_group.user = self._get_user(owner) new_repos_group.group_description = group_description or group_name - new_repos_group.parent_group = self._get_repos_group(parent) + new_repos_group.parent_group = self._get_repo_group(parent) new_repos_group.group_name = new_repos_group.get_new_name(group_name) self.sa.add(new_repos_group) - self._create_default_perms(new_repos_group) + perm_obj = self._create_default_perms(new_repos_group) + self.sa.add(perm_obj) #create an ADMIN permission for owner, later owner should go into #the owner field of groups @@ -176,7 +176,7 @@ def _set_perm_user(obj, user, perm): if isinstance(obj, RepoGroup): - ReposGroupModel().grant_user_permission( + self.grant_user_permission( repos_group=obj, user=user, perm=perm ) elif isinstance(obj, Repository): @@ -193,7 +193,7 @@ def _set_perm_group(obj, users_group, perm): if isinstance(obj, RepoGroup): - ReposGroupModel().grant_users_group_permission( + self.grant_users_group_permission( repos_group=obj, group_name=users_group, perm=perm ) elif isinstance(obj, Repository): @@ -237,14 +237,7 @@ def update(self, repos_group, form_data): try: - repos_group = self._get_repos_group(repos_group) - recursive = form_data['recursive'] - # iterate over all members(if in recursive mode) of this groups and - # set the permissions ! - # this can be potentially heavy operation - self._update_permissions(repos_group, form_data['perms_new'], - form_data['perms_updates'], recursive) - + repos_group = self._get_repo_group(repos_group) old_path = repos_group.full_path # change properties @@ -288,7 +281,7 @@ raise def delete(self, repos_group, force_delete=False): - repos_group = self._get_repos_group(repos_group) + repos_group = self._get_repo_group(repos_group) try: self.sa.delete(repos_group) self.__delete_group(repos_group, force_delete) @@ -307,7 +300,7 @@ :param recursive: recurse to all children of group """ from rhodecode.model.repo import RepoModel - repos_group = self._get_repos_group(repos_group) + repos_group = self._get_repo_group(repos_group) for el in repos_group.recursive_groups_and_repos(): if not recursive: @@ -346,7 +339,7 @@ :param perm: Instance of Permission, or permission_name """ - repos_group = self._get_repos_group(repos_group) + repos_group = self._get_repo_group(repos_group) user = self._get_user(user) permission = self._get_perm(perm) @@ -373,7 +366,7 @@ :param user: Instance of User, user_id or username """ - repos_group = self._get_repos_group(repos_group) + repos_group = self._get_repo_group(repos_group) user = self._get_user(user) obj = self.sa.query(UserRepoGroupToPerm)\ @@ -395,8 +388,8 @@ or user group name :param perm: Instance of Permission, or permission_name """ - repos_group = self._get_repos_group(repos_group) - group_name = self.__get_users_group(group_name) + repos_group = self._get_repo_group(repos_group) + group_name = self._get_user_group(group_name) permission = self._get_perm(perm) # check if we have that permission already @@ -424,8 +417,8 @@ :param group_name: Instance of UserGroup, users_group_id, or user group name """ - repos_group = self._get_repos_group(repos_group) - group_name = self.__get_users_group(group_name) + repos_group = self._get_repo_group(repos_group) + group_name = self._get_user_group(group_name) obj = self.sa.query(UserGroupRepoGroupToPerm)\ .filter(UserGroupRepoGroupToPerm.group == repos_group)\
--- a/rhodecode/model/scm.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/model/scm.py Mon Apr 08 22:47:35 2013 +0200 @@ -46,7 +46,8 @@ from rhodecode.lib import helpers as h from rhodecode.lib.utils2 import safe_str, safe_unicode, get_server_url,\ _set_extras -from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny +from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny,\ + HasUserGroupPermissionAnyDecorator, HasUserGroupPermissionAny from rhodecode.lib.utils import get_filesystem_repos, make_ui, \ action_logger, REMOVED_REPO_PAT from rhodecode.model import BaseModel @@ -165,36 +166,58 @@ yield tmp_d -class GroupList(object): - - def __init__(self, db_repo_group_list, perm_set=None): +class _PermCheckIterator(object): + def __init__(self, obj_list, obj_attr, perm_set, perm_checker): """ - Creates iterator from given list of group objects, additionally + Creates iterator from given list of objects, additionally checking permission for them from perm_set var - :param db_repo_group_list: - :param perm_set: list of permissons to check + :param obj_list: list of db objects + :param obj_attr: attribute of object to pass into perm_checker + :param perm_set: list of permissions to check + :param perm_checker: callable to check permissions against """ - self.db_repo_group_list = db_repo_group_list - if not perm_set: - perm_set = ['group.read', 'group.write', 'group.admin'] + self.obj_list = obj_list + self.obj_attr = obj_attr self.perm_set = perm_set + self.perm_checker = perm_checker def __len__(self): - return len(self.db_repo_group_list) + return len(self.obj_list) def __repr__(self): return '<%s (%s)>' % (self.__class__.__name__, self.__len__()) def __iter__(self): - for dbgr in self.db_repo_group_list: + for db_obj in self.obj_list: # check permission at this level - if not HasReposGroupPermissionAny( - *self.perm_set - )(dbgr.group_name, 'get group repo check'): + name = getattr(db_obj, self.obj_attr, None) + if not self.perm_checker(*self.perm_set)(name, self.__class__.__name__): continue - yield dbgr + yield db_obj + + +class RepoGroupList(_PermCheckIterator): + + def __init__(self, db_repo_group_list, perm_set=None): + if not perm_set: + perm_set = ['group.read', 'group.write', 'group.admin'] + + super(RepoGroupList, self).__init__(obj_list=db_repo_group_list, + obj_attr='group_name', perm_set=perm_set, + perm_checker=HasReposGroupPermissionAny) + + +class UserGroupList(_PermCheckIterator): + + def __init__(self, db_user_group_list, perm_set=None): + if not perm_set: + perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin'] + + super(UserGroupList, self).__init__(obj_list=db_user_group_list, + obj_attr='users_group_name', perm_set=perm_set, + perm_checker=HasUserGroupPermissionAny) class ScmModel(BaseModel): @@ -293,7 +316,7 @@ if all_groups is None: all_groups = RepoGroup.query()\ .filter(RepoGroup.group_parent_id == None).all() - return [x for x in GroupList(all_groups)] + return [x for x in RepoGroupList(all_groups)] def mark_for_invalidation(self, repo_name): """
--- a/rhodecode/model/user.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/model/user.py Mon Apr 08 22:47:35 2013 +0200 @@ -425,9 +425,11 @@ """ RK = 'repositories' GK = 'repositories_groups' + UK = 'user_groups' GLOBAL = 'global' user.permissions[RK] = {} user.permissions[GK] = {} + user.permissions[UK] = {} user.permissions[GLOBAL] = set() def _choose_perm(new_perm, cur_perm): @@ -450,6 +452,7 @@ default_repo_perms = Permission.get_default_perms(default_user_id) default_repo_groups_perms = Permission.get_default_group_perms(default_user_id) + default_user_group_perms = Permission.get_default_user_group_perms(default_user_id) if user.is_admin: #================================================================== @@ -469,6 +472,12 @@ rg_k = perm.UserRepoGroupToPerm.group.group_name p = 'group.admin' user.permissions[GK][rg_k] = p + + # user groups + for perm in default_user_group_perms: + u_k = perm.UserUserGroupToPerm.user_group.users_group_name + p = 'usergroup.admin' + user.permissions[UK][u_k] = p return user #================================================================== @@ -504,6 +513,13 @@ p = perm.Permission.permission_name user.permissions[GK][rg_k] = p + # defaults for user groups taken from default user permission + # on given user group + for perm in default_user_group_perms: + u_k = perm.UserUserGroupToPerm.user_group.users_group_name + p = perm.Permission.permission_name + user.permissions[UK][u_k] = p + #====================================================================== # !! OVERRIDE GLOBALS !! with user permissions if any found #====================================================================== @@ -588,15 +604,7 @@ # user explicit permissions for repositories, overrides any specified # by the group permission - user_repo_perms = \ - self.sa.query(UserRepoToPerm, Permission, Repository)\ - .join((Repository, UserRepoToPerm.repository_id == - Repository.repo_id))\ - .join((Permission, UserRepoToPerm.permission_id == - Permission.permission_id))\ - .filter(UserRepoToPerm.user_id == uid)\ - .all() - + user_repo_perms = Permission.get_default_perms(uid) for perm in user_repo_perms: r_k = perm.UserRepoToPerm.repository.repo_name cur_perm = user.permissions[RK][r_k] @@ -639,14 +647,7 @@ user.permissions[GK][g_k] = p # user explicit permissions for repository groups - user_repo_groups_perms = \ - self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\ - .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\ - .join((Permission, UserRepoGroupToPerm.permission_id - == Permission.permission_id))\ - .filter(UserRepoGroupToPerm.user_id == uid)\ - .all() - + user_repo_groups_perms = Permission.get_default_group_perms(uid) for perm in user_repo_groups_perms: rg_k = perm.UserRepoGroupToPerm.group.group_name p = perm.Permission.permission_name @@ -655,6 +656,19 @@ p = _choose_perm(p, cur_perm) user.permissions[GK][rg_k] = p + #====================================================================== + # !! PERMISSIONS FOR USER GROUPS !! + #====================================================================== + #user explicit permission for user groups + user_user_groups_perms = Permission.get_default_user_group_perms(uid) + for perm in user_user_groups_perms: + u_k = perm.UserUserGroupToPerm.user_group.users_group_name + p = perm.Permission.permission_name + cur_perm = user.permissions[UK][u_k] + if not explicit: + p = _choose_perm(p, cur_perm) + user.permissions[UK][u_k] = p + return user def has_perm(self, user, perm):
--- a/rhodecode/model/users_group.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/model/users_group.py Mon Apr 08 22:47:35 2013 +0200 @@ -29,7 +29,7 @@ from rhodecode.model import BaseModel from rhodecode.model.db import UserGroupMember, UserGroup,\ - UserGroupRepoToPerm, Permission, UserGroupToPerm, User + UserGroupRepoToPerm, Permission, UserGroupToPerm, User, UserUserGroupToPerm from rhodecode.lib.exceptions import UserGroupsAssignedException log = logging.getLogger(__name__) @@ -39,26 +39,74 @@ cls = UserGroup - def __get_users_group(self, users_group): + def _get_user_group(self, users_group): return self._get_instance(UserGroup, users_group, callback=UserGroup.get_by_group_name) + def _create_default_perms(self, user_group): + # create default permission + default_perm = 'usergroup.read' + def_user = User.get_by_username('default') + for p in def_user.user_perms: + if p.permission.permission_name.startswith('usergroup.'): + default_perm = p.permission.permission_name + break + + user_group_to_perm = UserUserGroupToPerm() + user_group_to_perm.permission = Permission.get_by_key(default_perm) + + user_group_to_perm.user_group = user_group + user_group_to_perm.user_id = def_user.user_id + return user_group_to_perm + + def _update_permissions(self, user_group, perms_new=None, + perms_updates=None): + if not perms_new: + perms_new = [] + if not perms_updates: + perms_updates = [] + + # update permissions + for member, perm, member_type in perms_updates: + if member_type == 'user': + # this updates existing one + self.grant_user_permission( + user_group=user_group, user=member, perm=perm + ) + else: + self.grant_users_group_permission( + user_group=user_group, group_name=member, perm=perm + ) + # set new permissions + for member, perm, member_type in perms_new: + if member_type == 'user': + self.grant_user_permission( + user_group=user_group, user=member, perm=perm + ) + else: + self.grant_users_group_permission( + user_group=user_group, group_name=member, perm=perm + ) + def get(self, users_group_id, cache=False): return UserGroup.get(users_group_id) def get_group(self, users_group): - return self.__get_users_group(users_group) + return self._get_user_group(users_group) def get_by_name(self, name, cache=False, case_insensitive=False): return UserGroup.get_by_group_name(name, cache, case_insensitive) - def create(self, name, active=True): + def create(self, name, owner, active=True): try: - new = UserGroup() - new.users_group_name = name - new.users_group_active = active - self.sa.add(new) - return new + new_user_group = UserGroup() + new_user_group.user = self._get_user(owner) + new_user_group.users_group_name = name + new_user_group.users_group_active = active + self.sa.add(new_user_group) + perm_obj = self._create_default_perms(new_user_group) + self.sa.add(perm_obj) + return new_user_group except Exception: log.error(traceback.format_exc()) raise @@ -66,7 +114,7 @@ def update(self, users_group, form_data): try: - users_group = self.__get_users_group(users_group) + users_group = self._get_user_group(users_group) for k, v in form_data.items(): if k == 'users_group_members': @@ -96,7 +144,7 @@ :param force: """ try: - users_group = self.__get_users_group(users_group) + users_group = self._get_user_group(users_group) # check if this group is not assigned to repo assigned_groups = UserGroupRepoToPerm.query()\ @@ -112,7 +160,7 @@ raise def add_user_to_group(self, users_group, user): - users_group = self.__get_users_group(users_group) + users_group = self._get_user_group(users_group) user = self._get_user(user) for m in users_group.members: @@ -135,7 +183,7 @@ raise def remove_user_from_group(self, users_group, user): - users_group = self.__get_users_group(users_group) + users_group = self._get_user_group(users_group) user = self._get_user(user) users_group_member = None @@ -157,7 +205,7 @@ return False def has_perm(self, users_group, perm): - users_group = self.__get_users_group(users_group) + users_group = self._get_user_group(users_group) perm = self._get_perm(perm) return UserGroupToPerm.query()\ @@ -165,7 +213,7 @@ .filter(UserGroupToPerm.permission == perm).scalar() is not None def grant_perm(self, users_group, perm): - users_group = self.__get_users_group(users_group) + users_group = self._get_user_group(users_group) perm = self._get_perm(perm) # if this permission is already granted skip it @@ -182,7 +230,7 @@ self.sa.add(new) def revoke_perm(self, users_group, perm): - users_group = self.__get_users_group(users_group) + users_group = self._get_user_group(users_group) perm = self._get_perm(perm) obj = UserGroupToPerm.query()\ @@ -190,3 +238,58 @@ .filter(UserGroupToPerm.permission == perm).scalar() if obj: self.sa.delete(obj) + + def grant_user_permission(self, user_group, user, perm): + """ + Grant permission for user on given user group, or update + existing one if found + + :param user_group: Instance of UserGroup, users_group_id, + or users_group_name + :param user: Instance of User, user_id or username + :param perm: Instance of Permission, or permission_name + """ + + user_group = self._get_user_group(user_group) + user = self._get_user(user) + permission = self._get_perm(perm) + + # check if we have that permission already + obj = self.sa.query(UserUserGroupToPerm)\ + .filter(UserUserGroupToPerm.user == user)\ + .filter(UserUserGroupToPerm.user_group == user_group)\ + .scalar() + if obj is None: + # create new ! + obj = UserUserGroupToPerm() + obj.user_group = user_group + obj.user = user + obj.permission = permission + self.sa.add(obj) + log.debug('Granted perm %s to %s on %s' % (perm, user, user_group)) + + def revoke_user_permission(self, user_group, user): + """ + Revoke permission for user on given repository group + + :param user_group: Instance of ReposGroup, repositories_group_id, + or repositories_group name + :param user: Instance of User, user_id or username + """ + + user_group = self._get_user_group(user_group) + user = self._get_user(user) + + obj = self.sa.query(UserUserGroupToPerm)\ + .filter(UserUserGroupToPerm.user == user)\ + .filter(UserUserGroupToPerm.user_group == user_group)\ + .scalar() + if obj: + self.sa.delete(obj) + log.debug('Revoked perm on %s on %s' % (user_group, user)) + + def grant_users_group_permission(self, user_group, group_name, perm): + raise NotImplementedError() + + def revoke_users_group_permission(self, user_group, group_name): + raise NotImplementedError()
--- a/rhodecode/model/validators.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/model/validators.py Mon Apr 08 22:47:35 2013 +0200 @@ -546,10 +546,12 @@ def ValidPerms(type_='repo'): - if type_ == 'group': + if type_ == 'repo_group': EMPTY_PERM = 'group.none' elif type_ == 'repo': EMPTY_PERM = 'repository.none' + elif type_ == 'user_group': + EMPTY_PERM = 'usergroup.none' class _validator(formencode.validators.FancyValidator): messages = {
--- a/rhodecode/templates/admin/repos/repo_edit_perms.html Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/templates/admin/repos/repo_edit_perms.html Mon Apr 08 22:47:35 2013 +0200 @@ -29,7 +29,7 @@ </td> <td> %if r2p.user.username !='default': - <span class="delete_icon action_button" onclick="ajaxActionUser(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')"> + <span class="delete_icon action_button" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}')"> ${_('revoke')} </span> %endif @@ -54,7 +54,7 @@ %endif </td> <td> - <span class="delete_icon action_button" onclick="ajaxActionUserGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')"> + <span class="delete_icon action_button" onclick="ajaxActionRevoke(${g2p.users_group.users_group_id}, 'user_group', '${'id%s'%id(g2p.users_group.users_group_name)}')"> ${_('revoke')} </span> </td> @@ -86,35 +86,29 @@ </tr> </table> <script type="text/javascript"> -function ajaxActionUser(user_id, field_id) { - var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}"; +function ajaxActionRevoke(obj_id, obj_type, field_id) { var callback = { success: function (o) { var tr = YUD.get(String(field_id)); tr.parentNode.removeChild(tr); }, failure: function (o) { - alert("${_('Failed to remove user')}"); + alert(_TM['Failed to remoke permission'] + ": " + o.status); }, }; - var postData = '_method=delete&user_id=' + user_id; + if (obj_type=='user'){ + var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}"; + var postData = '_method=delete&user_id={0}&obj_type=user'.format(obj_id); + } + else if (obj_type=='user_group'){ + var sUrl = "${h.url('delete_repo_users_group',repo_name=c.repo_name)}"; + var postData = '_method=delete&users_group_id={0}&obj_type=user_group'.format(obj_id); + + } + var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); }; -function ajaxActionUserGroup(users_group_id,field_id){ - var sUrl = "${h.url('delete_repo_users_group',repo_name=c.repo_name)}"; - var callback = { - success:function(o){ - var tr = YUD.get(String(field_id)); - tr.parentNode.removeChild(tr); - }, - failure:function(o){ - alert("${_('Failed to remove user group')}"); - }, - }; - var postData = '_method=delete&users_group_id='+users_group_id; - var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); -}; YUE.onDOMReady(function () { if (!YUD.hasClass('perm_new_member_name', 'error')) {
--- a/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html Mon Apr 08 22:47:35 2013 +0200 @@ -21,7 +21,7 @@ </td> <td> %if r2p.user.username !='default': - <span class="delete_icon action_button" onclick="ajaxActionUser(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')"> + <span class="delete_icon action_button" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}')"> ${_('revoke')} </span> %endif @@ -51,7 +51,7 @@ <img class="perm-gravatar" src="${h.url('/images/icons/group.png')}"/>${g2p.users_group.users_group_name} </td> <td> - <span class="delete_icon action_button" onclick="ajaxActionUserGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')"> + <span class="delete_icon action_button" onclick="ajaxActionRevoke(${g2p.users_group.users_group_id}, 'user_group', '${'id%s'%id(g2p.users_group.users_group_name)}')"> ${_('revoke')} </span> </td> @@ -89,37 +89,29 @@ </tr> </table> <script type="text/javascript"> -function ajaxActionUser(user_id, field_id) { - var sUrl = "${h.url('delete_repos_group_user_perm',group_name=c.repos_group.group_name)}"; +function ajaxActionRevoke(obj_id, obj_type, field_id) { var callback = { success: function (o) { var tr = YUD.get(String(field_id)); tr.parentNode.removeChild(tr); }, failure: function (o) { - alert("${_('Failed to remove user')}"); + alert(_TM['Failed to remoke permission'] + ": " + o.status); }, }; var recursive = YUD.get('recursive').checked; - var postData = '_method=delete&recursive={0}&user_id={1}'.format(recursive,user_id); + + if (obj_type=='user'){ + var sUrl = "${h.url('delete_repos_group_user_perm',group_name=c.repos_group.group_name)}"; + var postData = '_method=delete&recursive={0}&user_id={1}&obj_type=user'.format(recursive,obj_id); + } + else if (obj_type=='user_group'){ + var sUrl = "${h.url('delete_repos_group_users_group_perm',group_name=c.repos_group.group_name)}"; + var postData = '_method=delete&recursive={0}&users_group_id={0}&obj_type=user_group'.format(recursive,obj_id); + } var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); }; -function ajaxActionUserGroup(users_group_id,field_id){ - var sUrl = "${h.url('delete_repos_group_users_group_perm',group_name=c.repos_group.group_name)}"; - var callback = { - success:function(o){ - var tr = YUD.get(String(field_id)); - tr.parentNode.removeChild(tr); - }, - failure:function(o){ - alert("${_('Failed to remove user group')}"); - }, - }; - var recursive = YUD.get('recursive').checked; - var postData = '_method=delete&recursive={0}&users_group_id={1}'.format(recursive,users_group_id); - var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); -}; YUE.onDOMReady(function () { if (!YUD.hasClass('perm_new_member_name', 'error')) {
--- a/rhodecode/templates/admin/repos_groups/repos_groups_edit.html Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/templates/admin/repos_groups/repos_groups_edit.html Mon Apr 08 22:47:35 2013 +0200 @@ -18,7 +18,7 @@ </%def> <%def name="main()"> -<div class="box"> +<div class="box box-left"> <!-- box / title --> <div class="title"> ${self.breadcrumbs()} @@ -60,14 +60,6 @@ </div> </div> <div class="field"> - <div class="label"> - <label for="input">${_('Permissions')}:</label> - </div> - <div class="input"> - <%include file="repos_group_edit_perms.html"/> - </div> - </div> - <div class="field"> <div class="label label-checkbox"> <label for="enable_locking">${_('Enable locking')}:</label> </div> @@ -84,4 +76,28 @@ </div> ${h.end_form()} </div> +<div class="box box-right"> + <div class="title"> + <h5>${_('Permissions')}</h5> + </div> + ${h.form(url('set_repo_group_perm_member', group_name=c.repos_group.group_name),method='post')} + <div class="form"> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="input">${_('Permissions')}:</label> + </div> + <div class="input"> + ${h.hidden('repo_private')} + <%include file="repos_group_edit_perms.html"/> + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Save'),class_="ui-btn large")} + ${h.reset('reset',_('Reset'),class_="ui-btn large")} + </div> + </div> + </div> + ${h.end_form()} +</div> </%def>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rhodecode/templates/admin/users_groups/user_group_edit_perms.html Mon Apr 08 22:47:35 2013 +0200 @@ -0,0 +1,100 @@ +<table id="permissions_manage" class="noborder"> + <tr> + <td>${_('none')}</td> + <td>${_('read')}</td> + <td>${_('write')}</td> + <td>${_('admin')}</td> + <td>${_('member')}</td> + <td></td> + </tr> + ## USERS + %for r2p in c.users_group.user_user_group_to_perm: + ##forbid revoking permission from yourself + <tr id="id${id(r2p.user.username)}"> + %if c.rhodecode_user.user_id != r2p.user.user_id or c.rhodecode_user.is_admin: + <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.none')}</td> + <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.read')}</td> + <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.write')}</td> + <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.admin')}</td> + <td style="white-space: nowrap;"> + <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username if r2p.user.username != 'default' else _('default')} + </td> + <td> + %if r2p.user.username !='default': + <span class="delete_icon action_button" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}')"> + ${_('revoke')} + </span> + %endif + </td> + %else: + <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.none', disabled="disabled")}</td> + <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.read', disabled="disabled")}</td> + <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.write', disabled="disabled")}</td> + <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.admin', disabled="disabled")}</td> + <td style="white-space: nowrap;"> + <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username if r2p.user.username != 'default' else _('default')} + </td> + <td> + </td> + %endif + </tr> + %endfor + + <% + _tmpl = h.literal("""' \ + <td><input type="radio" value="usergroup.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \ + <td><input type="radio" value="usergroup.read" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \ + <td><input type="radio" value="usergroup.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \ + <td><input type="radio" value="usergroup.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \ + <td class="ac"> \ + <div class="perm_ac" id="perm_ac_{0}"> \ + <input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text"> \ + <input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden"> \ + <div id="perm_container_{0}"></div> \ + </div> \ + </td> \ + <td></td>'""") + %> + ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl' + <tr class="new_members last_new_member" id="add_perm_input"></tr> + <tr> + <td colspan="6"> + <span id="add_perm" class="add_icon" style="cursor: pointer;"> + ${_('Add another member')} + </span> + </td> + </tr> +</table> +<script type="text/javascript"> +function ajaxActionRevoke(obj_id, obj_type, field_id) { + var callback = { + success: function (o) { + var tr = YUD.get(String(field_id)); + tr.parentNode.removeChild(tr); + }, + failure: function (o) { + alert(_TM['Failed to remoke permission'] + ": " + o.status); + }, + }; + var sUrl = "${h.url('delete_user_group_perm_member', id=c.users_group.users_group_id)}"; + if (obj_type=='user'){ + var postData = '_method=delete&user_id={0}&obj_type=user'.format(obj_id); + } + else if (obj_type=='user_group'){ + var postData = '_method=delete&user_group_id={0}&obj_type=user_group'.format(obj_id); + } + + var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); +}; + + +YUE.onDOMReady(function () { + if (!YUD.hasClass('perm_new_member_name', 'error')) { + YUD.setStyle('add_perm_input', 'display', 'none'); + } + YAHOO.util.Event.addListener('add_perm', 'click', function () { + addPermAction(${_tmpl}, ${c.users_array|n}, ${c.users_groups_array|n}); + }); +}); + +</script>
--- a/rhodecode/templates/admin/users_groups/users_group_edit.html Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/templates/admin/users_groups/users_group_edit.html Mon Apr 08 22:47:35 2013 +0200 @@ -18,7 +18,7 @@ </%def> <%def name="main()"> -<div class="box box-left"> +<div class="box box-left" style="clear:left"> <!-- box / title --> <div class="title"> ${self.breadcrumbs()} @@ -92,12 +92,54 @@ </div> </div> ${h.end_form()} + <div class="group_members_wrap"> + % if c.group_members_obj: + <ul class="group_members"> + %for user in c.group_members_obj: + <li> + <div class="group_member"> + <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div> + <div>${h.link_to(user.username, h.url('edit_user',id=user.user_id))}</div> + <div>${user.full_name}</div> + </div> + </li> + %endfor + </ul> + %else: + <span class="empty_data">${_('No members yet')}</span> + %endif + </div> +</div> + + +<div class="box box-right"> + <div class="title"> + <h5>${_('Permissions')}</h5> + </div> + ${h.form(url('set_user_group_perm_member', id=c.users_group.users_group_id),method='post')} + <div class="form"> + <div class="fields"> + <div class="field"> + <div class="label"> + <label for="input">${_('Permissions')}:</label> + </div> + <div class="input"> + <%include file="user_group_edit_perms.html"/> + </div> + </div> + <div class="buttons"> + ${h.submit('save',_('Save'),class_="ui-btn large")} + ${h.reset('reset',_('Reset'),class_="ui-btn large")} + </div> + </div> + </div> + ${h.end_form()} </div> <div class="box box-right"> <!-- box / title --> <div class="title"> - <h5>${_('Permissions')}</h5> + <h5>${_('Permissions summary')}</h5> </div> ${h.form(url('users_group_perm', id=c.users_group.users_group_id), method='put')} <div class="form"> @@ -138,35 +180,6 @@ </div> </div> ${h.end_form()} - - ## permissions overview - <%namespace name="p" file="/base/perms_summary.html"/> - ${p.perms_summary(c.users_group.permissions)} -</div> - -<div class="box box-right" style="clear:right"> - <!-- box / title --> - <div class="title"> - <h5>${_('Group members')}</h5> - </div> - - <div class="group_members_wrap"> - % if c.group_members_obj: - <ul class="group_members"> - %for user in c.group_members_obj: - <li> - <div class="group_member"> - <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div> - <div>${h.link_to(user.username, h.url('edit_user',id=user.user_id))}</div> - <div>${user.full_name}</div> - </div> - </li> - %endfor - </ul> - %else: - <span class="empty_data">${_('No members yet')}</span> - %endif - </div> </div> <script type="text/javascript">
--- a/rhodecode/templates/base/base.html Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/templates/base/base.html Mon Apr 08 22:47:35 2013 +0200 @@ -77,9 +77,14 @@ </ul> </%def> -<%def name="admin_menu_simple()"> +<%def name="admin_menu_simple(repository_groups=None, user_groups=None)"> <ul> + %if repository_groups: <li>${h.link_to(_('Repository groups'),h.url('repos_groups'),class_='repos_groups')}</li> + %endif: + %if user_groups: + <li>${h.link_to(_('User groups'),h.url('users_groups'),class_='groups')}</li> + %endif </ul> </%def> @@ -294,12 +299,12 @@ </a> ${admin_menu()} </li> - % elif c.rhodecode_user.groups_admin: + % elif c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin: <li ${is_current('admin')}> <a class="menu_link admin childs" title="${_('Admin')}"> ${_('Admin')} </a> - ${admin_menu_simple()} + ${admin_menu_simple(c.rhodecode_user.repository_groups_admin, c.rhodecode_user.user_groups_admin)} </li> % endif ${usermenu()}
--- a/rhodecode/templates/base/root.html Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/templates/base/root.html Mon Apr 08 22:47:35 2013 +0200 @@ -54,7 +54,8 @@ 'Show selected changeset __S': "${_('Show selected changeset __S')}", 'Selection link': "${_('Selection link')}", 'Collapse diff': "${_('Collapse diff')}", - 'Expand diff': "${_('Expand diff')}" + 'Expand diff': "${_('Expand diff')}", + 'Failed to remoke permission': "${_('Failed to remoke permission')}" }; var _TM = TRANSLATION_MAP;
--- a/rhodecode/tests/api/api_base.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/tests/api/api_base.py Mon Apr 08 22:47:35 2013 +0200 @@ -50,9 +50,9 @@ ## helpers def make_users_group(name=TEST_USER_GROUP): - gr = UserGroupModel().create(name=name) + gr = fixture.create_user_group(name, cur_user=TEST_USER_ADMIN_LOGIN) UserGroupModel().add_user_to_group(users_group=gr, - user=TEST_USER_ADMIN_LOGIN) + user=TEST_USER_ADMIN_LOGIN) Session().commit() return gr @@ -1084,8 +1084,7 @@ def test_api_add_user_to_users_group(self): gr_name = 'test_group' - UserGroupModel().create(gr_name) - Session().commit() + fixture.create_user_group(gr_name) id_, params = _build_data(self.apikey, 'add_user_to_users_group', usersgroupid=gr_name, userid=TEST_USER_ADMIN_LOGIN) @@ -1113,8 +1112,7 @@ @mock.patch.object(UserGroupModel, 'add_user_to_group', crash) def test_api_add_user_to_users_group_exception_occurred(self): gr_name = 'test_group' - UserGroupModel().create(gr_name) - Session().commit() + fixture.create_user_group(gr_name) id_, params = _build_data(self.apikey, 'add_user_to_users_group', usersgroupid=gr_name, userid=TEST_USER_ADMIN_LOGIN) @@ -1128,7 +1126,7 @@ def test_api_remove_user_from_users_group(self): gr_name = 'test_group_3' - gr = UserGroupModel().create(gr_name) + gr = fixture.create_user_group(gr_name) UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN) Session().commit() id_, params = _build_data(self.apikey, 'remove_user_from_users_group', @@ -1149,7 +1147,7 @@ @mock.patch.object(UserGroupModel, 'remove_user_from_group', crash) def test_api_remove_user_from_users_group_exception_occurred(self): gr_name = 'test_group_3' - gr = UserGroupModel().create(gr_name) + gr = fixture.create_user_group(gr_name) UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN) Session().commit() id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
--- a/rhodecode/tests/fixture.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/tests/fixture.py Mon Apr 08 22:47:35 2013 +0200 @@ -2,10 +2,11 @@ Helpers for fixture generation """ from rhodecode.tests import * -from rhodecode.model.db import Repository, User, RepoGroup +from rhodecode.model.db import Repository, User, RepoGroup, UserGroup from rhodecode.model.meta import Session from rhodecode.model.repo import RepoModel from rhodecode.model.repos_group import ReposGroupModel +from rhodecode.model.users_group import UserGroupModel class Fixture(object): @@ -43,6 +44,15 @@ return defs + def _get_user_group_create_params(self, name, **custom): + defs = dict( + users_group_name=name, + users_group_active=True, + ) + defs.update(custom) + + return defs + def create_repo(self, name, **kwargs): if 'skip_if_exists' in kwargs: del kwargs['skip_if_exists'] @@ -100,3 +110,17 @@ Session().commit() gr = RepoGroup.get_by_group_name(gr.group_name) return gr + + def create_user_group(self, name, **kwargs): + if 'skip_if_exists' in kwargs: + del kwargs['skip_if_exists'] + gr = UserGroup.get_by_group_name(group_name=name) + if gr: + return gr + form_data = self._get_user_group_create_params(name, **kwargs) + owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN) + user_group = UserGroupModel().create(name=form_data['users_group_name'], + owner=owner, active=form_data['users_group_active']) + Session().commit() + user_group = UserGroup.get_by_group_name(user_group.users_group_name) + return user_group
--- a/rhodecode/tests/models/test_permissions.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/tests/models/test_permissions.py Mon Apr 08 22:47:35 2013 +0200 @@ -126,9 +126,7 @@ def test_propagated_permission_from_users_group_by_explicit_perms_exist(self): # make group - self.ug1 = UserGroupModel().create('G1') - # add user to group - + self.ug1 = fixture.create_user_group('G1') UserGroupModel().add_user_to_group(self.ug1, self.u1) # set permission to lower @@ -160,9 +158,7 @@ def test_propagated_permission_from_users_group(self): # make group - self.ug1 = UserGroupModel().create('G1') - # add user to group - + self.ug1 = fixture.create_user_group('G1') UserGroupModel().add_user_to_group(self.ug1, self.u3) # grant perm for group this should override default permission from user @@ -185,7 +181,7 @@ def test_propagated_permission_from_users_group_lower_weight(self): # make group - self.ug1 = UserGroupModel().create('G1') + self.ug1 = fixture.create_user_group('G1') # add user to group UserGroupModel().add_user_to_group(self.ug1, self.u1) @@ -295,7 +291,7 @@ user=self.anon, perm='group.none') # make group - self.ug1 = UserGroupModel().create('G1') + self.ug1 = fixture.create_user_group('G1') # add user to group UserGroupModel().add_user_to_group(self.ug1, self.u1) Session().commit() @@ -434,8 +430,7 @@ self.assertEqual(u1_auth.permissions['repositories']['myownrepo'], 'repository.admin') #set his permission as user group, he should still be admin - self.ug1 = UserGroupModel().create('G1') - # add user to group + self.ug1 = fixture.create_user_group('G1') UserGroupModel().add_user_to_group(self.ug1, self.u1) RepoModel().grant_users_group_permission(self.test_repo, group_name=self.ug1,
--- a/rhodecode/tests/models/test_users.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/tests/models/test_users.py Mon Apr 08 22:47:35 2013 +0200 @@ -7,6 +7,9 @@ from rhodecode.model.meta import Session from rhodecode.model.users_group import UserGroupModel +from rhodecode.tests.fixture import Fixture + +fixture = Fixture() class TestUser(unittest.TestCase): @@ -26,7 +29,7 @@ self.assertEqual(User.get_by_username(u'test_user'), usr) # make user group - users_group = UserGroupModel().create('some_example_group') + users_group = fixture.create_user_group('some_example_group') Session().commit() UserGroupModel().add_user_to_group(users_group, usr)
--- a/rhodecode/tests/models/test_users_group_permissions_on_groups.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/tests/models/test_users_group_permissions_on_groups.py Mon Apr 08 22:47:35 2013 +0200 @@ -4,15 +4,16 @@ from rhodecode.tests import * from rhodecode.model.repos_group import ReposGroupModel -from rhodecode.model.db import RepoGroup, Repository, User +from rhodecode.model.db import RepoGroup from rhodecode.model.meta import Session from nose.tools import with_setup from rhodecode.tests.models.common import _create_project_tree, check_tree_perms, \ _get_perms, _check_expected_count, expected_count, _destroy_project_tree from rhodecode.model.users_group import UserGroupModel -from rhodecode.model.repo import RepoModel +from rhodecode.tests.fixture import Fixture +fixture = Fixture() test_u2_id = None test_u2_gr_id = None @@ -40,7 +41,7 @@ Session().commit() test_u2_id = test_u2.user_id - gr1 = UserGroupModel().create(name='perms_group_1') + gr1 = fixture.create_user_group('perms_group_1') Session().commit() test_u2_gr_id = gr1.users_group_id UserGroupModel().add_user_to_group(gr1, user=test_u2_id)
--- a/rhodecode/tests/test_validators.py Mon Apr 08 20:38:37 2013 +0200 +++ b/rhodecode/tests/test_validators.py Mon Apr 08 22:47:35 2013 +0200 @@ -12,6 +12,9 @@ from rhodecode.config.routing import ADMIN_PREFIX from rhodecode.model.db import ChangesetStatus, Repository from rhodecode.model.changeset_status import ChangesetStatusModel +from rhodecode.tests.fixture import Fixture + +fixture = Fixture() class TestReposGroups(unittest.TestCase): @@ -55,9 +58,9 @@ self.assertRaises(formencode.Invalid, validator.to_python, 'default') self.assertRaises(formencode.Invalid, validator.to_python, '.,') - gr = UserGroupModel().create('test') - gr2 = UserGroupModel().create('tes2') - Session.commit() + gr = fixture.create_user_group('test') + gr2 = fixture.create_user_group('tes2') + Session().commit() self.assertRaises(formencode.Invalid, validator.to_python, 'test') assert gr.users_group_id != None validator = v.ValidUserGroup(edit=True, @@ -69,7 +72,7 @@ self.assertRaises(formencode.Invalid, validator.to_python, 'TEST') UserGroupModel().delete(gr) UserGroupModel().delete(gr2) - Session.commit() + Session().commit() def test_ValidReposGroup(self): validator = v.ValidReposGroup()