# HG changeset patch # User Marcin Kuzminski # Date 2017-08-31 10:47:19 # Node ID 71f5d13f22a6d68c234d6e28df2d9e5368d4de44 # Parent e89cfa8fe4b06a1793c4043920c807d8cd03f885 user-groups: rewrote the app to pyramid - added new event data with added/removed/changed permissions - cleanup code and spelling diff --git a/rhodecode/apps/_base/__init__.py b/rhodecode/apps/_base/__init__.py --- a/rhodecode/apps/_base/__init__.py +++ b/rhodecode/apps/_base/__init__.py @@ -29,6 +29,7 @@ from rhodecode.lib.utils2 import StrictA from rhodecode.lib.vcs.exceptions import RepositoryRequirementError from rhodecode.model import repo from rhodecode.model import repo_group +from rhodecode.model import user_group from rhodecode.model.db import User from rhodecode.model.scm import ScmModel @@ -259,6 +260,13 @@ class RepoGroupAppView(BaseAppView): self.db_repo_group_name = self.db_repo_group.group_name +class UserGroupAppView(BaseAppView): + def __init__(self, context, request): + super(UserGroupAppView, self).__init__(context, request) + self.db_user_group = request.db_user_group + self.db_user_group_name = self.db_user_group.users_group_name + + class DataGridAppView(object): """ Common class to have re-usable grid rendering components @@ -462,6 +470,33 @@ class RepoGroupRoutePredicate(object): return False +class UserGroupRoutePredicate(object): + def __init__(self, val, config): + self.val = val + + def text(self): + return 'user_group_route = %s' % self.val + + phash = text + + def __call__(self, info, request): + if hasattr(request, 'vcs_call'): + # skip vcs calls + return + + user_group_id = info['match']['user_group_id'] + user_group_model = user_group.UserGroup() + by_name_match = user_group_model.get( + user_group_id, cache=True) + + if by_name_match: + # register this as request object we can re-use later + request.db_user_group = by_name_match + return True + + return False + + def includeme(config): config.add_route_predicate( 'repo_route', RepoRoutePredicate) @@ -469,3 +504,5 @@ def includeme(config): 'repo_accepted_types', RepoTypeRoutePredicate) config.add_route_predicate( 'repo_group_route', RepoGroupRoutePredicate) + config.add_route_predicate( + 'user_group_route', UserGroupRoutePredicate) diff --git a/rhodecode/apps/admin/__init__.py b/rhodecode/apps/admin/__init__.py --- a/rhodecode/apps/admin/__init__.py +++ b/rhodecode/apps/admin/__init__.py @@ -180,7 +180,7 @@ def admin_routes(config): name='edit_user_perms_summary_json', pattern='/users/{user_id:\d+}/edit/permissions_summary/json') - # user groups management + # user user groups management config.add_route( name='edit_user_groups_management', pattern='/users/{user_id:\d+}/edit/groups_management') @@ -194,7 +194,7 @@ def admin_routes(config): name='edit_user_audit_logs', pattern='/users/{user_id:\d+}/edit/audit') - # user groups admin + # user-groups admin config.add_route( name='user_groups', pattern='/user_groups') @@ -204,16 +204,12 @@ def admin_routes(config): pattern='/user_groups_data') config.add_route( - name='user_group_members_data', - pattern='/user_groups/{user_group_id:\d+}/members') + name='user_groups_new', + pattern='/user_groups/new') - # user groups perms config.add_route( - name='edit_user_group_perms_summary', - pattern='/user_groups/{user_group_id:\d+}/edit/permissions_summary') - config.add_route( - name='edit_user_group_perms_summary_json', - pattern='/user_groups/{user_group_id:\d+}/edit/permissions_summary/json') + name='user_groups_create', + pattern='/user_groups/create') # repos admin config.add_route( diff --git a/rhodecode/apps/admin/tests/test_admin_user_groups.py b/rhodecode/apps/admin/tests/test_admin_user_groups.py --- a/rhodecode/apps/admin/tests/test_admin_user_groups.py +++ b/rhodecode/apps/admin/tests/test_admin_user_groups.py @@ -38,6 +38,9 @@ def route_path(name, params=None, **kwar 'user_groups': ADMIN_PREFIX + '/user_groups', 'user_groups_data': ADMIN_PREFIX + '/user_groups_data', 'user_group_members_data': ADMIN_PREFIX + '/user_groups/{user_group_id}/members', + 'user_groups_new': ADMIN_PREFIX + '/user_groups/new', + 'user_groups_create': ADMIN_PREFIX + '/user_groups/create', + 'edit_user_group': ADMIN_PREFIX + '/user_groups/{user_group_id}/edit', }[name].format(**kwargs) if params: @@ -107,7 +110,61 @@ class TestAdminUserGroupsView(TestContro members = [u.user_id for u in User.get_all()] ug = user_util.create_user_group(members=members) response = self.app.get( - route_path('user_group_members_data', user_group_id=ug.users_group_id), + route_path('user_group_members_data', + user_group_id=ug.users_group_id), extra_environ=xhr_header) assert len(response.json['members']) == len(members) + + def test_creation_page(self): + self.log_user() + self.app.get(route_path('user_groups_new'), status=200) + + def test_create(self): + from rhodecode.lib import helpers as h + + self.log_user() + users_group_name = 'test_user_group' + response = self.app.post(route_path('user_groups_create'), { + 'users_group_name': users_group_name, + 'user_group_description': 'DESC', + 'active': True, + 'csrf_token': self.csrf_token}) + + user_group_id = UserGroup.get_by_group_name( + users_group_name).users_group_id + + user_group_link = h.link_to( + users_group_name, + route_path('edit_user_group', user_group_id=user_group_id)) + + assert_session_flash( + response, + 'Created user group %s' % user_group_link) + + fixture.destroy_user_group(users_group_name) + + def test_create_with_empty_name(self): + self.log_user() + + response = self.app.post(route_path('user_groups_create'), { + 'users_group_name': '', + 'user_group_description': 'DESC', + 'active': True, + 'csrf_token': self.csrf_token}, status=200) + + response.mustcontain('Please enter a value') + + def test_create_duplicate(self, user_util): + self.log_user() + + user_group = user_util.create_user_group() + duplicate_name = user_group.users_group_name + response = self.app.post(route_path('user_groups_create'), { + 'users_group_name': duplicate_name, + 'user_group_description': 'DESC', + 'active': True, + 'csrf_token': self.csrf_token}, status=200) + + response.mustcontain( + 'User group `{}` already exists'.format(user_group.users_group_name)) diff --git a/rhodecode/apps/admin/views/user_groups.py b/rhodecode/apps/admin/views/user_groups.py --- a/rhodecode/apps/admin/views/user_groups.py +++ b/rhodecode/apps/admin/views/user_groups.py @@ -20,22 +20,28 @@ import logging +import formencode +import formencode.htmlfill + from pyramid.httpexceptions import HTTPFound from pyramid.view import view_config - -from rhodecode.model.scm import UserGroupList +from pyramid.response import Response +from pyramid.renderers import render from rhodecode.apps._base import BaseAppView, DataGridAppView from rhodecode.lib.auth import ( - LoginRequired, NotAnonymous, - HasUserGroupPermissionAnyDecorator) -from rhodecode.lib import helpers as h + LoginRequired, NotAnonymous, CSRFRequired, HasPermissionAnyDecorator) +from rhodecode.lib import helpers as h, audit_logger from rhodecode.lib.utils import PartialRenderer from rhodecode.lib.utils2 import safe_unicode + +from rhodecode.model.forms import UserGroupForm +from rhodecode.model.permission import PermissionModel +from rhodecode.model.scm import UserGroupList from rhodecode.model.db import ( - joinedload, or_, count, User, UserGroup, UserGroupMember, - UserGroupRepoToPerm, UserGroupRepoGroupToPerm) + or_, count, User, UserGroup, UserGroupMember) from rhodecode.model.meta import Session +from rhodecode.model.user_group import UserGroupModel log = logging.getLogger(__name__) @@ -44,6 +50,10 @@ class AdminUserGroupsView(BaseAppView, D def load_default_context(self): c = self._get_local_tmpl_context() + + PermissionModel().set_global_permission_choices( + c, gettext_translator=self.request.translate) + self._register_global_c(c) return c @@ -168,89 +178,70 @@ class AdminUserGroupsView(BaseAppView, D return data @LoginRequired() - @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') @view_config( - route_name='user_group_members_data', request_method='GET', - renderer='json_ext', xhr=True) - def user_group_members(self): - """ - Return members of given user group - """ - user_group_id = self.request.matchdict['user_group_id'] - user_group = UserGroup.get_or_404(user_group_id) - group_members_obj = sorted((x.user for x in user_group.members), - key=lambda u: u.username.lower()) - - group_members = [ - { - 'id': user.user_id, - 'first_name': user.first_name, - 'last_name': user.last_name, - 'username': user.username, - 'icon_link': h.gravatar_url(user.email, 30), - 'value_display': h.person(user.email), - 'value': user.username, - 'value_type': 'user', - 'active': user.active, - } - for user in group_members_obj - ] - - return { - 'members': group_members - } - - def _get_perms_summary(self, user_group_id): - permissions = { - 'repositories': {}, - 'repositories_groups': {}, - } - 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: - 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: - permissions['repositories_groups'][gr.group.group_name] \ - = gr.permission.permission_name - return permissions - - @LoginRequired() - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - @view_config( - route_name='edit_user_group_perms_summary', request_method='GET', - renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') - def user_group_perms_summary(self): + route_name='user_groups_new', request_method='GET', + renderer='rhodecode:templates/admin/user_groups/user_group_add.mako') + def user_groups_new(self): c = self.load_default_context() - - user_group_id = self.request.matchdict.get('user_group_id') - c.user_group = UserGroup.get_or_404(user_group_id) - - c.active = 'perms_summary' - - c.permissions = self._get_perms_summary(c.user_group.users_group_id) return self._get_template_context(c) @LoginRequired() - @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') + @CSRFRequired() @view_config( - route_name='edit_user_group_perms_summary_json', request_method='GET', - renderer='json_ext') - def user_group_perms_summary_json(self): - self.load_default_context() + route_name='user_groups_create', request_method='POST', + renderer='rhodecode:templates/admin/user_groups/user_group_add.mako') + def user_groups_create(self): + _ = self.request.translate + c = self.load_default_context() + users_group_form = UserGroupForm()() + + user_group_name = self.request.POST.get('users_group_name') + try: + form_result = users_group_form.to_python(dict(self.request.POST)) + user_group = UserGroupModel().create( + name=form_result['users_group_name'], + description=form_result['user_group_description'], + owner=self._rhodecode_user.user_id, + active=form_result['users_group_active']) + Session().flush() + creation_data = user_group.get_api_data() + user_group_name = form_result['users_group_name'] + + audit_logger.store_web( + 'user_group.create', action_data={'data': creation_data}, + user=self._rhodecode_user) - user_group_id = self.request.matchdict.get('user_group_id') - user_group = UserGroup.get_or_404(user_group_id) + user_group_link = h.link_to( + h.escape(user_group_name), + h.route_path( + 'edit_user_group', user_group_id=user_group.users_group_id)) + h.flash(h.literal(_('Created user group %(user_group_link)s') + % {'user_group_link': user_group_link}), + category='success') + Session().commit() + user_group_id = user_group.users_group_id + except formencode.Invalid as errors: - return self._get_perms_summary(user_group.users_group_id) + data = render( + 'rhodecode:templates/admin/user_groups/user_group_add.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + except Exception: + log.exception("Exception creating user group") + h.flash(_('Error occurred during creation of user group %s') \ + % user_group_name, category='error') + raise HTTPFound(h.route_path('user_groups_new')) + + raise HTTPFound( + h.route_path('edit_user_group', user_group_id=user_group_id)) diff --git a/rhodecode/apps/user_group/__init__.py b/rhodecode/apps/user_group/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/apps/user_group/__init__.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2017 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + + +from rhodecode.apps.admin.navigation import NavigationRegistry +from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.lib.utils2 import str2bool + + +def admin_routes(config): + """ + User groups /_admin prefixed routes + """ + + config.add_route( + name='user_group_members_data', + pattern='/user_groups/{user_group_id:\d+}/members', + user_group_route=True) + + # user groups perms + config.add_route( + name='edit_user_group_perms_summary', + pattern='/user_groups/{user_group_id:\d+}/edit/permissions_summary', + user_group_route=True) + config.add_route( + name='edit_user_group_perms_summary_json', + pattern='/user_groups/{user_group_id:\d+}/edit/permissions_summary/json', + user_group_route=True) + + # user groups edit + config.add_route( + name='edit_user_group', + pattern='/user_groups/{user_group_id:\d+}/edit', + user_group_route=True) + + # user groups update + config.add_route( + name='user_groups_update', + pattern='/user_groups/{user_group_id:\d+}/update', + user_group_route=True) + + config.add_route( + name='edit_user_group_global_perms', + pattern='/user_groups/{user_group_id:\d+}/edit/global_permissions', + user_group_route=True) + + config.add_route( + name='edit_user_group_global_perms_update', + pattern='/user_groups/{user_group_id:\d+}/edit/global_permissions/update', + user_group_route=True) + + config.add_route( + name='edit_user_group_perms', + pattern='/user_groups/{user_group_id:\d+}/edit/permissions', + user_group_route=True) + + config.add_route( + name='edit_user_group_perms_update', + pattern='/user_groups/{user_group_id:\d+}/edit/permissions/update', + user_group_route=True) + + config.add_route( + name='edit_user_group_advanced', + pattern='/user_groups/{user_group_id:\d+}/edit/advanced', + user_group_route=True) + + config.add_route( + name='edit_user_group_advanced_sync', + pattern='/user_groups/{user_group_id:\d+}/edit/advanced/sync', + user_group_route=True) + + # user groups delete + config.add_route( + name='user_groups_delete', + pattern='/user_groups/{user_group_id:\d+}/delete', + user_group_route=True) + + +def includeme(config): + # main admin routes + config.include(admin_routes, route_prefix=ADMIN_PREFIX) + + # Scan module for configuration decorators. + config.scan('.views', ignore='.tests') diff --git a/rhodecode/apps/user_group/tests/__init__.py b/rhodecode/apps/user_group/tests/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/apps/user_group/tests/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2017 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/\ diff --git a/rhodecode/tests/functional/test_admin_user_groups.py b/rhodecode/apps/user_group/tests/test_user_groups.py rename from rhodecode/tests/functional/test_admin_user_groups.py rename to rhodecode/apps/user_group/tests/test_user_groups.py --- a/rhodecode/tests/functional/test_admin_user_groups.py +++ b/rhodecode/apps/user_group/tests/test_user_groups.py @@ -21,98 +21,83 @@ import pytest from rhodecode.tests import ( - TestController, url, assert_session_flash, link_to, TEST_USER_ADMIN_LOGIN) -from rhodecode.model.db import User, UserGroup + TestController, assert_session_flash, TEST_USER_ADMIN_LOGIN) +from rhodecode.model.db import UserGroup from rhodecode.model.meta import Session from rhodecode.tests.fixture import Fixture -TEST_USER_GROUP = 'admins_test' - fixture = Fixture() -class TestAdminUsersGroupsController(TestController): - - def test_create(self): - self.log_user() - users_group_name = TEST_USER_GROUP - response = self.app.post(url('users_groups'), { - 'users_group_name': users_group_name, - 'user_group_description': 'DESC', - 'active': True, - 'csrf_token': self.csrf_token}) +def route_path(name, params=None, **kwargs): + import urllib + from rhodecode.apps._base import ADMIN_PREFIX - user_group_link = link_to( - users_group_name, - url('edit_users_group', - user_group_id=UserGroup.get_by_group_name( - users_group_name).users_group_id)) - assert_session_flash( - response, - 'Created user group %s' % user_group_link) + base_url = { + 'user_groups': ADMIN_PREFIX + '/user_groups', + 'user_groups_data': ADMIN_PREFIX + '/user_groups_data', + 'user_group_members_data': ADMIN_PREFIX + '/user_groups/{user_group_id}/members', + 'user_groups_new': ADMIN_PREFIX + '/user_groups/new', + 'user_groups_create': ADMIN_PREFIX + '/user_groups/create', + 'edit_user_group': ADMIN_PREFIX + '/user_groups/{user_group_id}/edit', + 'edit_user_group_advanced_sync': ADMIN_PREFIX + '/user_groups/{user_group_id}/edit/advanced/sync', + 'edit_user_group_global_perms_update': ADMIN_PREFIX + '/user_groups/{user_group_id}/edit/global_permissions/update', + 'user_groups_update': ADMIN_PREFIX + '/user_groups/{user_group_id}/update', + 'user_groups_delete': ADMIN_PREFIX + '/user_groups/{user_group_id}/delete', - def test_set_synchronization(self): + }[name].format(**kwargs) + + if params: + base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) + return base_url + + +class TestUserGroupsView(TestController): + + def test_set_synchronization(self, user_util): self.log_user() - users_group_name = TEST_USER_GROUP + 'sync' - response = self.app.post(url('users_groups'), { - 'users_group_name': users_group_name, - 'user_group_description': 'DESC', - 'active': True, - 'csrf_token': self.csrf_token}) + user_group_name = user_util.create_user_group().users_group_name group = Session().query(UserGroup).filter( - UserGroup.users_group_name == users_group_name).one() + UserGroup.users_group_name == user_group_name).one() assert group.group_data.get('extern_type') is None # enable self.app.post( - url('edit_user_group_advanced_sync', user_group_id=group.users_group_id), + route_path('edit_user_group_advanced_sync', + user_group_id=group.users_group_id), params={'csrf_token': self.csrf_token}, status=302) group = Session().query(UserGroup).filter( - UserGroup.users_group_name == users_group_name).one() + UserGroup.users_group_name == user_group_name).one() assert group.group_data.get('extern_type') == 'manual' assert group.group_data.get('extern_type_set_by') == TEST_USER_ADMIN_LOGIN # disable self.app.post( - url('edit_user_group_advanced_sync', + route_path('edit_user_group_advanced_sync', user_group_id=group.users_group_id), params={'csrf_token': self.csrf_token}, status=302) group = Session().query(UserGroup).filter( - UserGroup.users_group_name == users_group_name).one() + UserGroup.users_group_name == user_group_name).one() assert group.group_data.get('extern_type') is None assert group.group_data.get('extern_type_set_by') == TEST_USER_ADMIN_LOGIN - def test_delete(self): + def test_delete_user_group(self, user_util): self.log_user() - users_group_name = TEST_USER_GROUP + 'another' - response = self.app.post(url('users_groups'), { - 'users_group_name': users_group_name, - 'user_group_description': 'DESC', - 'active': True, - 'csrf_token': self.csrf_token}) - - user_group_link = link_to( - users_group_name, - url('edit_users_group', - user_group_id=UserGroup.get_by_group_name( - users_group_name).users_group_id)) - assert_session_flash( - response, - 'Created user group %s' % user_group_link) + user_group_id = user_util.create_user_group().users_group_id group = Session().query(UserGroup).filter( - UserGroup.users_group_name == users_group_name).one() + UserGroup.users_group_id == user_group_id).one() self.app.post( - url('delete_users_group', user_group_id=group.users_group_id), - params={'_method': 'delete', 'csrf_token': self.csrf_token}) + route_path('user_groups_delete', user_group_id=group.users_group_id), + params={'csrf_token': self.csrf_token}) group = Session().query(UserGroup).filter( - UserGroup.users_group_name == users_group_name).scalar() + UserGroup.users_group_id == user_group_id).scalar() assert group is None @@ -122,26 +107,16 @@ class TestAdminUsersGroupsController(Tes ('hg.create.XXX', 'hg.create.write_on_repogroup.true', 'hg.usergroup.create.true', 'hg.repogroup.create.true', 'hg.fork.repository', 'hg.inherit_default_perms.false', False, True), ('', '', '', '', '', '', True, False), ]) - def test_global_perms_on_group( + def test_global_permissions_on_user_group( self, repo_create, repo_create_write, user_group_create, repo_group_create, fork_create, expect_error, expect_form_error, - inherit_default_permissions): - self.log_user() - users_group_name = TEST_USER_GROUP + 'another2' - response = self.app.post(url('users_groups'), - {'users_group_name': users_group_name, - 'user_group_description': 'DESC', - 'active': True, - 'csrf_token': self.csrf_token}) + inherit_default_permissions, user_util): - ug = UserGroup.get_by_group_name(users_group_name) - user_group_link = link_to( - users_group_name, - url('edit_users_group', user_group_id=ug.users_group_id)) - assert_session_flash( - response, - 'Created user group %s' % user_group_link) - response.follow() + self.log_user() + user_group = user_util.create_user_group() + + user_group_name = user_group.users_group_name + user_group_id = user_group.users_group_id # ENABLE REPO CREATE ON A GROUP perm_params = { @@ -153,12 +128,11 @@ class TestAdminUsersGroupsController(Tes 'default_fork_create': fork_create, 'default_inherit_default_permissions': inherit_default_permissions, - '_method': 'put', 'csrf_token': self.csrf_token, } response = self.app.post( - url('edit_user_group_global_perms', - user_group_id=ug.users_group_id), + route_path('edit_user_group_global_perms_update', + user_group_id=user_group_id), params=perm_params) if expect_form_error: @@ -169,21 +143,76 @@ class TestAdminUsersGroupsController(Tes msg = 'An error occurred during permissions saving' else: msg = 'User Group global permissions updated successfully' - ug = UserGroup.get_by_group_name(users_group_name) - del perm_params['_method'] + ug = UserGroup.get_by_group_name(user_group_name) del perm_params['csrf_token'] del perm_params['inherit_default_permissions'] assert perm_params == ug.get_default_perms() assert_session_flash(response, msg) - fixture.destroy_user_group(users_group_name) - - def test_edit_autocomplete(self): + def test_edit_view(self, user_util): self.log_user() - ug = fixture.create_user_group(TEST_USER_GROUP, skip_if_exists=True) - response = self.app.get( - url('edit_users_group', user_group_id=ug.users_group_id)) - fixture.destroy_user_group(TEST_USER_GROUP) + + user_group = user_util.create_user_group() + self.app.get( + route_path('edit_user_group', + user_group_id=user_group.users_group_id), + status=200) + + def test_update_user_group(self, user_util): + user = self.log_user() + + user_group = user_util.create_user_group() + users_group_id = user_group.users_group_id + new_name = user_group.users_group_name + '_CHANGE' + + params = [ + ('users_group_active', False), + ('user_group_description', 'DESC'), + ('users_group_name', new_name), + ('user', user['username']), + ('csrf_token', self.csrf_token), + ('__start__', 'user_group_members:sequence'), + ('__start__', 'member:mapping'), + ('member_user_id', user['user_id']), + ('type', 'existing'), + ('__end__', 'member:mapping'), + ('__end__', 'user_group_members:sequence'), + ] + + self.app.post( + route_path('user_groups_update', + user_group_id=users_group_id), + params=params, + status=302) + + user_group = UserGroup.get(users_group_id) + assert user_group + + assert user_group.users_group_name == new_name + assert user_group.user_group_description == 'DESC' + assert user_group.users_group_active == False + + def test_update_user_group_name_conflicts(self, user_util): + self.log_user() + user_group_old = user_util.create_user_group() + new_name = user_group_old.users_group_name + + user_group = user_util.create_user_group() + + params = dict( + users_group_active=False, + user_group_description='DESC', + users_group_name=new_name, + csrf_token=self.csrf_token) + + response = self.app.post( + route_path('user_groups_update', + user_group_id=user_group.users_group_id), + params=params, + status=200) + + response.mustcontain('User group `{}` already exists'.format( + new_name)) def test_update_members_from_user_ids(self, user_regular): uid = user_regular.user_id @@ -197,7 +226,6 @@ class TestAdminUsersGroupsController(Tes form_data = [ ('csrf_token', self.csrf_token), - ('_method', 'put'), ('user', username), ('users_group_name', 'changed_name'), ('users_group_active', expected_active_state), @@ -211,7 +239,8 @@ class TestAdminUsersGroupsController(Tes ('__end__', 'user_group_members:sequence'), ] ugid = user_group.users_group_id - self.app.post(url('update_users_group', user_group_id=ugid), form_data) + self.app.post( + route_path('user_groups_update', user_group_id=ugid), form_data) user_group = UserGroup.get(ugid) assert user_group diff --git a/rhodecode/apps/user_group/views/__init__.py b/rhodecode/apps/user_group/views/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/apps/user_group/views/__init__.py @@ -0,0 +1,529 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2017 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +import peppercorn +import formencode +import formencode.htmlfill +from pyramid.httpexceptions import HTTPFound +from pyramid.view import view_config +from pyramid.response import Response +from pyramid.renderers import render + +from rhodecode.lib.exceptions import ( + RepoGroupAssignmentError, UserGroupAssignedException) +from rhodecode.model.forms import ( + UserGroupPermsForm, UserGroupForm, UserIndividualPermissionsForm, + UserPermissionsForm) +from rhodecode.model.permission import PermissionModel + +from rhodecode.apps._base import UserGroupAppView +from rhodecode.lib.auth import ( + LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired) +from rhodecode.lib import helpers as h, audit_logger +from rhodecode.lib.utils2 import str2bool +from rhodecode.model.db import ( + joinedload, User, UserGroupRepoToPerm, UserGroupRepoGroupToPerm) +from rhodecode.model.meta import Session +from rhodecode.model.user_group import UserGroupModel + +log = logging.getLogger(__name__) + + +class UserGroupsView(UserGroupAppView): + + def load_default_context(self): + c = self._get_local_tmpl_context() + + PermissionModel().set_global_permission_choices( + c, gettext_translator=self.request.translate) + + self._register_global_c(c) + return c + + def _get_perms_summary(self, user_group_id): + permissions = { + 'repositories': {}, + 'repositories_groups': {}, + } + 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: + 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: + permissions['repositories_groups'][gr.group.group_name] \ + = gr.permission.permission_name + return permissions + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @view_config( + route_name='user_group_members_data', request_method='GET', + renderer='json_ext', xhr=True) + def user_group_members(self): + """ + Return members of given user group + """ + user_group = self.db_user_group + group_members_obj = sorted((x.user for x in user_group.members), + key=lambda u: u.username.lower()) + + group_members = [ + { + 'id': user.user_id, + 'first_name': user.first_name, + 'last_name': user.last_name, + 'username': user.username, + 'icon_link': h.gravatar_url(user.email, 30), + 'value_display': h.person(user.email), + 'value': user.username, + 'value_type': 'user', + 'active': user.active, + } + for user in group_members_obj + ] + + return { + 'members': group_members + } + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @view_config( + route_name='edit_user_group_perms_summary', request_method='GET', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_perms_summary(self): + c = self.load_default_context() + c.user_group = self.db_user_group + c.active = 'perms_summary' + c.permissions = self._get_perms_summary(c.user_group.users_group_id) + return self._get_template_context(c) + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @view_config( + route_name='edit_user_group_perms_summary_json', request_method='GET', + renderer='json_ext') + def user_group_perms_summary_json(self): + self.load_default_context() + user_group = self.db_user_group + return self._get_perms_summary(user_group.users_group_id) + + def _revoke_perms_on_yourself(self, form_result): + _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), + form_result['perm_updates']) + _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), + form_result['perm_additions']) + _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), + form_result['perm_deletions']) + admin_perm = 'usergroup.admin' + if _updates and _updates[0][1] != admin_perm or \ + _additions and _additions[0][1] != admin_perm or \ + _deletions and _deletions[0][1] != admin_perm: + return True + return False + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @CSRFRequired() + @view_config( + route_name='user_groups_update', request_method='POST', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_update(self): + _ = self.request.translate + + user_group = self.db_user_group + user_group_id = user_group.users_group_id + + c = self.load_default_context() + c.user_group = user_group + c.group_members_obj = [x.user for x in c.user_group.members] + c.group_members_obj.sort(key=lambda u: u.username.lower()) + c.group_members = [(x.user_id, x.username) for x in c.group_members_obj] + c.active = 'settings' + + users_group_form = UserGroupForm( + edit=True, old_data=c.user_group.get_dict(), allow_disabled=True)() + + old_values = c.user_group.get_api_data() + user_group_name = self.request.POST.get('users_group_name') + try: + form_result = users_group_form.to_python(self.request.POST) + pstruct = peppercorn.parse(self.request.POST.items()) + form_result['users_group_members'] = pstruct['user_group_members'] + + user_group, added_members, removed_members = \ + UserGroupModel().update(c.user_group, form_result) + updated_user_group = form_result['users_group_name'] + + audit_logger.store_web( + 'user_group.edit', action_data={'old_data': old_values}, + user=self._rhodecode_user) + + # TODO(marcink): use added/removed to set user_group.edit.member.add + + h.flash(_('Updated user group %s') % updated_user_group, + category='success') + Session().commit() + except formencode.Invalid as errors: + defaults = errors.value + e = errors.error_dict or {} + + data = render( + 'rhodecode:templates/admin/user_groups/user_group_edit.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=defaults, + errors=e, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + except Exception: + log.exception("Exception during update of user group") + h.flash(_('Error occurred during update of user group %s') + % user_group_name, category='error') + + raise HTTPFound( + h.route_path('edit_user_group', user_group_id=user_group_id)) + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @CSRFRequired() + @view_config( + route_name='user_groups_delete', request_method='POST', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_delete(self): + _ = self.request.translate + user_group = self.db_user_group + + self.load_default_context() + force = str2bool(self.request.POST.get('force')) + + old_values = user_group.get_api_data() + try: + UserGroupModel().delete(user_group, force=force) + audit_logger.store_web( + 'user.delete', action_data={'old_data': old_values}, + user=self._rhodecode_user) + Session().commit() + h.flash(_('Successfully deleted user group'), category='success') + except UserGroupAssignedException as e: + h.flash(str(e), category='error') + except Exception: + log.exception("Exception during deletion of user group") + h.flash(_('An error occurred during deletion of user group'), + category='error') + raise HTTPFound(h.route_path('user_groups')) + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @view_config( + route_name='edit_user_group', request_method='GET', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_edit(self): + user_group = self.db_user_group + + c = self.load_default_context() + c.user_group = user_group + c.group_members_obj = [x.user for x in c.user_group.members] + c.group_members_obj.sort(key=lambda u: u.username.lower()) + c.group_members = [(x.user_id, x.username) for x in c.group_members_obj] + + c.active = 'settings' + + defaults = user_group.get_dict() + # fill owner + if user_group.user: + defaults.update({'user': user_group.user.username}) + else: + replacement_user = User.get_first_super_admin().username + defaults.update({'user': replacement_user}) + + data = render( + 'rhodecode:templates/admin/user_groups/user_group_edit.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @view_config( + route_name='edit_user_group_perms', request_method='GET', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_edit_perms(self): + user_group = self.db_user_group + c = self.load_default_context() + c.user_group = user_group + c.active = 'perms' + + defaults = {} + # fill user group users + for p in c.user_group.user_user_group_to_perm: + defaults.update({'u_perm_%s' % p.user.user_id: + p.permission.permission_name}) + + for p in c.user_group.user_group_user_group_to_perm: + defaults.update({'g_perm_%s' % p.user_group.users_group_id: + p.permission.permission_name}) + + data = render( + 'rhodecode:templates/admin/user_groups/user_group_edit.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @CSRFRequired() + @view_config( + route_name='edit_user_group_perms_update', request_method='POST', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_update_perms(self): + """ + grant permission for given user group + """ + _ = self.request.translate + + user_group = self.db_user_group + user_group_id = user_group.users_group_id + c = self.load_default_context() + c.user_group = user_group + form = UserGroupPermsForm()().to_python(self.request.POST) + + if not self._rhodecode_user.is_admin: + if self._revoke_perms_on_yourself(form): + msg = _('Cannot change permission for yourself as admin') + h.flash(msg, category='warning') + raise HTTPFound( + h.route_path('edit_user_group_perms', + user_group_id=user_group_id)) + + try: + changes = UserGroupModel().update_permissions( + user_group_id, + form['perm_additions'], form['perm_updates'], + form['perm_deletions']) + + except RepoGroupAssignmentError: + h.flash(_('Target group cannot be the same'), category='error') + raise HTTPFound( + h.route_path('edit_user_group_perms', + user_group_id=user_group_id)) + + action_data = { + 'added': changes['added'], + 'updated': changes['updated'], + 'deleted': changes['deleted'], + } + audit_logger.store_web( + 'user_group.edit.permissions', action_data=action_data, + user=self._rhodecode_user) + + Session().commit() + h.flash(_('User Group permissions updated'), category='success') + raise HTTPFound( + h.route_path('edit_user_group_perms', user_group_id=user_group_id)) + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @view_config( + route_name='edit_user_group_global_perms', request_method='GET', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_global_perms_edit(self): + user_group = self.db_user_group + c = self.load_default_context() + c.user_group = user_group + c.active = 'global_perms' + + c.default_user = User.get_default_user() + defaults = c.user_group.get_dict() + defaults.update(c.default_user.get_default_perms(suffix='_inherited')) + defaults.update(c.user_group.get_default_perms()) + + data = render( + 'rhodecode:templates/admin/user_groups/user_group_edit.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @CSRFRequired() + @view_config( + route_name='edit_user_group_global_perms_update', request_method='POST', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_global_perms_update(self): + _ = self.request.translate + user_group = self.db_user_group + user_group_id = self.db_user_group.users_group_id + + c = self.load_default_context() + c.user_group = user_group + c.active = 'global_perms' + + try: + # first stage that verifies the checkbox + _form = UserIndividualPermissionsForm() + form_result = _form.to_python(dict(self.request.POST)) + inherit_perms = form_result['inherit_default_permissions'] + user_group.inherit_default_permissions = inherit_perms + Session().add(user_group) + + if not inherit_perms: + # only update the individual ones if we un check the flag + _form = UserPermissionsForm( + [x[0] for x in c.repo_create_choices], + [x[0] for x in c.repo_create_on_write_choices], + [x[0] for x in c.repo_group_create_choices], + [x[0] for x in c.user_group_create_choices], + [x[0] for x in c.fork_choices], + [x[0] for x in c.inherit_default_permission_choices])() + + form_result = _form.to_python(dict(self.request.POST)) + form_result.update( + {'perm_user_group_id': user_group.users_group_id}) + + PermissionModel().update_user_group_permissions(form_result) + + Session().commit() + h.flash(_('User Group global permissions updated successfully'), + category='success') + + except formencode.Invalid as errors: + defaults = errors.value + + data = render( + 'rhodecode:templates/admin/user_groups/user_group_edit.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + except Exception: + log.exception("Exception during permissions saving") + h.flash(_('An error occurred during permissions saving'), + category='error') + + raise HTTPFound( + h.route_path('edit_user_group_global_perms', + user_group_id=user_group_id)) + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @view_config( + route_name='edit_user_group_advanced', request_method='GET', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_edit_advanced(self): + user_group = self.db_user_group + + c = self.load_default_context() + c.user_group = user_group + c.active = 'advanced' + c.group_members_obj = sorted( + (x.user for x in c.user_group.members), + key=lambda u: u.username.lower()) + + c.group_to_repos = sorted( + (x.repository for x in c.user_group.users_group_repo_to_perm), + key=lambda u: u.repo_name.lower()) + + c.group_to_repo_groups = sorted( + (x.group for x in c.user_group.users_group_repo_group_to_perm), + key=lambda u: u.group_name.lower()) + + c.group_to_review_rules = sorted( + (x.users_group for x in c.user_group.user_group_review_rules), + key=lambda u: u.users_group_name.lower()) + + return self._get_template_context(c) + + @LoginRequired() + @HasUserGroupPermissionAnyDecorator('usergroup.admin') + @CSRFRequired() + @view_config( + route_name='edit_user_group_advanced_sync', request_method='POST', + renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako') + def user_group_edit_advanced_set_synchronization(self): + _ = self.request.translate + user_group = self.db_user_group + user_group_id = user_group.users_group_id + + existing = user_group.group_data.get('extern_type') + + if existing: + new_state = user_group.group_data + new_state['extern_type'] = None + else: + new_state = user_group.group_data + new_state['extern_type'] = 'manual' + new_state['extern_type_set_by'] = self._rhodecode_user.username + + try: + user_group.group_data = new_state + Session().add(user_group) + Session().commit() + + h.flash(_('User Group synchronization updated successfully'), + category='success') + except Exception: + log.exception("Exception during sync settings saving") + h.flash(_('An error occurred during synchronization update'), + category='error') + + raise HTTPFound( + h.route_path('edit_user_group_advanced', + user_group_id=user_group_id)) diff --git a/rhodecode/config/middleware.py b/rhodecode/config/middleware.py --- a/rhodecode/config/middleware.py +++ b/rhodecode/config/middleware.py @@ -296,6 +296,7 @@ def includeme(config): config.include('rhodecode.apps.journal') config.include('rhodecode.apps.repository') config.include('rhodecode.apps.repo_group') + config.include('rhodecode.apps.user_group') config.include('rhodecode.apps.search') config.include('rhodecode.apps.user_profile') config.include('rhodecode.apps.my_account') diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py --- a/rhodecode/config/routing.py +++ b/rhodecode/config/routing.py @@ -254,44 +254,6 @@ def make_map(config): m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions', action='update_global_perms', conditions={'method': ['PUT']}) - # ADMIN USER GROUPS REST ROUTES - with rmap.submapper(path_prefix=ADMIN_PREFIX, - controller='admin/user_groups') as m: - m.connect('users_groups', '/user_groups', - action='create', conditions={'method': ['POST']}) - m.connect('new_users_group', '/user_groups/new', - action='new', conditions={'method': ['GET']}) - m.connect('update_users_group', '/user_groups/{user_group_id}', - action='update', conditions={'method': ['PUT']}) - m.connect('delete_users_group', '/user_groups/{user_group_id}', - action='delete', conditions={'method': ['DELETE']}) - m.connect('edit_users_group', '/user_groups/{user_group_id}/edit', - action='edit', conditions={'method': ['GET']}, - function=check_user_group) - - # EXTRAS USER GROUP ROUTES - m.connect('edit_user_group_global_perms', - '/user_groups/{user_group_id}/edit/global_permissions', - action='edit_global_perms', conditions={'method': ['GET']}) - m.connect('edit_user_group_global_perms', - '/user_groups/{user_group_id}/edit/global_permissions', - action='update_global_perms', conditions={'method': ['PUT']}) - - m.connect('edit_user_group_perms', - '/user_groups/{user_group_id}/edit/permissions', - action='edit_perms', conditions={'method': ['GET']}) - m.connect('edit_user_group_perms', - '/user_groups/{user_group_id}/edit/permissions', - action='update_perms', conditions={'method': ['PUT']}) - - m.connect('edit_user_group_advanced', - '/user_groups/{user_group_id}/edit/advanced', - action='edit_advanced', conditions={'method': ['GET']}) - - m.connect('edit_user_group_advanced_sync', - '/user_groups/{user_group_id}/edit/advanced/sync', - action='edit_advanced_set_synchronization', conditions={'method': ['POST']}) - # ADMIN DEFAULTS REST ROUTES with rmap.submapper(path_prefix=ADMIN_PREFIX, controller='admin/defaults') as m: diff --git a/rhodecode/controllers/admin/user_groups.py b/rhodecode/controllers/admin/user_groups.py deleted file mode 100644 --- a/rhodecode/controllers/admin/user_groups.py +++ /dev/null @@ -1,417 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (C) 2011-2017 RhodeCode GmbH -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License, version 3 -# (only), as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# This program is dual-licensed. If you wish to learn more about the -# RhodeCode Enterprise Edition, including its added features, Support services, -# and proprietary license terms, please see https://rhodecode.com/licenses/ - -""" -User Groups crud controller for pylons -""" - -import logging -import formencode - -import peppercorn -from formencode import htmlfill -from pylons import request, tmpl_context as c, url, config -from pylons.controllers.util import redirect -from pylons.i18n.translation import _ - -from rhodecode.lib import auth -from rhodecode.lib import helpers as h -from rhodecode.lib import audit_logger -from rhodecode.lib.exceptions import UserGroupAssignedException,\ - RepoGroupAssignmentError -from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int -from rhodecode.lib.auth import ( - LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator, - HasPermissionAnyDecorator) -from rhodecode.lib.base import BaseController, render -from rhodecode.model.permission import PermissionModel -from rhodecode.model.user_group import UserGroupModel -from rhodecode.model.db import User, UserGroup -from rhodecode.model.forms import ( - UserGroupForm, UserGroupPermsForm, UserIndividualPermissionsForm, - UserPermissionsForm) -from rhodecode.model.meta import Session - - -log = logging.getLogger(__name__) - - -class UserGroupsController(BaseController): - """REST Controller styled on the Atom Publishing Protocol""" - - @LoginRequired() - def __before__(self): - super(UserGroupsController, self).__before__() - c.available_permissions = config['available_permissions'] - PermissionModel().set_global_permission_choices(c, gettext_translator=_) - - def __load_data(self, user_group_id): - c.group_members_obj = [x.user for x in c.user_group.members] - c.group_members_obj.sort(key=lambda u: u.username.lower()) - c.group_members = [(x.user_id, x.username) for x in c.group_members_obj] - - 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() - # fill owner - if user_group.user: - data.update({'user': user_group.user.username}) - else: - replacement_user = User.get_first_super_admin().username - data.update({'user': replacement_user}) - return data - - def _revoke_perms_on_yourself(self, form_result): - _updates = filter(lambda u: c.rhodecode_user.user_id == int(u[0]), - form_result['perm_updates']) - _additions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]), - form_result['perm_additions']) - _deletions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]), - form_result['perm_deletions']) - admin_perm = 'usergroup.admin' - if _updates and _updates[0][1] != admin_perm or \ - _additions and _additions[0][1] != admin_perm or \ - _deletions and _deletions[0][1] != admin_perm: - return True - return False - - @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') - @auth.CSRFRequired() - def create(self): - - users_group_form = UserGroupForm()() - try: - form_result = users_group_form.to_python(dict(request.POST)) - user_group = UserGroupModel().create( - name=form_result['users_group_name'], - description=form_result['user_group_description'], - owner=c.rhodecode_user.user_id, - active=form_result['users_group_active']) - Session().flush() - creation_data = user_group.get_api_data() - user_group_name = form_result['users_group_name'] - - audit_logger.store_web( - 'user_group.create', action_data={'data': creation_data}, - user=c.rhodecode_user) - - user_group_link = h.link_to( - h.escape(user_group_name), - url('edit_users_group', user_group_id=user_group.users_group_id)) - h.flash(h.literal(_('Created user group %(user_group_link)s') - % {'user_group_link': user_group_link}), - category='success') - Session().commit() - except formencode.Invalid as errors: - return htmlfill.render( - render('admin/user_groups/user_group_add.mako'), - defaults=errors.value, - errors=errors.error_dict or {}, - prefix_error=False, - encoding="UTF-8", - force_defaults=False) - except Exception: - log.exception("Exception creating user group") - h.flash(_('Error occurred during creation of user group %s') \ - % request.POST.get('users_group_name'), category='error') - - return redirect( - url('edit_users_group', user_group_id=user_group.users_group_id)) - - @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') - def new(self): - """GET /user_groups/new: Form to create a new item""" - # url('new_users_group') - return render('admin/user_groups/user_group_add.mako') - - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - @auth.CSRFRequired() - def update(self, user_group_id): - - user_group_id = safe_int(user_group_id) - c.user_group = UserGroup.get_or_404(user_group_id) - c.active = 'settings' - self.__load_data(user_group_id) - - users_group_form = UserGroupForm( - edit=True, old_data=c.user_group.get_dict(), allow_disabled=True)() - - old_values = c.user_group.get_api_data() - try: - form_result = users_group_form.to_python(request.POST) - pstruct = peppercorn.parse(request.POST.items()) - form_result['users_group_members'] = pstruct['user_group_members'] - - user_group, added_members, removed_members = \ - UserGroupModel().update(c.user_group, form_result) - updated_user_group = form_result['users_group_name'] - - audit_logger.store_web( - 'user_group.edit', action_data={'old_data': old_values}, - user=c.rhodecode_user) - - # TODO(marcink): use added/removed to set user_group.edit.member.add - - h.flash(_('Updated user group %s') % updated_user_group, - category='success') - Session().commit() - except formencode.Invalid as errors: - defaults = errors.value - e = errors.error_dict or {} - - return htmlfill.render( - render('admin/user_groups/user_group_edit.mako'), - defaults=defaults, - errors=e, - prefix_error=False, - encoding="UTF-8", - force_defaults=False) - except Exception: - log.exception("Exception during update of user group") - h.flash(_('Error occurred during update of user group %s') - % request.POST.get('users_group_name'), category='error') - - return redirect(url('edit_users_group', user_group_id=user_group_id)) - - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - @auth.CSRFRequired() - def delete(self, user_group_id): - user_group_id = safe_int(user_group_id) - c.user_group = UserGroup.get_or_404(user_group_id) - force = str2bool(request.POST.get('force')) - - old_values = c.user_group.get_api_data() - try: - UserGroupModel().delete(c.user_group, force=force) - audit_logger.store_web( - 'user.delete', action_data={'old_data': old_values}, - user=c.rhodecode_user) - Session().commit() - h.flash(_('Successfully deleted user group'), category='success') - except UserGroupAssignedException as e: - h.flash(str(e), category='error') - except Exception: - log.exception("Exception during deletion of user group") - h.flash(_('An error occurred during deletion of user group'), - category='error') - return redirect(url('users_groups')) - - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - def edit(self, user_group_id): - """GET /user_groups/user_group_id/edit: Form to edit an existing item""" - # url('edit_users_group', user_group_id=ID) - - user_group_id = safe_int(user_group_id) - c.user_group = UserGroup.get_or_404(user_group_id) - c.active = 'settings' - self.__load_data(user_group_id) - - defaults = self.__load_defaults(user_group_id) - - return htmlfill.render( - render('admin/user_groups/user_group_edit.mako'), - defaults=defaults, - encoding="UTF-8", - force_defaults=False - ) - - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - def edit_perms(self, user_group_id): - user_group_id = safe_int(user_group_id) - c.user_group = UserGroup.get_or_404(user_group_id) - c.active = 'perms' - - defaults = {} - # fill user group users - for p in c.user_group.user_user_group_to_perm: - defaults.update({'u_perm_%s' % p.user.user_id: - p.permission.permission_name}) - - for p in c.user_group.user_group_user_group_to_perm: - defaults.update({'g_perm_%s' % p.user_group.users_group_id: - p.permission.permission_name}) - - return htmlfill.render( - render('admin/user_groups/user_group_edit.mako'), - defaults=defaults, - encoding="UTF-8", - force_defaults=False - ) - - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - @auth.CSRFRequired() - def update_perms(self, user_group_id): - """ - grant permission for given usergroup - - :param user_group_id: - """ - user_group_id = safe_int(user_group_id) - c.user_group = UserGroup.get_or_404(user_group_id) - form = UserGroupPermsForm()().to_python(request.POST) - - if not c.rhodecode_user.is_admin: - if self._revoke_perms_on_yourself(form): - msg = _('Cannot change permission for yourself as admin') - h.flash(msg, category='warning') - return redirect(url('edit_user_group_perms', user_group_id=user_group_id)) - - try: - UserGroupModel().update_permissions(user_group_id, - form['perm_additions'], form['perm_updates'], form['perm_deletions']) - except RepoGroupAssignmentError: - h.flash(_('Target group cannot be the same'), category='error') - return redirect(url('edit_user_group_perms', user_group_id=user_group_id)) - - # TODO(marcink): implement global permissions - # audit_log.store_web('user_group.edit.permissions') - Session().commit() - h.flash(_('User Group permissions updated'), category='success') - return redirect(url('edit_user_group_perms', user_group_id=user_group_id)) - - - - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - def edit_global_perms(self, user_group_id): - user_group_id = safe_int(user_group_id) - c.user_group = UserGroup.get_or_404(user_group_id) - c.active = 'global_perms' - - c.default_user = User.get_default_user() - defaults = c.user_group.get_dict() - defaults.update(c.default_user.get_default_perms(suffix='_inherited')) - defaults.update(c.user_group.get_default_perms()) - - return htmlfill.render( - render('admin/user_groups/user_group_edit.mako'), - defaults=defaults, - encoding="UTF-8", - force_defaults=False - ) - - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - @auth.CSRFRequired() - def update_global_perms(self, user_group_id): - user_group_id = safe_int(user_group_id) - user_group = UserGroup.get_or_404(user_group_id) - c.active = 'global_perms' - - try: - # first stage that verifies the checkbox - _form = UserIndividualPermissionsForm() - form_result = _form.to_python(dict(request.POST)) - inherit_perms = form_result['inherit_default_permissions'] - user_group.inherit_default_permissions = inherit_perms - Session().add(user_group) - - if not inherit_perms: - # only update the individual ones if we un check the flag - _form = UserPermissionsForm( - [x[0] for x in c.repo_create_choices], - [x[0] for x in c.repo_create_on_write_choices], - [x[0] for x in c.repo_group_create_choices], - [x[0] for x in c.user_group_create_choices], - [x[0] for x in c.fork_choices], - [x[0] for x in c.inherit_default_permission_choices])() - - form_result = _form.to_python(dict(request.POST)) - form_result.update({'perm_user_group_id': user_group.users_group_id}) - - PermissionModel().update_user_group_permissions(form_result) - - Session().commit() - h.flash(_('User Group global permissions updated successfully'), - category='success') - - except formencode.Invalid as errors: - defaults = errors.value - c.user_group = user_group - return htmlfill.render( - render('admin/user_groups/user_group_edit.mako'), - defaults=defaults, - errors=errors.error_dict or {}, - prefix_error=False, - encoding="UTF-8", - force_defaults=False) - except Exception: - log.exception("Exception during permissions saving") - h.flash(_('An error occurred during permissions saving'), - category='error') - - return redirect(url('edit_user_group_global_perms', user_group_id=user_group_id)) - - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - def edit_advanced(self, user_group_id): - user_group_id = safe_int(user_group_id) - c.user_group = UserGroup.get_or_404(user_group_id) - c.active = 'advanced' - c.group_members_obj = sorted( - (x.user for x in c.user_group.members), - key=lambda u: u.username.lower()) - - c.group_to_repos = sorted( - (x.repository for x in c.user_group.users_group_repo_to_perm), - key=lambda u: u.repo_name.lower()) - - c.group_to_repo_groups = sorted( - (x.group for x in c.user_group.users_group_repo_group_to_perm), - key=lambda u: u.group_name.lower()) - - c.group_to_review_rules = sorted( - (x.users_group for x in c.user_group.user_group_review_rules), - key=lambda u: u.users_group_name.lower()) - - return render('admin/user_groups/user_group_edit.mako') - - @HasUserGroupPermissionAnyDecorator('usergroup.admin') - def edit_advanced_set_synchronization(self, user_group_id): - user_group_id = safe_int(user_group_id) - user_group = UserGroup.get_or_404(user_group_id) - - existing = user_group.group_data.get('extern_type') - - if existing: - new_state = user_group.group_data - new_state['extern_type'] = None - else: - new_state = user_group.group_data - new_state['extern_type'] = 'manual' - new_state['extern_type_set_by'] = c.rhodecode_user.username - - try: - user_group.group_data = new_state - Session().add(user_group) - Session().commit() - - h.flash(_('User Group synchronization updated successfully'), - category='success') - except Exception: - log.exception("Exception during sync settings saving") - h.flash(_('An error occurred during synchronization update'), - category='error') - - return redirect( - url('edit_user_group_advanced', user_group_id=user_group_id)) - diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py --- a/rhodecode/lib/auth.py +++ b/rhodecode/lib/auth.py @@ -1305,7 +1305,7 @@ def get_csrf_token(session=None, force_n return session.get(csrf_token_key) -def get_request(perm_class): +def get_request(perm_class_instance): from pyramid.threadlocal import get_current_request pyramid_request = get_current_request() if not pyramid_request: diff --git a/rhodecode/lib/dbmigrate/schema/db_1_2_0.py b/rhodecode/lib/dbmigrate/schema/db_1_2_0.py --- a/rhodecode/lib/dbmigrate/schema/db_1_2_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_1_2_0.py @@ -378,7 +378,6 @@ class UserGroup(Base, BaseModel): "get_user_%s" % group_name)) return gr.scalar() - @classmethod def get(cls, users_group_id, cache=False): users_group = cls.query() @@ -390,13 +389,13 @@ class UserGroup(Base, BaseModel): @classmethod def create(cls, form_data): try: - new_users_group = cls() + new_user_group = cls() for k, v in form_data.items(): - setattr(new_users_group, k, v) + setattr(new_user_group, k, v) - Session.add(new_users_group) + Session.add(new_user_group) Session.commit() - return new_users_group + return new_user_group except: log.error(traceback.format_exc()) Session.rollback() diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py --- a/rhodecode/lib/utils.py +++ b/rhodecode/lib/utils.py @@ -136,22 +136,29 @@ def get_repo_group_slug(request): def get_user_group_slug(request): - if isinstance(request, Request) and getattr(request, 'matchdict', None): - # pyramid - _group = request.matchdict.get('user_group_id') - else: - _group = request.environ['pylons.routes_dict'].get('user_group_id') + _user_group = '' + if isinstance(request, Request): + + if hasattr(request, 'db_user_group'): + _user_group = request.db_user_group.users_group_name + elif getattr(request, 'matchdict', None): + # pyramid + _user_group = request.matchdict.get('user_group_id') - try: - _group = UserGroup.get(_group) - if _group: - _group = _group.users_group_name - except Exception: - log.exception('Failed to get user group by id') - # catch all failures here - return None + try: + _user_group = UserGroup.get(_user_group) + if _user_group: + _user_group = _user_group.users_group_name + except Exception: + log.exception('Failed to get user group by id') + # catch all failures here + return None - return _group + # TODO(marcink): remove after pylons migration... + if not _user_group: + _user_group = request.environ['pylons.routes_dict'].get('user_group_id') + + return _user_group def get_filesystem_repos(path, recursive=False, skip_removed_repos=True): 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 @@ -68,8 +68,8 @@ class RepositoryPermissionModel(BaseMode .filter(UserGroupRepoToPerm.repository == repository) \ .scalar() - def update_users_group_permission(self, repository, users_group, - permission): + def update_user_group_permission(self, repository, users_group, + permission): permission = Permission.get_by_key(permission) current = self.get_users_group_permission(repository, users_group) if current: @@ -96,7 +96,7 @@ class RepositoryPermissionModel(BaseMode def update_or_delete_users_group_permission(self, repository, user_group, permission): if permission: - self.update_users_group_permission(repository, user_group, + self.update_user_group_permission(repository, user_group, permission) else: self.delete_users_group_permission(repository, user_group) diff --git a/rhodecode/model/user_group.py b/rhodecode/model/user_group.py --- a/rhodecode/model/user_group.py +++ b/rhodecode/model/user_group.py @@ -18,12 +18,6 @@ # RhodeCode Enterprise Edition, including its added features, Support services, # and proprietary license terms, please see https://rhodecode.com/licenses/ - -""" -user group model for RhodeCode -""" - - import logging import traceback @@ -67,8 +61,10 @@ class UserGroupModel(BaseModel): user_group_to_perm.user_id = def_user.user_id return user_group_to_perm - def update_permissions(self, user_group, perm_additions=None, perm_updates=None, - perm_deletions=None, check_perms=True, cur_user=None): + def update_permissions( + self, user_group, perm_additions=None, perm_updates=None, + perm_deletions=None, check_perms=True, cur_user=None): + from rhodecode.lib.auth import HasUserGroupPermissionAny if not perm_additions: perm_additions = [] @@ -79,10 +75,16 @@ class UserGroupModel(BaseModel): req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin') + changes = { + 'added': [], + 'updated': [], + 'deleted': [] + } # update permissions for member_id, perm, member_type in perm_updates: member_id = int(member_id) if member_type == 'user': + member_name = User.get(member_id).username # this updates existing one self.grant_user_permission( user_group=user_group, user=member_id, perm=perm @@ -90,38 +92,49 @@ class UserGroupModel(BaseModel): else: # check if we have permissions to alter this usergroup member_name = UserGroup.get(member_id).users_group_name - if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user): + if not check_perms or HasUserGroupPermissionAny( + *req_perms)(member_name, user=cur_user): self.grant_user_group_permission( - target_user_group=user_group, user_group=member_id, perm=perm - ) + target_user_group=user_group, user_group=member_id, perm=perm) + + changes['updated'].append({'type': member_type, 'id': member_id, + 'name': member_name, 'new_perm': perm}) # set new permissions for member_id, perm, member_type in perm_additions: member_id = int(member_id) if member_type == 'user': + member_name = User.get(member_id).username self.grant_user_permission( - user_group=user_group, user=member_id, perm=perm - ) + user_group=user_group, user=member_id, perm=perm) else: # check if we have permissions to alter this usergroup member_name = UserGroup.get(member_id).users_group_name - if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user): + if not check_perms or HasUserGroupPermissionAny( + *req_perms)(member_name, user=cur_user): self.grant_user_group_permission( - target_user_group=user_group, user_group=member_id, perm=perm - ) + target_user_group=user_group, user_group=member_id, perm=perm) + + changes['added'].append({'type': member_type, 'id': member_id, + 'name': member_name, 'new_perm': perm}) # delete permissions for member_id, perm, member_type in perm_deletions: member_id = int(member_id) if member_type == 'user': + member_name = User.get(member_id).username self.revoke_user_permission(user_group=user_group, user=member_id) else: # check if we have permissions to alter this usergroup member_name = UserGroup.get(member_id).users_group_name - if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user): + if not check_perms or HasUserGroupPermissionAny( + *req_perms)(member_name, user=cur_user): self.revoke_user_group_permission( - target_user_group=user_group, user_group=member_id - ) + target_user_group=user_group, user_group=member_id) + + changes['deleted'].append({'type': member_type, 'id': member_id, + 'name': member_name, 'new_perm': perm}) + return changes def get(self, user_group_id, cache=False): return UserGroup.get(user_group_id) @@ -247,6 +260,9 @@ class UserGroupModel(BaseModel): :param force: """ user_group = self._get_user_group(user_group) + if not user_group: + return + try: # check if this group is not assigned to repo assigned_to_repo = [x.repository for x in UserGroupRepoToPerm.query()\ @@ -527,7 +543,6 @@ class UserGroupModel(BaseModel): This method changes user group assignment :param user: User :param groups: array of UserGroupModel - :return: """ user = self._get_user(user) log.debug('Changing user(%s) assignment to groups(%s)', user, groups) @@ -542,11 +557,14 @@ class UserGroupModel(BaseModel): groups_to_add = groups - current_groups for gr in groups_to_remove: - log.debug('Removing user %s from user group %s', user.username, gr.users_group_name) + log.debug('Removing user %s from user group %s', + user.username, gr.users_group_name) self.remove_user_from_group(gr.users_group_name, user.username) for gr in groups_to_add: - log.debug('Adding user %s to user group %s', user.username, gr.users_group_name) - UserGroupModel().add_user_to_group(gr.users_group_name, user.username) + log.debug('Adding user %s to user group %s', + user.username, gr.users_group_name) + UserGroupModel().add_user_to_group( + gr.users_group_name, user.username) def _serialize_user_group(self, user_group): import rhodecode.lib.helpers as h @@ -617,7 +635,3 @@ class UserGroupModel(BaseModel): 'owner_icon': h.gravatar_url(user_group.user.email, 30)} } return data - - - - diff --git a/rhodecode/model/validators.py b/rhodecode/model/validators.py --- a/rhodecode/model/validators.py +++ b/rhodecode/model/validators.py @@ -221,7 +221,7 @@ def ValidUserGroup(edit=False, old_data= class _validator(formencode.validators.FancyValidator): messages = { 'invalid_group': _(u'Invalid user group name'), - 'group_exist': _(u'User group "%(usergroup)s" already exists'), + 'group_exist': _(u'User group `%(usergroup)s` already exists'), 'invalid_usergroup_name': _(u'user group name may only contain alphanumeric ' u'characters underscores, periods or dashes and must begin ' diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -81,9 +81,8 @@ function registerRCRoutes() { pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']); pyroutes.register('user_groups', '/_admin/user_groups', []); pyroutes.register('user_groups_data', '/_admin/user_groups_data', []); - pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']); - pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']); - pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']); + pyroutes.register('user_groups_new', '/_admin/user_groups/new', []); + pyroutes.register('user_groups_create', '/_admin/user_groups/create', []); pyroutes.register('repos', '/_admin/repos', []); pyroutes.register('repo_new', '/_admin/repos/new', []); pyroutes.register('repo_create', '/_admin/repos/create', []); @@ -210,6 +209,18 @@ function registerRCRoutes() { pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']); pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']); pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']); + pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']); + pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']); + pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']); + pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']); + pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']); + pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']); + pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']); + pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']); + pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']); + pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']); + pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']); + pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']); pyroutes.register('search', '/_admin/search', []); pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']); pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']); diff --git a/rhodecode/templates/admin/repo_groups/repo_group_edit_perms.mako b/rhodecode/templates/admin/repo_groups/repo_group_edit_perms.mako --- a/rhodecode/templates/admin/repo_groups/repo_group_edit_perms.mako +++ b/rhodecode/templates/admin/repo_groups/repo_group_edit_perms.mako @@ -96,7 +96,7 @@ %if h.HasPermissionAny('hg.admin')(): - + ${_user_group.users_group_name} %else: diff --git a/rhodecode/templates/admin/repos/repo_edit_permissions.mako b/rhodecode/templates/admin/repos/repo_edit_permissions.mako --- a/rhodecode/templates/admin/repos/repo_edit_permissions.mako +++ b/rhodecode/templates/admin/repos/repo_edit_permissions.mako @@ -85,7 +85,7 @@ %if h.HasPermissionAny('hg.admin')(): - + ${_user_group.users_group_name} %else: diff --git a/rhodecode/templates/admin/user_groups/user_group_add.mako b/rhodecode/templates/admin/user_groups/user_group_add.mako --- a/rhodecode/templates/admin/user_groups/user_group_add.mako +++ b/rhodecode/templates/admin/user_groups/user_group_add.mako @@ -10,7 +10,7 @@ <%def name="breadcrumbs_links()"> ${h.link_to(_('Admin'),h.route_path('admin_home'))} » - ${h.link_to(_('User groups'),h.url('users_groups'))} + ${h.link_to(_('User groups'),h.route_path('user_groups'))} » ${_('Add User Group')} @@ -26,7 +26,7 @@ ${self.breadcrumbs()} - ${h.secure_form(h.url('users_groups'))} + ${h.secure_form(h.route_path('user_groups_create'), method='POST', request=request)}
diff --git a/rhodecode/templates/admin/user_groups/user_group_edit.mako b/rhodecode/templates/admin/user_groups/user_group_edit.mako --- a/rhodecode/templates/admin/user_groups/user_group_edit.mako +++ b/rhodecode/templates/admin/user_groups/user_group_edit.mako @@ -11,7 +11,7 @@ <%def name="breadcrumbs_links()"> ${h.link_to(_('Admin'),h.route_path('admin_home'))} » - ${h.link_to(_('User Groups'),h.url('users_groups'))} + ${h.link_to(_('User Groups'),h.route_path('user_groups'))} » ${c.user_group.users_group_name} @@ -30,10 +30,10 @@