diff --git a/rhodecode/apps/repository/__init__.py b/rhodecode/apps/repository/__init__.py
--- a/rhodecode/apps/repository/__init__.py
+++ b/rhodecode/apps/repository/__init__.py
@@ -31,6 +31,11 @@ def includeme(config):
name='edit_repo_caches',
pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True)
+ # Permissions
+ config.add_route(
+ name='edit_repo_perms',
+ pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
+
# Repo Review Rules
config.add_route(
name='repo_reviewers',
diff --git a/rhodecode/apps/repository/tests/test_repo_settings.py b/rhodecode/apps/repository/tests/test_repo_settings.py
--- a/rhodecode/apps/repository/tests/test_repo_settings.py
+++ b/rhodecode/apps/repository/tests/test_repo_settings.py
@@ -39,6 +39,7 @@ def route_path(name, params=None, **kwar
base_url = {
'edit_repo': '/{repo_name}/settings',
'edit_repo_caches': '/{repo_name}/settings/caches',
+ 'edit_repo_perms': '/{repo_name}/settings/permissions',
}[name].format(**kwargs)
if params:
@@ -59,7 +60,8 @@ def _get_permission_for_user(user, repo)
class TestAdminRepoSettings(object):
@pytest.mark.parametrize('urlname', [
'edit_repo',
- 'edit_repo_caches'
+ 'edit_repo_caches',
+ 'edit_repo_perms',
])
def test_show_page(self, urlname, app, backend):
app.get(route_path(urlname, repo_name=backend.repo_name), status=200)
@@ -72,7 +74,6 @@ class TestAdminRepoSettings(object):
self.app.get(route_path('edit_repo', repo_name=backend_hg.repo_name))
@pytest.mark.parametrize('urlname', [
- 'edit_repo_perms',
'edit_repo_advanced',
'repo_vcs_settings',
'edit_repo_fields',
diff --git a/rhodecode/apps/repository/views/repo_permissions.py b/rhodecode/apps/repository/views/repo_permissions.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/repository/views/repo_permissions.py
@@ -0,0 +1,98 @@
+# -*- 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/
+
+import logging
+
+import deform
+from pyramid.httpexceptions import HTTPFound
+from pyramid.view import view_config
+
+from rhodecode.apps._base import RepoAppView
+from rhodecode.forms import RcForm
+from rhodecode.lib import helpers as h
+from rhodecode.lib import audit_logger
+from rhodecode.lib.auth import (
+ LoginRequired, HasRepoPermissionAnyDecorator,
+ HasRepoPermissionAllDecorator, CSRFRequired)
+from rhodecode.model.db import RepositoryField, RepoGroup
+from rhodecode.model.forms import RepoPermsForm
+from rhodecode.model.meta import Session
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.scm import RepoGroupList, ScmModel
+from rhodecode.model.validation_schema.schemas import repo_schema
+
+log = logging.getLogger(__name__)
+
+
+class RepoSettingsPermissionsView(RepoAppView):
+
+ def load_default_context(self):
+ c = self._get_local_tmpl_context()
+
+ # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
+ c.repo_info = self.db_repo
+
+ self._register_global_c(c)
+ return c
+
+ @LoginRequired()
+ @HasRepoPermissionAnyDecorator('repository.admin')
+ @view_config(
+ route_name='edit_repo_perms', request_method='GET',
+ renderer='rhodecode:templates/admin/repos/repo_edit.mako')
+ def edit_permissions(self):
+ c = self.load_default_context()
+ c.active = 'permissions'
+ return self._get_template_context(c)
+
+ @LoginRequired()
+ @HasRepoPermissionAllDecorator('repository.admin')
+ @CSRFRequired()
+ @view_config(
+ route_name='edit_repo_perms', request_method='POST',
+ renderer='rhodecode:templates/admin/repos/repo_edit.mako')
+ def edit_permissions_update(self):
+ _ = self.request.translate
+ c = self.load_default_context()
+ c.active = 'permissions'
+ data = self.request.POST
+ # store private flag outside of HTML to verify if we can modify
+ # default user permissions, prevents submition of FAKE post data
+ # into the form for private repos
+ data['repo_private'] = self.db_repo.private
+ form = RepoPermsForm()().to_python(data)
+ changes = RepoModel().update_permissions(
+ self.db_repo_name, form['perm_additions'], form['perm_updates'],
+ form['perm_deletions'])
+
+ action_data = {
+ 'added': changes['added'],
+ 'updated': changes['updated'],
+ 'deleted': changes['deleted'],
+ }
+ audit_logger.store(
+ 'repo.edit.permissions', action_data=action_data,
+ user=self._rhodecode_user, repo=self.db_repo)
+
+ Session().commit()
+ h.flash(_('Repository permissions updated'), category='success')
+
+ raise HTTPFound(
+ self.request.route_path('edit_repo_perms', repo_name=self.db_repo_name))
diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py
--- a/rhodecode/config/routing.py
+++ b/rhodecode/config/routing.py
@@ -661,16 +661,6 @@ def make_map(config):
requirements=URL_NAME_REQUIREMENTS)
# repo edit options
- rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
- jsroute=True,
- controller='admin/repos', action='edit_permissions',
- conditions={'method': ['GET'], 'function': check_repo},
- requirements=URL_NAME_REQUIREMENTS)
- rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
- controller='admin/repos', action='edit_permissions_update',
- conditions={'method': ['PUT'], 'function': check_repo},
- requirements=URL_NAME_REQUIREMENTS)
-
rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
controller='admin/repos', action='edit_fields',
conditions={'method': ['GET'], 'function': check_repo},
diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py
--- a/rhodecode/controllers/admin/repos.py
+++ b/rhodecode/controllers/admin/repos.py
@@ -339,33 +339,6 @@ class ReposController(BaseRepoController
# url('repo', repo_name=ID)
@HasRepoPermissionAllDecorator('repository.admin')
- def edit_permissions(self, repo_name):
- """GET /repo_name/settings: Form to edit an existing item"""
- c.repo_info = self._load_repo(repo_name)
- c.active = 'permissions'
- defaults = RepoModel()._get_defaults(repo_name)
-
- return htmlfill.render(
- render('admin/repos/repo_edit.mako'),
- defaults=defaults,
- encoding="UTF-8",
- force_defaults=False)
-
- @HasRepoPermissionAllDecorator('repository.admin')
- @auth.CSRFRequired()
- def edit_permissions_update(self, repo_name):
- form = RepoPermsForm()().to_python(request.POST)
- RepoModel().update_permissions(repo_name,
- form['perm_additions'], form['perm_updates'], form['perm_deletions'])
-
- #TODO: implement this
- #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions',
- # repo_name, self.ip_addr, self.sa)
- Session().commit()
- h.flash(_('Repository permissions updated'), category='success')
- return redirect(url('edit_repo_perms', repo_name=repo_name))
-
- @HasRepoPermissionAllDecorator('repository.admin')
def edit_fields(self, repo_name):
"""GET /repo_name/settings: Form to edit an existing item"""
c.repo_info = self._load_repo(repo_name)
diff --git a/rhodecode/lib/audit_logger.py b/rhodecode/lib/audit_logger.py
--- a/rhodecode/lib/audit_logger.py
+++ b/rhodecode/lib/audit_logger.py
@@ -36,6 +36,7 @@ ACTIONS = {
'repo.add': {},
'repo.edit': {},
+ 'repo.edit.permissions': {},
'repo.commit.strip': {}
}
diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py
--- a/rhodecode/model/repo.py
+++ b/rhodecode/model/repo.py
@@ -259,7 +259,7 @@ class RepoModel(BaseModel):
defaults = repo_info.get_dict()
defaults['repo_name'] = repo_info.just_name
- groups = repo_info.groups_with_parents
+ groups = repo_info.groups_with_parents
parent_group = groups[-1] if groups else None
# we use -1 as this is how in HTML, we mark an empty group
@@ -295,16 +295,6 @@ class RepoModel(BaseModel):
replacement_user = User.get_first_super_admin().username
defaults.update({'user': replacement_user})
- # fill repository users
- for p in repo_info.repo_to_perm:
- defaults.update({'u_perm_%s' % p.user.user_id:
- p.permission.permission_name})
-
- # fill repository groups
- for p in repo_info.users_group_to_perm:
- defaults.update({'g_perm_%s' % p.users_group.users_group_id:
- p.permission.permission_name})
-
return defaults
def update(self, repo, **kwargs):
@@ -507,10 +497,16 @@ class RepoModel(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 also current one if found
self.grant_user_permission(
repo=repo, user=member_id, perm=perm)
@@ -522,10 +518,14 @@ class RepoModel(BaseModel):
self.grant_user_group_permission(
repo=repo, group_name=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(
repo=repo, user=member_id, perm=perm)
else: # set for user group
@@ -535,11 +535,13 @@ class RepoModel(BaseModel):
*req_perms)(member_name, user=cur_user):
self.grant_user_group_permission(
repo=repo, group_name=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(repo=repo, user=member_id)
else: # set for user group
# check if we have permissions to alter this usergroup
@@ -549,6 +551,10 @@ class RepoModel(BaseModel):
self.revoke_user_group_permission(
repo=repo, group_name=member_id)
+ changes['deleted'].append({'type': member_type, 'id': member_id,
+ 'name': member_name, 'new_perm': perm})
+ return changes
+
def create_fork(self, form_data, cur_user):
"""
Simple wrapper into executing celery task for fork creation
diff --git a/rhodecode/model/validators.py b/rhodecode/model/validators.py
--- a/rhodecode/model/validators.py
+++ b/rhodecode/model/validators.py
@@ -784,7 +784,8 @@ def ValidPerms(type_='repo'):
del_member = perm_dict.get('id')
del_type = perm_dict.get('type')
if del_member and del_type:
- perm_deletions.add((del_member, None, del_type))
+ perm_deletions.add(
+ (del_member, None, del_type))
# store additions in order of how they were added in web form
for k in sorted(new_perms_group.keys()):
@@ -793,36 +794,48 @@ def ValidPerms(type_='repo'):
new_type = perm_dict.get('type')
new_perm = perm_dict.get('perm')
if new_member and new_perm and new_type:
- perm_additions.add((new_member, new_perm, new_type))
+ perm_additions.add(
+ (new_member, new_perm, new_type))
# get updates of permissions
# (read the existing radio button states)
+ default_user_id = User.get_default_user().user_id
for k, update_value in value.iteritems():
if k.startswith('u_perm_') or k.startswith('g_perm_'):
member = k[7:]
update_type = {'u': 'user',
'g': 'users_group'}[k[0]]
- if member == User.DEFAULT_USER:
+
+ if safe_int(member) == default_user_id:
if str2bool(value.get('repo_private')):
- # set none for default when updating to
- # private repo protects agains form manipulation
+ # prevent from updating default user permissions
+ # when this repository is marked as private
update_value = EMPTY_PERM
- perm_updates.add((member, update_value, update_type))
- # check the deletes
- value['perm_additions'] = list(perm_additions)
+ perm_updates.add(
+ (member, update_value, update_type))
+
+ value['perm_additions'] = [] # propagated later
value['perm_updates'] = list(perm_updates)
value['perm_deletions'] = list(perm_deletions)
- # validate users they exist and they are active !
- for member_id, _perm, member_type in perm_additions:
+ updates_map = dict(
+ (x[0], (x[1], x[2])) for x in value['perm_updates'])
+ # make sure Additions don't override updates.
+ for member_id, perm, member_type in list(perm_additions):
+ if member_id in updates_map:
+ perm = updates_map[member_id][0]
+ value['perm_additions'].append((member_id, perm, member_type))
+
+ # on new entries validate users they exist and they are active !
+ # this leaves feedback to the form
try:
if member_type == 'user':
- self.user_db = User.query()\
+ User.query()\
.filter(User.active == true())\
.filter(User.user_id == member_id).one()
if member_type == 'users_group':
- self.user_db = UserGroup.query()\
+ UserGroup.query()\
.filter(UserGroup.users_group_active == true())\
.filter(UserGroup.users_group_id == member_id)\
.one()
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
@@ -24,7 +24,6 @@ function registerRCRoutes() {
pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
- pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
@@ -99,6 +98,7 @@ function registerRCRoutes() {
pyroutes.register('goto_switcher_data', '/_goto_data', []);
pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
+ pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']);
pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']);
diff --git a/rhodecode/templates/admin/repos/repo_edit.mako b/rhodecode/templates/admin/repos/repo_edit.mako
--- a/rhodecode/templates/admin/repos/repo_edit.mako
+++ b/rhodecode/templates/admin/repos/repo_edit.mako
@@ -42,7 +42,7 @@
${_('Settings')}
- ${_('Permissions')}
+ ${_('Permissions')}
${_('Advanced')}
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
@@ -5,8 +5,7 @@
${_('Repository Permissions')}
- ${h.secure_form(url('edit_repo_perms_update', repo_name=c.repo_name), method='put')}
- ${h.hidden('repo_private')}
+ ${h.secure_form(h.route_path('edit_repo_perms', repo_name=c.repo_name), method='POST')}
${_('None')} |
@@ -40,7 +39,7 @@
- ${_('private repository')}
+ ${_('private repository')}
|
@@ -50,10 +49,10 @@
|
%else:
- ${h.radio('u_perm_%s' % _user.user_id,'repository.none')} |
- ${h.radio('u_perm_%s' % _user.user_id,'repository.read')} |
- ${h.radio('u_perm_%s' % _user.user_id,'repository.write')} |
- ${h.radio('u_perm_%s' % _user.user_id,'repository.admin')} |
+ ${h.radio('u_perm_%s' % _user.user_id,'repository.none', checked=_user.permission=='repository.none')} |
+ ${h.radio('u_perm_%s' % _user.user_id,'repository.read', checked=_user.permission=='repository.read')} |
+ ${h.radio('u_perm_%s' % _user.user_id,'repository.write', checked=_user.permission=='repository.write')} |
+ ${h.radio('u_perm_%s' % _user.user_id,'repository.admin', checked=_user.permission=='repository.admin')} |
${base.gravatar(_user.email, 16)}
@@ -79,10 +78,10 @@
## USER GROUPS
%for _user_group in c.repo_info.permission_user_groups():
- ${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.none')} |
- ${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.read')} |
- ${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write')} |
- ${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin')} |
+ ${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.none', checked=_user_group.permission=='repository.none')} |
+ ${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.read', checked=_user_group.permission=='repository.read')} |
+ ${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write', checked=_user_group.permission=='repository.write')} |
+ ${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin', checked=_user_group.permission=='repository.admin')} |
%if h.HasPermissionAny('hg.admin')():
diff --git a/rhodecode/templates/base/perms_summary.mako b/rhodecode/templates/base/perms_summary.mako
--- a/rhodecode/templates/base/perms_summary.mako
+++ b/rhodecode/templates/base/perms_summary.mako
@@ -146,7 +146,7 @@
%if actions:
|
%if section == 'repositories':
- ${_('edit')}
+ ${_('edit')}
%elif section == 'repositories_groups':
${_('edit')}
%elif section == 'user_groups':
| |