repo-groups: moved to pyramid
This commit is contained in:
parent
d702ba605f
commit
69a865a7a3
41 changed files with 1178 additions and 756 deletions
|
|
@ -260,6 +260,20 @@ class RepoGroupAppView(BaseAppView):
|
|||
self.db_repo_group = request.db_repo_group
|
||||
self.db_repo_group_name = self.db_repo_group.group_name
|
||||
|
||||
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 = 'group.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
|
||||
|
||||
|
||||
class UserGroupAppView(BaseAppView):
|
||||
def __init__(self, context, request):
|
||||
|
|
|
|||
|
|
@ -295,6 +295,19 @@ def admin_routes(config):
|
|||
name='repo_create',
|
||||
pattern='/repos/create')
|
||||
|
||||
# repo groups admin
|
||||
config.add_route(
|
||||
name='repo_groups',
|
||||
pattern='/repo_groups')
|
||||
|
||||
config.add_route(
|
||||
name='repo_group_new',
|
||||
pattern='/repo_group/new')
|
||||
|
||||
config.add_route(
|
||||
name='repo_group_create',
|
||||
pattern='/repo_group/create')
|
||||
|
||||
|
||||
def includeme(config):
|
||||
settings = config.get_settings()
|
||||
|
|
|
|||
|
|
@ -19,107 +19,85 @@
|
|||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from rhodecode.apps._base import ADMIN_PREFIX
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.model.db import Repository, UserRepoToPerm, User
|
||||
from rhodecode.model.meta import Session
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.tests import (
|
||||
url, TestController, assert_session_flash, GIT_REPO, HG_REPO,
|
||||
TESTS_TMP_PATH, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
|
||||
assert_session_flash, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH, TestController)
|
||||
from rhodecode.tests.fixture import Fixture
|
||||
|
||||
fixture = Fixture()
|
||||
|
||||
|
||||
def route_path(name, params=None, **kwargs):
|
||||
import urllib
|
||||
|
||||
def test_update(app, csrf_token, autologin_user, user_util):
|
||||
repo_group = user_util.create_repo_group()
|
||||
description = 'description for newly created repo group'
|
||||
Session().commit()
|
||||
response = app.post(
|
||||
url('update_repo_group', group_name=repo_group.group_name),
|
||||
fixture._get_group_create_params(
|
||||
group_name=repo_group.group_name,
|
||||
group_description=description,
|
||||
csrf_token=csrf_token,
|
||||
_method='PUT')
|
||||
)
|
||||
# TODO: anderson: johbo: we believe that this update should return
|
||||
# a redirect instead of rendering the template.
|
||||
assert response.status_code == 200
|
||||
base_url = {
|
||||
'repo_groups': ADMIN_PREFIX + '/repo_groups',
|
||||
'repo_group_new': ADMIN_PREFIX + '/repo_group/new',
|
||||
'repo_group_create': ADMIN_PREFIX + '/repo_group/create',
|
||||
|
||||
}[name].format(**kwargs)
|
||||
|
||||
if params:
|
||||
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
|
||||
return base_url
|
||||
|
||||
|
||||
def test_edit(app, user_util, autologin_user):
|
||||
repo_group = user_util.create_repo_group()
|
||||
Session().commit()
|
||||
response = app.get(
|
||||
url('edit_repo_group', group_name=repo_group.group_name))
|
||||
assert response.status_code == 200
|
||||
def _get_permission_for_user(user, repo):
|
||||
perm = UserRepoToPerm.query()\
|
||||
.filter(UserRepoToPerm.repository ==
|
||||
Repository.get_by_repo_name(repo))\
|
||||
.filter(UserRepoToPerm.user == User.get_by_username(user))\
|
||||
.all()
|
||||
return perm
|
||||
|
||||
|
||||
def test_edit_repo_group_perms(app, user_util, autologin_user):
|
||||
repo_group = user_util.create_repo_group()
|
||||
Session().commit()
|
||||
response = app.get(
|
||||
url('edit_repo_group_perms', group_name=repo_group.group_name))
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_update_fails_when_parent_pointing_to_self(
|
||||
app, csrf_token, user_util, autologin_user):
|
||||
group = user_util.create_repo_group()
|
||||
response = app.post(
|
||||
url('update_repo_group', group_name=group.group_name),
|
||||
fixture._get_group_create_params(
|
||||
group_parent_id=group.group_id,
|
||||
csrf_token=csrf_token,
|
||||
_method='PUT')
|
||||
)
|
||||
response.mustcontain(
|
||||
'<select class="medium error" id="group_parent_id"'
|
||||
' name="group_parent_id">')
|
||||
response.mustcontain('<span class="error-message">Value must be one of:')
|
||||
|
||||
|
||||
class _BaseTest(TestController):
|
||||
|
||||
REPO_GROUP = None
|
||||
NEW_REPO_GROUP = None
|
||||
REPO = None
|
||||
REPO_TYPE = None
|
||||
|
||||
def test_index(self):
|
||||
self.log_user()
|
||||
response = self.app.get(url('repo_groups'))
|
||||
@pytest.mark.usefixtures("app")
|
||||
class TestAdminRepositoryGroups(object):
|
||||
def test_show_repo_groups(self, autologin_user):
|
||||
response = self.app.get(route_path('repo_groups'))
|
||||
response.mustcontain('data: []')
|
||||
|
||||
def test_index_after_creating_group(self):
|
||||
self.log_user()
|
||||
def test_show_repo_groups_after_creating_group(self, autologin_user):
|
||||
fixture.create_repo_group('test_repo_group')
|
||||
response = self.app.get(url('repo_groups'))
|
||||
response = self.app.get(route_path('repo_groups'))
|
||||
response.mustcontain('"name_raw": "test_repo_group"')
|
||||
fixture.destroy_repo_group('test_repo_group')
|
||||
|
||||
def test_new(self):
|
||||
self.log_user()
|
||||
self.app.get(url('new_repo_group'))
|
||||
def test_new(self, autologin_user):
|
||||
self.app.get(route_path('repo_group_new'))
|
||||
|
||||
def test_new_by_regular_user_no_permission(self):
|
||||
self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
|
||||
self.app.get(url('new_repo_group'), status=403)
|
||||
def test_new_with_parent_group(self, autologin_user, user_util):
|
||||
gr = user_util.create_repo_group()
|
||||
|
||||
def test_create(self):
|
||||
self.log_user()
|
||||
repo_group_name = self.NEW_REPO_GROUP
|
||||
self.app.get(route_path('repo_group_new'),
|
||||
params=dict(parent_group=gr.group_name))
|
||||
|
||||
def test_new_by_regular_user_no_permission(self, autologin_regular_user):
|
||||
self.app.get(route_path('repo_group_new'), status=403)
|
||||
|
||||
@pytest.mark.parametrize('repo_group_name', [
|
||||
'git_repo',
|
||||
'git_repo_ąć',
|
||||
'hg_repo',
|
||||
'12345',
|
||||
'hg_repo_ąć',
|
||||
])
|
||||
def test_create(self, autologin_user, repo_group_name, csrf_token):
|
||||
repo_group_name_unicode = repo_group_name.decode('utf8')
|
||||
description = 'description for newly created repo group'
|
||||
|
||||
response = self.app.post(
|
||||
url('repo_groups'),
|
||||
route_path('repo_group_create'),
|
||||
fixture._get_group_create_params(
|
||||
group_name=repo_group_name,
|
||||
group_description=description,
|
||||
csrf_token=self.csrf_token))
|
||||
csrf_token=csrf_token))
|
||||
|
||||
# run the check page that triggers the flash message
|
||||
repo_gr_url = h.route_path(
|
||||
|
|
@ -151,9 +129,14 @@ class _BaseTest(TestController):
|
|||
RepoGroupModel().delete(repo_group_name_unicode)
|
||||
Session().commit()
|
||||
|
||||
def test_create_subgroup(self, user_util):
|
||||
self.log_user()
|
||||
repo_group_name = self.NEW_REPO_GROUP
|
||||
@pytest.mark.parametrize('repo_group_name', [
|
||||
'git_repo',
|
||||
'git_repo_ąć',
|
||||
'hg_repo',
|
||||
'12345',
|
||||
'hg_repo_ąć',
|
||||
])
|
||||
def test_create_subgroup(self, autologin_user, user_util, repo_group_name, csrf_token):
|
||||
parent_group = user_util.create_repo_group()
|
||||
parent_group_name = parent_group.group_name
|
||||
|
||||
|
|
@ -163,65 +146,31 @@ class _BaseTest(TestController):
|
|||
|
||||
try:
|
||||
response = self.app.post(
|
||||
url('repo_groups'),
|
||||
route_path('repo_group_create'),
|
||||
fixture._get_group_create_params(
|
||||
group_name=repo_group_name,
|
||||
group_parent_id=parent_group.group_id,
|
||||
group_description='Test desciption',
|
||||
csrf_token=self.csrf_token))
|
||||
csrf_token=csrf_token))
|
||||
|
||||
assert_session_flash(
|
||||
response,
|
||||
u'Created repository group <a href="%s">%s</a>' % (
|
||||
h.route_path('repo_group_home', repo_group_name=expected_group_name),
|
||||
h.route_path('repo_group_home',
|
||||
repo_group_name=expected_group_name),
|
||||
expected_group_name_unicode))
|
||||
finally:
|
||||
RepoGroupModel().delete(expected_group_name_unicode)
|
||||
Session().commit()
|
||||
|
||||
def test_user_with_creation_permissions_cannot_create_subgroups(
|
||||
self, user_util):
|
||||
self, autologin_regular_user, user_util):
|
||||
|
||||
user_util.grant_user_permission(
|
||||
TEST_USER_REGULAR_LOGIN, 'hg.repogroup.create.true')
|
||||
parent_group = user_util.create_repo_group()
|
||||
parent_group_id = parent_group.group_id
|
||||
self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
|
||||
self.app.get(
|
||||
url('new_repo_group', parent_group=parent_group_id,),
|
||||
route_path('repo_group_new',
|
||||
params=dict(parent_group=parent_group_id), ),
|
||||
status=403)
|
||||
|
||||
|
||||
class TestRepoGroupsControllerGIT(_BaseTest):
|
||||
REPO_GROUP = None
|
||||
NEW_REPO_GROUP = 'git_repo'
|
||||
REPO = GIT_REPO
|
||||
REPO_TYPE = 'git'
|
||||
|
||||
|
||||
class TestRepoGroupsControllerNonAsciiGit(_BaseTest):
|
||||
REPO_GROUP = None
|
||||
NEW_REPO_GROUP = 'git_repo_ąć'
|
||||
REPO = GIT_REPO
|
||||
REPO_TYPE = 'git'
|
||||
|
||||
|
||||
class TestRepoGroupsControllerHG(_BaseTest):
|
||||
REPO_GROUP = None
|
||||
NEW_REPO_GROUP = 'hg_repo'
|
||||
REPO = HG_REPO
|
||||
REPO_TYPE = 'hg'
|
||||
|
||||
|
||||
class TestRepoGroupsControllerNumericalHG(_BaseTest):
|
||||
REPO_GROUP = None
|
||||
NEW_REPO_GROUP = '12345'
|
||||
REPO = HG_REPO
|
||||
REPO_TYPE = 'hg'
|
||||
|
||||
|
||||
class TestRepoGroupsControllerNonAsciiHG(_BaseTest):
|
||||
REPO_GROUP = None
|
||||
NEW_REPO_GROUP = 'hg_repo_ąć'
|
||||
REPO = HG_REPO
|
||||
REPO_TYPE = 'hg'
|
||||
204
rhodecode/apps/admin/views/repo_groups.py
Normal file
204
rhodecode/apps/admin/views/repo_groups.py
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
# -*- 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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 formencode
|
||||
import formencode.htmlfill
|
||||
|
||||
from pyramid.httpexceptions import HTTPFound, HTTPForbidden
|
||||
from pyramid.view import view_config
|
||||
from pyramid.renderers import render
|
||||
from pyramid.response import Response
|
||||
|
||||
from rhodecode.apps._base import BaseAppView, DataGridAppView
|
||||
|
||||
from rhodecode.lib.ext_json import json
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, CSRFRequired, NotAnonymous,
|
||||
HasPermissionAny, HasRepoGroupPermissionAny)
|
||||
from rhodecode.lib import helpers as h, audit_logger
|
||||
from rhodecode.lib.utils2 import safe_int, safe_unicode
|
||||
from rhodecode.model.forms import RepoGroupForm
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.scm import RepoGroupList
|
||||
from rhodecode.model.db import Session, RepoGroup
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AdminRepoGroupsView(BaseAppView, DataGridAppView):
|
||||
|
||||
def load_default_context(self):
|
||||
c = self._get_local_tmpl_context()
|
||||
self._register_global_c(c)
|
||||
return c
|
||||
|
||||
def _load_form_data(self, c):
|
||||
allow_empty_group = False
|
||||
|
||||
if self._can_create_repo_group():
|
||||
# we're global admin, we're ok and we can create TOP level groups
|
||||
allow_empty_group = True
|
||||
|
||||
# override the choices for this form, we need to filter choices
|
||||
# and display only those we have ADMIN right
|
||||
groups_with_admin_rights = RepoGroupList(
|
||||
RepoGroup.query().all(),
|
||||
perm_set=['group.admin'])
|
||||
c.repo_groups = RepoGroup.groups_choices(
|
||||
groups=groups_with_admin_rights,
|
||||
show_empty_group=allow_empty_group)
|
||||
|
||||
def _can_create_repo_group(self, parent_group_id=None):
|
||||
is_admin = HasPermissionAny('hg.admin')('group create controller')
|
||||
create_repo_group = HasPermissionAny(
|
||||
'hg.repogroup.create.true')('group create controller')
|
||||
if is_admin or (create_repo_group and not parent_group_id):
|
||||
# we're global admin, or we have global repo group create
|
||||
# permission
|
||||
# we're ok and we can create TOP level groups
|
||||
return True
|
||||
elif parent_group_id:
|
||||
# we check the permission if we can write to parent group
|
||||
group = RepoGroup.get(parent_group_id)
|
||||
group_name = group.group_name if group else None
|
||||
if HasRepoGroupPermissionAny('group.admin')(
|
||||
group_name, 'check if user is an admin of group'):
|
||||
# we're an admin of passed in group, we're ok.
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
# perms check inside
|
||||
@view_config(
|
||||
route_name='repo_groups', request_method='GET',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_groups.mako')
|
||||
def repo_group_list(self):
|
||||
c = self.load_default_context()
|
||||
|
||||
repo_group_list = RepoGroup.get_all_repo_groups()
|
||||
repo_group_list_acl = RepoGroupList(
|
||||
repo_group_list, perm_set=['group.admin'])
|
||||
repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
|
||||
repo_group_list=repo_group_list_acl, admin=True)
|
||||
c.data = json.dumps(repo_group_data)
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
# perm checks inside
|
||||
@view_config(
|
||||
route_name='repo_group_new', request_method='GET',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_group_add.mako')
|
||||
def repo_group_new(self):
|
||||
c = self.load_default_context()
|
||||
|
||||
# perm check for admin, create_group perm or admin of parent_group
|
||||
parent_group_id = safe_int(self.request.GET.get('parent_group'))
|
||||
if not self._can_create_repo_group(parent_group_id):
|
||||
raise HTTPForbidden()
|
||||
|
||||
self._load_form_data(c)
|
||||
|
||||
defaults = {} # Future proof for default of repo group
|
||||
data = render(
|
||||
'rhodecode:templates/admin/repo_groups/repo_group_add.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()
|
||||
@NotAnonymous()
|
||||
@CSRFRequired()
|
||||
# perm checks inside
|
||||
@view_config(
|
||||
route_name='repo_group_create', request_method='POST',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_group_add.mako')
|
||||
def repo_group_create(self):
|
||||
c = self.load_default_context()
|
||||
_ = self.request.translate
|
||||
|
||||
parent_group_id = safe_int(self.request.POST.get('group_parent_id'))
|
||||
can_create = self._can_create_repo_group(parent_group_id)
|
||||
|
||||
self._load_form_data(c)
|
||||
# permissions for can create group based on parent_id are checked
|
||||
# here in the Form
|
||||
available_groups = map(lambda k: safe_unicode(k[0]), c.repo_groups)
|
||||
repo_group_form = RepoGroupForm(available_groups=available_groups,
|
||||
can_create_in_root=can_create)()
|
||||
|
||||
repo_group_name = self.request.POST.get('group_name')
|
||||
try:
|
||||
owner = self._rhodecode_user
|
||||
form_result = repo_group_form.to_python(dict(self.request.POST))
|
||||
repo_group = RepoGroupModel().create(
|
||||
group_name=form_result['group_name_full'],
|
||||
group_description=form_result['group_description'],
|
||||
owner=owner.user_id,
|
||||
copy_permissions=form_result['group_copy_permissions']
|
||||
)
|
||||
Session().flush()
|
||||
|
||||
repo_group_data = repo_group.get_api_data()
|
||||
audit_logger.store_web(
|
||||
'repo_group.create', action_data={'data': repo_group_data},
|
||||
user=self._rhodecode_user)
|
||||
|
||||
Session().commit()
|
||||
|
||||
_new_group_name = form_result['group_name_full']
|
||||
|
||||
repo_group_url = h.link_to(
|
||||
_new_group_name,
|
||||
h.route_path('repo_group_home', repo_group_name=_new_group_name))
|
||||
h.flash(h.literal(_('Created repository group %s')
|
||||
% repo_group_url), category='success')
|
||||
|
||||
except formencode.Invalid as errors:
|
||||
data = render(
|
||||
'rhodecode:templates/admin/repo_groups/repo_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 during creation of repository group")
|
||||
h.flash(_('Error occurred during creation of repository group %s')
|
||||
% repo_group_name, category='error')
|
||||
raise HTTPFound(h.route_path('home'))
|
||||
|
||||
raise HTTPFound(
|
||||
h.route_path('repo_group_home',
|
||||
repo_group_name=form_result['group_name_full']))
|
||||
|
|
@ -22,7 +22,36 @@ from rhodecode.apps._base import add_route_with_slash
|
|||
|
||||
def includeme(config):
|
||||
|
||||
# Summary
|
||||
# Settings
|
||||
config.add_route(
|
||||
name='edit_repo_group',
|
||||
pattern='/{repo_group_name:.*?[^/]}/_edit',
|
||||
repo_group_route=True)
|
||||
# update is POST on edit_repo_group
|
||||
|
||||
# Settings advanced
|
||||
config.add_route(
|
||||
name='edit_repo_group_advanced',
|
||||
pattern='/{repo_group_name:.*?[^/]}/_settings/advanced',
|
||||
repo_group_route=True)
|
||||
|
||||
config.add_route(
|
||||
name='edit_repo_group_advanced_delete',
|
||||
pattern='/{repo_group_name:.*?[^/]}/_settings/advanced/delete',
|
||||
repo_group_route=True)
|
||||
|
||||
# settings permissions
|
||||
config.add_route(
|
||||
name='edit_repo_group_perms',
|
||||
pattern='/{repo_group_name:.*?[^/]}/_settings/permissions',
|
||||
repo_group_route=True)
|
||||
|
||||
config.add_route(
|
||||
name='edit_repo_group_perms_update',
|
||||
pattern='/{repo_group_name:.*?[^/]}/_settings/permissions/update',
|
||||
repo_group_route=True)
|
||||
|
||||
# Summary, NOTE(marcink): needs to be at the end for catch-all
|
||||
add_route_with_slash(
|
||||
config,
|
||||
name='repo_group_home',
|
||||
|
|
@ -30,4 +59,3 @@ def includeme(config):
|
|||
|
||||
# Scan module for configuration decorators.
|
||||
config.scan('.views', ignore='.tests')
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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/
|
||||
89
rhodecode/apps/repo_group/tests/test_repo_groups_advanced.py
Normal file
89
rhodecode/apps/repo_group/tests/test_repo_groups_advanced.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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 pytest
|
||||
|
||||
from rhodecode.tests import assert_session_flash
|
||||
|
||||
|
||||
def route_path(name, params=None, **kwargs):
|
||||
import urllib
|
||||
|
||||
base_url = {
|
||||
'edit_repo_group_advanced':
|
||||
'/{repo_group_name}/_settings/advanced',
|
||||
'edit_repo_group_advanced_delete':
|
||||
'/{repo_group_name}/_settings/advanced/delete',
|
||||
}[name].format(**kwargs)
|
||||
|
||||
if params:
|
||||
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
|
||||
return base_url
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("app")
|
||||
class TestRepoGroupsAdvancedView(object):
|
||||
|
||||
@pytest.mark.parametrize('repo_group_name', [
|
||||
'gro',
|
||||
'12345',
|
||||
])
|
||||
def test_show_advanced_settings(self, autologin_user, user_util, repo_group_name):
|
||||
user_util._test_name = repo_group_name
|
||||
gr = user_util.create_repo_group()
|
||||
self.app.get(
|
||||
route_path('edit_repo_group_advanced',
|
||||
repo_group_name=gr.group_name))
|
||||
|
||||
def test_show_advanced_settings_delete(self, autologin_user, user_util,
|
||||
csrf_token):
|
||||
gr = user_util.create_repo_group(auto_cleanup=False)
|
||||
repo_group_name = gr.group_name
|
||||
|
||||
params = dict(
|
||||
csrf_token=csrf_token
|
||||
)
|
||||
response = self.app.post(
|
||||
route_path('edit_repo_group_advanced_delete',
|
||||
repo_group_name=repo_group_name), params=params)
|
||||
assert_session_flash(
|
||||
response, 'Removed repository group `{}`'.format(repo_group_name))
|
||||
|
||||
def test_delete_not_possible_with_objects_inside(self, autologin_user,
|
||||
repo_groups, csrf_token):
|
||||
zombie_group, parent_group, child_group = repo_groups
|
||||
|
||||
response = self.app.get(
|
||||
route_path('edit_repo_group_advanced',
|
||||
repo_group_name=parent_group.group_name))
|
||||
|
||||
response.mustcontain(
|
||||
'This repository group includes 1 children repository group')
|
||||
|
||||
params = dict(
|
||||
csrf_token=csrf_token
|
||||
)
|
||||
response = self.app.post(
|
||||
route_path('edit_repo_group_advanced_delete',
|
||||
repo_group_name=parent_group.group_name), params=params)
|
||||
|
||||
assert_session_flash(
|
||||
response, 'This repository group contains 1 subgroup '
|
||||
'and cannot be deleted')
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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 pytest
|
||||
|
||||
|
||||
def route_path(name, params=None, **kwargs):
|
||||
import urllib
|
||||
|
||||
base_url = {
|
||||
'edit_repo_group_perms':
|
||||
'/{repo_group_name:}/_settings/permissions',
|
||||
'edit_repo_group_perms_update':
|
||||
'/{repo_group_name}/_settings/permissions/update',
|
||||
}[name].format(**kwargs)
|
||||
|
||||
if params:
|
||||
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
|
||||
return base_url
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("app")
|
||||
class TestRepoGroupsPermissionsView(object):
|
||||
|
||||
def test_edit_repo_group_perms(self, user_util, autologin_user):
|
||||
repo_group = user_util.create_repo_group()
|
||||
self.app.get(
|
||||
route_path('edit_repo_group_perms',
|
||||
repo_group_name=repo_group.group_name), status=200)
|
||||
|
||||
def test_update_permissions(self):
|
||||
pass
|
||||
90
rhodecode/apps/repo_group/tests/test_repo_groups_settings.py
Normal file
90
rhodecode/apps/repo_group/tests/test_repo_groups_settings.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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 pytest
|
||||
|
||||
from rhodecode.tests import assert_session_flash
|
||||
|
||||
|
||||
def route_path(name, params=None, **kwargs):
|
||||
import urllib
|
||||
|
||||
base_url = {
|
||||
'edit_repo_group': '/{repo_group_name}/_edit',
|
||||
# Update is POST to the above url
|
||||
}[name].format(**kwargs)
|
||||
|
||||
if params:
|
||||
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
|
||||
return base_url
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("app")
|
||||
class TestRepoGroupsSettingsView(object):
|
||||
|
||||
@pytest.mark.parametrize('repo_group_name', [
|
||||
'gro',
|
||||
u'12345',
|
||||
])
|
||||
def test_edit(self, user_util, autologin_user, repo_group_name):
|
||||
user_util._test_name = repo_group_name
|
||||
repo_group = user_util.create_repo_group()
|
||||
|
||||
self.app.get(
|
||||
route_path('edit_repo_group', repo_group_name=repo_group.group_name),
|
||||
status=200)
|
||||
|
||||
def test_update(self, csrf_token, autologin_user, user_util, rc_fixture):
|
||||
repo_group = user_util.create_repo_group()
|
||||
repo_group_name = repo_group.group_name
|
||||
|
||||
description = 'description for newly created repo group'
|
||||
form_data = rc_fixture._get_group_create_params(
|
||||
group_name=repo_group.group_name,
|
||||
group_description=description,
|
||||
csrf_token=csrf_token,
|
||||
repo_group_name=repo_group.group_name,
|
||||
repo_group_owner=repo_group.user.username)
|
||||
|
||||
response = self.app.post(
|
||||
route_path('edit_repo_group',
|
||||
repo_group_name=repo_group.group_name),
|
||||
form_data,
|
||||
status=302)
|
||||
|
||||
assert_session_flash(
|
||||
response, 'Repository Group `{}` updated successfully'.format(
|
||||
repo_group_name))
|
||||
|
||||
def test_update_fails_when_parent_pointing_to_self(
|
||||
self, csrf_token, user_util, autologin_user, rc_fixture):
|
||||
group = user_util.create_repo_group()
|
||||
response = self.app.post(
|
||||
route_path('edit_repo_group', repo_group_name=group.group_name),
|
||||
rc_fixture._get_group_create_params(
|
||||
repo_group_name=group.group_name,
|
||||
repo_group_owner=group.user.username,
|
||||
repo_group=group.group_id,
|
||||
csrf_token=csrf_token),
|
||||
status=200
|
||||
)
|
||||
response.mustcontain(
|
||||
'<span class="error-message">"{}" is not one of -1'.format(
|
||||
group.group_id))
|
||||
105
rhodecode/apps/repo_group/views/repo_group_advanced.py
Normal file
105
rhodecode/apps/repo_group/views/repo_group_advanced.py
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# -*- 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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
|
||||
|
||||
from pyramid.view import view_config
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
|
||||
from rhodecode.apps._base import RepoGroupAppView
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.lib import audit_logger
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, CSRFRequired, HasRepoGroupPermissionAnyDecorator)
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.meta import Session
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RepoGroupSettingsView(RepoGroupAppView):
|
||||
def load_default_context(self):
|
||||
c = self._get_local_tmpl_context()
|
||||
self._register_global_c(c)
|
||||
return c
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
@view_config(
|
||||
route_name='edit_repo_group_advanced', request_method='GET',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
|
||||
def edit_repo_group_advanced(self):
|
||||
c = self.load_default_context()
|
||||
c.active = 'advanced'
|
||||
c.repo_group = self.db_repo_group
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
@CSRFRequired()
|
||||
@view_config(
|
||||
route_name='edit_repo_group_advanced_delete', request_method='POST',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
|
||||
def edit_repo_group_delete(self):
|
||||
_ = self.request.translate
|
||||
_ungettext = self.request.plularize
|
||||
c = self.load_default_context()
|
||||
c.repo_group = self.db_repo_group
|
||||
|
||||
repos = c.repo_group.repositories.all()
|
||||
if repos:
|
||||
msg = _ungettext(
|
||||
'This repository group contains %(num)d repository and cannot be deleted',
|
||||
'This repository group contains %(num)d repositories and cannot be'
|
||||
' deleted',
|
||||
len(repos)) % {'num': len(repos)}
|
||||
h.flash(msg, category='warning')
|
||||
raise HTTPFound(
|
||||
h.route_path('edit_repo_group_advanced',
|
||||
repo_group_name=self.db_repo_group_name))
|
||||
|
||||
children = c.repo_group.children.all()
|
||||
if children:
|
||||
msg = _ungettext(
|
||||
'This repository group contains %(num)d subgroup and cannot be deleted',
|
||||
'This repository group contains %(num)d subgroups and cannot be deleted',
|
||||
len(children)) % {'num': len(children)}
|
||||
h.flash(msg, category='warning')
|
||||
raise HTTPFound(
|
||||
h.route_path('edit_repo_group_advanced',
|
||||
repo_group_name=self.db_repo_group_name))
|
||||
|
||||
try:
|
||||
old_values = c.repo_group.get_api_data()
|
||||
RepoGroupModel().delete(self.db_repo_group_name)
|
||||
|
||||
audit_logger.store_web(
|
||||
'repo_group.delete', action_data={'old_data': old_values},
|
||||
user=c.rhodecode_user)
|
||||
|
||||
Session().commit()
|
||||
h.flash(_('Removed repository group `%s`') % self.db_repo_group_name,
|
||||
category='success')
|
||||
except Exception:
|
||||
log.exception("Exception during deletion of repository group")
|
||||
h.flash(_('Error occurred during deletion of repository group %s')
|
||||
% self.db_repo_group_name, category='error')
|
||||
|
||||
raise HTTPFound(h.route_path('repo_groups'))
|
||||
100
rhodecode/apps/repo_group/views/repo_group_permissions.py
Normal file
100
rhodecode/apps/repo_group/views/repo_group_permissions.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
# -*- 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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
|
||||
|
||||
from pyramid.view import view_config
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
|
||||
from rhodecode.apps._base import RepoGroupAppView
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.lib import audit_logger
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.forms import RepoGroupPermsForm
|
||||
from rhodecode.model.meta import Session
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RepoGroupPermissionsView(RepoGroupAppView):
|
||||
def load_default_context(self):
|
||||
c = self._get_local_tmpl_context()
|
||||
self._register_global_c(c)
|
||||
return c
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
@view_config(
|
||||
route_name='edit_repo_group_perms', request_method='GET',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
|
||||
def edit_repo_group_permissions(self):
|
||||
c = self.load_default_context()
|
||||
c.active = 'permissions'
|
||||
c.repo_group = self.db_repo_group
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
@CSRFRequired()
|
||||
@view_config(
|
||||
route_name='edit_repo_group_perms_update', request_method='POST',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
|
||||
def edit_repo_groups_permissions_update(self):
|
||||
_ = self.request.translate
|
||||
c = self.load_default_context()
|
||||
c.active = 'perms'
|
||||
c.repo_group = self.db_repo_group
|
||||
|
||||
valid_recursive_choices = ['none', 'repos', 'groups', 'all']
|
||||
form = RepoGroupPermsForm(valid_recursive_choices)()\
|
||||
.to_python(self.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')
|
||||
raise HTTPFound(
|
||||
h.route_path('edit_repo_group_perms',
|
||||
group_name=self.db_repo_group_name))
|
||||
|
||||
# iterate over all members(if in recursive mode) of this groups and
|
||||
# set the permissions !
|
||||
# this can be potentially heavy operation
|
||||
changes = RepoGroupModel().update_permissions(
|
||||
c.repo_group,
|
||||
form['perm_additions'], form['perm_updates'], form['perm_deletions'],
|
||||
form['recursive'])
|
||||
|
||||
action_data = {
|
||||
'added': changes['added'],
|
||||
'updated': changes['updated'],
|
||||
'deleted': changes['deleted'],
|
||||
}
|
||||
audit_logger.store_web(
|
||||
'repo_group.edit.permissions', action_data=action_data,
|
||||
user=c.rhodecode_user)
|
||||
|
||||
Session().commit()
|
||||
h.flash(_('Repository Group permissions updated'), category='success')
|
||||
raise HTTPFound(
|
||||
h.route_path('edit_repo_group_perms',
|
||||
repo_group_name=self.db_repo_group_name))
|
||||
183
rhodecode/apps/repo_group/views/repo_group_settings.py
Normal file
183
rhodecode/apps/repo_group/views/repo_group_settings.py
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
# -*- 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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.view import view_config
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
|
||||
from rhodecode.apps._base import RepoGroupAppView
|
||||
from rhodecode.forms import RcForm
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.lib import audit_logger
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, HasPermissionAll,
|
||||
HasRepoGroupPermissionAny, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
|
||||
from rhodecode.model.db import Session, RepoGroup
|
||||
from rhodecode.model.scm import RepoGroupList
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.validation_schema.schemas import repo_group_schema
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RepoGroupSettingsView(RepoGroupAppView):
|
||||
def load_default_context(self):
|
||||
c = self._get_local_tmpl_context()
|
||||
c.repo_group = self.db_repo_group
|
||||
no_parrent = not c.repo_group.parent_group
|
||||
can_create_in_root = self._can_create_repo_group()
|
||||
|
||||
show_root_location = False
|
||||
if no_parrent or can_create_in_root:
|
||||
# we're global admin, we're ok and we can create TOP level groups
|
||||
# or in case this group is already at top-level we also allow
|
||||
# creation in root
|
||||
show_root_location = True
|
||||
|
||||
acl_groups = RepoGroupList(
|
||||
RepoGroup.query().all(),
|
||||
perm_set=['group.admin'])
|
||||
c.repo_groups = RepoGroup.groups_choices(
|
||||
groups=acl_groups,
|
||||
show_empty_group=show_root_location)
|
||||
# filter out current repo group
|
||||
exclude_group_ids = [c.repo_group.group_id]
|
||||
c.repo_groups = filter(lambda x: x[0] not in exclude_group_ids,
|
||||
c.repo_groups)
|
||||
c.repo_groups_choices = map(lambda k: k[0], c.repo_groups)
|
||||
|
||||
parent_group = c.repo_group.parent_group
|
||||
|
||||
add_parent_group = (parent_group and (
|
||||
parent_group.group_id not in c.repo_groups_choices))
|
||||
if add_parent_group:
|
||||
c.repo_groups_choices.append(parent_group.group_id)
|
||||
c.repo_groups.append(RepoGroup._generate_choice(parent_group))
|
||||
|
||||
self._register_global_c(c)
|
||||
return c
|
||||
|
||||
def _can_create_repo_group(self, parent_group_id=None):
|
||||
is_admin = HasPermissionAll('hg.admin')('group create controller')
|
||||
create_repo_group = HasPermissionAll(
|
||||
'hg.repogroup.create.true')('group create controller')
|
||||
if is_admin or (create_repo_group and not parent_group_id):
|
||||
# we're global admin, or we have global repo group create
|
||||
# permission
|
||||
# we're ok and we can create TOP level groups
|
||||
return True
|
||||
elif parent_group_id:
|
||||
# we check the permission if we can write to parent group
|
||||
group = RepoGroup.get(parent_group_id)
|
||||
group_name = group.group_name if group else None
|
||||
if HasRepoGroupPermissionAny('group.admin')(
|
||||
group_name, 'check if user is an admin of group'):
|
||||
# we're an admin of passed in group, we're ok.
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
def _get_schema(self, c, old_values=None):
|
||||
return repo_group_schema.RepoGroupSettingsSchema().bind(
|
||||
repo_group_repo_group_options=c.repo_groups_choices,
|
||||
repo_group_repo_group_items=c.repo_groups,
|
||||
|
||||
# user caller
|
||||
user=self._rhodecode_user,
|
||||
old_values=old_values
|
||||
)
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
@view_config(
|
||||
route_name='edit_repo_group', request_method='GET',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
|
||||
def edit_settings(self):
|
||||
c = self.load_default_context()
|
||||
c.active = 'settings'
|
||||
|
||||
defaults = RepoGroupModel()._get_defaults(self.db_repo_group_name)
|
||||
defaults['repo_group_owner'] = defaults['user']
|
||||
|
||||
schema = self._get_schema(c)
|
||||
c.form = RcForm(schema, appstruct=defaults)
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
@CSRFRequired()
|
||||
@view_config(
|
||||
route_name='edit_repo_group', request_method='POST',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
|
||||
def edit_settings_update(self):
|
||||
_ = self.request.translate
|
||||
c = self.load_default_context()
|
||||
c.active = 'settings'
|
||||
|
||||
old_repo_group_name = self.db_repo_group_name
|
||||
new_repo_group_name = old_repo_group_name
|
||||
|
||||
old_values = RepoGroupModel()._get_defaults(self.db_repo_group_name)
|
||||
schema = self._get_schema(c, old_values=old_values)
|
||||
|
||||
c.form = RcForm(schema)
|
||||
pstruct = self.request.POST.items()
|
||||
|
||||
try:
|
||||
schema_data = c.form.validate(pstruct)
|
||||
except deform.ValidationFailure as err_form:
|
||||
return self._get_template_context(c)
|
||||
|
||||
# data is now VALID, proceed with updates
|
||||
# save validated data back into the updates dict
|
||||
validated_updates = dict(
|
||||
group_name=schema_data['repo_group']['repo_group_name_without_group'],
|
||||
group_parent_id=schema_data['repo_group']['repo_group_id'],
|
||||
user=schema_data['repo_group_owner'],
|
||||
group_description=schema_data['repo_group_description'],
|
||||
enable_locking=schema_data['repo_group_enable_locking'],
|
||||
)
|
||||
|
||||
try:
|
||||
RepoGroupModel().update(self.db_repo_group, validated_updates)
|
||||
|
||||
audit_logger.store_web(
|
||||
'repo_group.edit', action_data={'old_data': old_values},
|
||||
user=c.rhodecode_user)
|
||||
|
||||
Session().commit()
|
||||
|
||||
# use the new full name for redirect once we know we updated
|
||||
# the name on filesystem and in DB
|
||||
new_repo_group_name = schema_data['repo_group_name']
|
||||
|
||||
h.flash(_('Repository Group `{}` updated successfully').format(
|
||||
old_repo_group_name), category='success')
|
||||
|
||||
except Exception:
|
||||
log.exception("Exception during update or repository group")
|
||||
h.flash(_('Error occurred during update of repository group %s')
|
||||
% old_repo_group_name, category='error')
|
||||
|
||||
raise HTTPFound(
|
||||
h.route_path('edit_repo_group', repo_group_name=new_repo_group_name))
|
||||
|
|
@ -312,6 +312,7 @@ def includeme(config):
|
|||
config.add_route(
|
||||
name='edit_repo',
|
||||
pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
|
||||
# update is POST on edit_repo
|
||||
|
||||
# Settings advanced
|
||||
config.add_route(
|
||||
|
|
@ -373,7 +374,6 @@ def includeme(config):
|
|||
name='edit_repo_remote_pull',
|
||||
pattern='/{repo_name:.*?[^/]}/settings/remote/pull', repo_route=True)
|
||||
|
||||
|
||||
# Statistics
|
||||
config.add_route(
|
||||
name='edit_repo_statistics',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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/
|
||||
|
|
@ -197,7 +197,7 @@ class TestAdminRepoSettings(object):
|
|||
|
||||
assert_session_flash(
|
||||
response,
|
||||
msg='Repository %s updated successfully' % (backend.repo_name))
|
||||
msg='Repository `%s` updated successfully' % (backend.repo_name))
|
||||
|
||||
repo = Repository.get_by_repo_name(backend.repo_name)
|
||||
assert repo.private is True
|
||||
|
|
@ -218,7 +218,7 @@ class TestAdminRepoSettings(object):
|
|||
|
||||
assert_session_flash(
|
||||
response,
|
||||
msg='Repository %s updated successfully' % (backend.repo_name))
|
||||
msg='Repository `%s` updated successfully' % (backend.repo_name))
|
||||
assert backend.repo.private is False
|
||||
|
||||
# we turn off private now the repo default permission should stay None
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ class RepoSettingsView(RepoAppView):
|
|||
|
||||
Session().commit()
|
||||
|
||||
h.flash(_('Repository {} updated successfully').format(
|
||||
h.flash(_('Repository `{}` updated successfully').format(
|
||||
old_repo_name), category='success')
|
||||
except Exception:
|
||||
log.exception("Exception during update of repository")
|
||||
|
|
|
|||
|
|
@ -172,53 +172,6 @@ def make_map(config):
|
|||
# CUSTOM ROUTES HERE
|
||||
#==========================================================================
|
||||
|
||||
# ADMIN REPOSITORY GROUPS ROUTES
|
||||
with rmap.submapper(path_prefix=ADMIN_PREFIX,
|
||||
controller='admin/repo_groups') as m:
|
||||
m.connect('repo_groups', '/repo_groups',
|
||||
action='create', conditions={'method': ['POST']})
|
||||
m.connect('repo_groups', '/repo_groups',
|
||||
action='index', conditions={'method': ['GET']})
|
||||
m.connect('new_repo_group', '/repo_groups/new',
|
||||
action='new', conditions={'method': ['GET']})
|
||||
m.connect('update_repo_group', '/repo_groups/{group_name}',
|
||||
action='update', conditions={'method': ['PUT'],
|
||||
'function': check_group},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
# EXTRAS REPO GROUP ROUTES
|
||||
m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
|
||||
action='edit',
|
||||
conditions={'method': ['GET'], 'function': check_group},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
|
||||
action='edit',
|
||||
conditions={'method': ['PUT'], 'function': check_group},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
|
||||
action='edit_repo_group_advanced',
|
||||
conditions={'method': ['GET'], 'function': check_group},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
|
||||
action='edit_repo_group_advanced',
|
||||
conditions={'method': ['PUT'], 'function': check_group},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
|
||||
action='edit_repo_group_perms',
|
||||
conditions={'method': ['GET'], 'function': check_group},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
|
||||
action='update_perms',
|
||||
conditions={'method': ['PUT'], 'function': check_group},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
m.connect('delete_repo_group', '/repo_groups/{group_name}',
|
||||
action='delete', conditions={'method': ['DELETE'],
|
||||
'function': check_group},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
# ADMIN SETTINGS ROUTES
|
||||
with rmap.submapper(path_prefix=ADMIN_PREFIX,
|
||||
controller='admin/settings') as m:
|
||||
|
|
|
|||
|
|
@ -1,405 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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/
|
||||
|
||||
|
||||
"""
|
||||
Repository groups controller for RhodeCode
|
||||
"""
|
||||
|
||||
import logging
|
||||
import formencode
|
||||
|
||||
from formencode import htmlfill
|
||||
|
||||
from pylons import request, tmpl_context as c, url
|
||||
from pylons.controllers.util import abort, redirect
|
||||
from pylons.i18n.translation import _, ungettext
|
||||
|
||||
from rhodecode.lib import auth
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.lib import audit_logger
|
||||
from rhodecode.lib.ext_json import json
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, NotAnonymous, HasPermissionAll,
|
||||
HasRepoGroupPermissionAll, HasRepoGroupPermissionAnyDecorator)
|
||||
from rhodecode.lib.base import BaseController, render
|
||||
from rhodecode.lib.utils2 import safe_int
|
||||
from rhodecode.model.db import RepoGroup, User
|
||||
from rhodecode.model.scm import RepoGroupList
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.forms import RepoGroupForm, RepoGroupPermsForm
|
||||
from rhodecode.model.meta import Session
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RepoGroupsController(BaseController):
|
||||
"""REST Controller styled on the Atom Publishing Protocol"""
|
||||
|
||||
@LoginRequired()
|
||||
def __before__(self):
|
||||
super(RepoGroupsController, self).__before__()
|
||||
|
||||
def __load_defaults(self, allow_empty_group=False, repo_group=None):
|
||||
if self._can_create_repo_group():
|
||||
# we're global admin, we're ok and we can create TOP level groups
|
||||
allow_empty_group = True
|
||||
|
||||
# override the choices for this form, we need to filter choices
|
||||
# and display only those we have ADMIN right
|
||||
groups_with_admin_rights = RepoGroupList(
|
||||
RepoGroup.query().all(),
|
||||
perm_set=['group.admin'])
|
||||
c.repo_groups = RepoGroup.groups_choices(
|
||||
groups=groups_with_admin_rights,
|
||||
show_empty_group=allow_empty_group)
|
||||
|
||||
if repo_group:
|
||||
# exclude filtered ids
|
||||
exclude_group_ids = [repo_group.group_id]
|
||||
c.repo_groups = filter(lambda x: x[0] not in exclude_group_ids,
|
||||
c.repo_groups)
|
||||
c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
|
||||
parent_group = repo_group.parent_group
|
||||
|
||||
add_parent_group = (parent_group and (
|
||||
unicode(parent_group.group_id) not in c.repo_groups_choices))
|
||||
if add_parent_group:
|
||||
c.repo_groups_choices.append(unicode(parent_group.group_id))
|
||||
c.repo_groups.append(RepoGroup._generate_choice(parent_group))
|
||||
|
||||
def __load_data(self, group_id):
|
||||
"""
|
||||
Load defaults settings for edit, and update
|
||||
|
||||
:param group_id:
|
||||
"""
|
||||
repo_group = RepoGroup.get_or_404(group_id)
|
||||
data = repo_group.get_dict()
|
||||
data['group_name'] = repo_group.name
|
||||
|
||||
# fill owner
|
||||
if repo_group.user:
|
||||
data.update({'user': repo_group.user.username})
|
||||
else:
|
||||
replacement_user = User.get_first_super_admin().username
|
||||
data.update({'user': replacement_user})
|
||||
|
||||
# fill repository group users
|
||||
for p in repo_group.repo_group_to_perm:
|
||||
data.update({
|
||||
'u_perm_%s' % p.user.user_id: p.permission.permission_name})
|
||||
|
||||
# fill repository group user groups
|
||||
for p in repo_group.users_group_to_perm:
|
||||
data.update({
|
||||
'g_perm_%s' % p.users_group.users_group_id:
|
||||
p.permission.permission_name})
|
||||
# html and form expects -1 as empty parent group
|
||||
data['group_parent_id'] = data['group_parent_id'] or -1
|
||||
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 = 'group.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
|
||||
|
||||
def _can_create_repo_group(self, parent_group_id=None):
|
||||
is_admin = HasPermissionAll('hg.admin')('group create controller')
|
||||
create_repo_group = HasPermissionAll(
|
||||
'hg.repogroup.create.true')('group create controller')
|
||||
if is_admin or (create_repo_group and not parent_group_id):
|
||||
# we're global admin, or we have global repo group create
|
||||
# permission
|
||||
# we're ok and we can create TOP level groups
|
||||
return True
|
||||
elif parent_group_id:
|
||||
# we check the permission if we can write to parent group
|
||||
group = RepoGroup.get(parent_group_id)
|
||||
group_name = group.group_name if group else None
|
||||
if HasRepoGroupPermissionAll('group.admin')(
|
||||
group_name, 'check if user is an admin of group'):
|
||||
# we're an admin of passed in group, we're ok.
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
@NotAnonymous()
|
||||
def index(self):
|
||||
repo_group_list = RepoGroup.get_all_repo_groups()
|
||||
_perms = ['group.admin']
|
||||
repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms)
|
||||
repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
|
||||
repo_group_list=repo_group_list_acl, admin=True)
|
||||
c.data = json.dumps(repo_group_data)
|
||||
return render('admin/repo_groups/repo_groups.mako')
|
||||
|
||||
# perm checks inside
|
||||
@NotAnonymous()
|
||||
@auth.CSRFRequired()
|
||||
def create(self):
|
||||
|
||||
parent_group_id = safe_int(request.POST.get('group_parent_id'))
|
||||
can_create = self._can_create_repo_group(parent_group_id)
|
||||
|
||||
self.__load_defaults()
|
||||
# permissions for can create group based on parent_id are checked
|
||||
# here in the Form
|
||||
available_groups = map(lambda k: unicode(k[0]), c.repo_groups)
|
||||
repo_group_form = RepoGroupForm(available_groups=available_groups,
|
||||
can_create_in_root=can_create)()
|
||||
try:
|
||||
owner = c.rhodecode_user
|
||||
form_result = repo_group_form.to_python(dict(request.POST))
|
||||
repo_group = RepoGroupModel().create(
|
||||
group_name=form_result['group_name_full'],
|
||||
group_description=form_result['group_description'],
|
||||
owner=owner.user_id,
|
||||
copy_permissions=form_result['group_copy_permissions']
|
||||
)
|
||||
Session().flush()
|
||||
|
||||
repo_group_data = repo_group.get_api_data()
|
||||
audit_logger.store_web(
|
||||
'repo_group.create', action_data={'data': repo_group_data},
|
||||
user=c.rhodecode_user)
|
||||
|
||||
Session().commit()
|
||||
|
||||
_new_group_name = form_result['group_name_full']
|
||||
|
||||
repo_group_url = h.link_to(
|
||||
_new_group_name,
|
||||
h.route_path('repo_group_home', repo_group_name=_new_group_name))
|
||||
h.flash(h.literal(_('Created repository group %s')
|
||||
% repo_group_url), category='success')
|
||||
|
||||
except formencode.Invalid as errors:
|
||||
return htmlfill.render(
|
||||
render('admin/repo_groups/repo_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 during creation of repository group")
|
||||
h.flash(_('Error occurred during creation of repository group %s')
|
||||
% request.POST.get('group_name'), category='error')
|
||||
|
||||
# TODO: maybe we should get back to the main view, not the admin one
|
||||
return redirect(url('repo_groups', parent_group=parent_group_id))
|
||||
|
||||
# perm checks inside
|
||||
@NotAnonymous()
|
||||
def new(self):
|
||||
# perm check for admin, create_group perm or admin of parent_group
|
||||
parent_group_id = safe_int(request.GET.get('parent_group'))
|
||||
if not self._can_create_repo_group(parent_group_id):
|
||||
return abort(403)
|
||||
|
||||
self.__load_defaults()
|
||||
return render('admin/repo_groups/repo_group_add.mako')
|
||||
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
@auth.CSRFRequired()
|
||||
def update(self, group_name):
|
||||
|
||||
c.repo_group = RepoGroupModel()._get_repo_group(group_name)
|
||||
can_create_in_root = self._can_create_repo_group()
|
||||
show_root_location = can_create_in_root
|
||||
if not c.repo_group.parent_group:
|
||||
# this group don't have a parrent so we should show empty value
|
||||
show_root_location = True
|
||||
self.__load_defaults(allow_empty_group=show_root_location,
|
||||
repo_group=c.repo_group)
|
||||
|
||||
repo_group_form = RepoGroupForm(
|
||||
edit=True, old_data=c.repo_group.get_dict(),
|
||||
available_groups=c.repo_groups_choices,
|
||||
can_create_in_root=can_create_in_root, allow_disabled=True)()
|
||||
|
||||
old_values = c.repo_group.get_api_data()
|
||||
try:
|
||||
form_result = repo_group_form.to_python(dict(request.POST))
|
||||
gr_name = form_result['group_name']
|
||||
new_gr = RepoGroupModel().update(group_name, form_result)
|
||||
|
||||
audit_logger.store_web(
|
||||
'repo_group.edit', action_data={'old_data': old_values},
|
||||
user=c.rhodecode_user)
|
||||
|
||||
Session().commit()
|
||||
h.flash(_('Updated repository group %s') % (gr_name,),
|
||||
category='success')
|
||||
# we now have new name !
|
||||
group_name = new_gr.group_name
|
||||
except formencode.Invalid as errors:
|
||||
c.active = 'settings'
|
||||
return htmlfill.render(
|
||||
render('admin/repo_groups/repo_group_edit.mako'),
|
||||
defaults=errors.value,
|
||||
errors=errors.error_dict or {},
|
||||
prefix_error=False,
|
||||
encoding="UTF-8",
|
||||
force_defaults=False)
|
||||
except Exception:
|
||||
log.exception("Exception during update or repository group")
|
||||
h.flash(_('Error occurred during update of repository group %s')
|
||||
% request.POST.get('group_name'), category='error')
|
||||
|
||||
return redirect(url('edit_repo_group', group_name=group_name))
|
||||
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
@auth.CSRFRequired()
|
||||
def delete(self, group_name):
|
||||
gr = c.repo_group = RepoGroupModel()._get_repo_group(group_name)
|
||||
repos = gr.repositories.all()
|
||||
if repos:
|
||||
msg = ungettext(
|
||||
'This group contains %(num)d repository and cannot be deleted',
|
||||
'This group contains %(num)d repositories and cannot be'
|
||||
' deleted',
|
||||
len(repos)) % {'num': len(repos)}
|
||||
h.flash(msg, category='warning')
|
||||
return redirect(url('repo_groups'))
|
||||
|
||||
children = gr.children.all()
|
||||
if children:
|
||||
msg = ungettext(
|
||||
'This group contains %(num)d subgroup and cannot be deleted',
|
||||
'This group contains %(num)d subgroups and cannot be deleted',
|
||||
len(children)) % {'num': len(children)}
|
||||
h.flash(msg, category='warning')
|
||||
return redirect(url('repo_groups'))
|
||||
|
||||
try:
|
||||
old_values = gr.get_api_data()
|
||||
RepoGroupModel().delete(group_name)
|
||||
|
||||
audit_logger.store_web(
|
||||
'repo_group.delete', action_data={'old_data': old_values},
|
||||
user=c.rhodecode_user)
|
||||
|
||||
Session().commit()
|
||||
h.flash(_('Removed repository group %s') % group_name,
|
||||
category='success')
|
||||
except Exception:
|
||||
log.exception("Exception during deletion of repository group")
|
||||
h.flash(_('Error occurred during deletion of repository group %s')
|
||||
% group_name, category='error')
|
||||
|
||||
return redirect(url('repo_groups'))
|
||||
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
def edit(self, group_name):
|
||||
|
||||
c.active = 'settings'
|
||||
|
||||
c.repo_group = RepoGroupModel()._get_repo_group(group_name)
|
||||
# we can only allow moving empty group if it's already a top-level
|
||||
# group, ie has no parents, or we're admin
|
||||
can_create_in_root = self._can_create_repo_group()
|
||||
show_root_location = can_create_in_root
|
||||
if not c.repo_group.parent_group:
|
||||
# this group don't have a parrent so we should show empty value
|
||||
show_root_location = True
|
||||
self.__load_defaults(allow_empty_group=show_root_location,
|
||||
repo_group=c.repo_group)
|
||||
defaults = self.__load_data(c.repo_group.group_id)
|
||||
|
||||
return htmlfill.render(
|
||||
render('admin/repo_groups/repo_group_edit.mako'),
|
||||
defaults=defaults,
|
||||
encoding="UTF-8",
|
||||
force_defaults=False
|
||||
)
|
||||
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
def edit_repo_group_advanced(self, group_name):
|
||||
c.active = 'advanced'
|
||||
c.repo_group = RepoGroupModel()._get_repo_group(group_name)
|
||||
|
||||
return render('admin/repo_groups/repo_group_edit.mako')
|
||||
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
def edit_repo_group_perms(self, group_name):
|
||||
c.active = 'perms'
|
||||
c.repo_group = RepoGroupModel()._get_repo_group(group_name)
|
||||
self.__load_defaults()
|
||||
defaults = self.__load_data(c.repo_group.group_id)
|
||||
|
||||
return htmlfill.render(
|
||||
render('admin/repo_groups/repo_group_edit.mako'),
|
||||
defaults=defaults,
|
||||
encoding="UTF-8",
|
||||
force_defaults=False
|
||||
)
|
||||
|
||||
@HasRepoGroupPermissionAnyDecorator('group.admin')
|
||||
@auth.CSRFRequired()
|
||||
def update_perms(self, group_name):
|
||||
"""
|
||||
Update permissions for given repository group
|
||||
"""
|
||||
|
||||
c.repo_group = RepoGroupModel()._get_repo_group(group_name)
|
||||
valid_recursive_choices = ['none', 'repos', 'groups', 'all']
|
||||
form = RepoGroupPermsForm(valid_recursive_choices)().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_repo_group_perms', group_name=group_name))
|
||||
|
||||
# iterate over all members(if in recursive mode) of this groups and
|
||||
# set the permissions !
|
||||
# this can be potentially heavy operation
|
||||
changes = RepoGroupModel().update_permissions(
|
||||
c.repo_group,
|
||||
form['perm_additions'], form['perm_updates'], form['perm_deletions'],
|
||||
form['recursive'])
|
||||
|
||||
action_data = {
|
||||
'added': changes['added'],
|
||||
'updated': changes['updated'],
|
||||
'deleted': changes['deleted'],
|
||||
}
|
||||
audit_logger.store_web(
|
||||
'repo_group.edit.permissions', action_data=action_data,
|
||||
user=c.rhodecode_user)
|
||||
|
||||
Session().commit()
|
||||
h.flash(_('Repository Group permissions updated'), category='success')
|
||||
return redirect(url('edit_repo_group_perms', group_name=group_name))
|
||||
|
|
@ -71,7 +71,7 @@ def includeme(config):
|
|||
|
||||
# repo group integrations
|
||||
config.add_route('repo_group_integrations_home',
|
||||
add_route_requirements('/{repo_group_name}/settings/integrations'),
|
||||
add_route_requirements('/{repo_group_name}/_settings/integrations'),
|
||||
repo_group_route=True)
|
||||
|
||||
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
|
||||
|
|
@ -81,7 +81,7 @@ def includeme(config):
|
|||
route_name='repo_group_integrations_home')
|
||||
|
||||
config.add_route('repo_group_integrations_new',
|
||||
add_route_requirements('/{repo_group_name}/settings/integrations/new'),
|
||||
add_route_requirements('/{repo_group_name}/_settings/integrations/new'),
|
||||
repo_group_route=True)
|
||||
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
|
||||
attr='new_integration',
|
||||
|
|
@ -90,7 +90,7 @@ def includeme(config):
|
|||
route_name='repo_group_integrations_new')
|
||||
|
||||
config.add_route('repo_group_integrations_list',
|
||||
add_route_requirements('/{repo_group_name}/settings/integrations/{integration}'),
|
||||
add_route_requirements('/{repo_group_name}/_settings/integrations/{integration}'),
|
||||
repo_group_route=True,
|
||||
custom_predicates=(valid_integration,))
|
||||
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
|
||||
|
|
@ -100,7 +100,7 @@ def includeme(config):
|
|||
route_name='repo_group_integrations_list')
|
||||
|
||||
config.add_route('repo_group_integrations_create',
|
||||
add_route_requirements('/{repo_group_name}/settings/integrations/{integration}/new'),
|
||||
add_route_requirements('/{repo_group_name}/_settings/integrations/{integration}/new'),
|
||||
repo_group_route=True,
|
||||
custom_predicates=(valid_integration,))
|
||||
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
|
||||
|
|
@ -115,7 +115,7 @@ def includeme(config):
|
|||
route_name='repo_group_integrations_create')
|
||||
|
||||
config.add_route('repo_group_integrations_edit',
|
||||
add_route_requirements('/{repo_group_name}/settings/integrations/{integration}/{integration_id}'),
|
||||
add_route_requirements('/{repo_group_name}/_settings/integrations/{integration}/{integration_id}'),
|
||||
repo_group_route=True,
|
||||
custom_predicates=(valid_integration,))
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class TestRepoIntegrationsView(TestIntegrationsView):
|
|||
|
||||
class TestRepoGroupIntegrationsView(TestIntegrationsView):
|
||||
def test_index_no_integrations(self, test_repo_group):
|
||||
url = '/{repo_group_name}/settings/integrations'.format(
|
||||
url = '/{repo_group_name}/_settings/integrations'.format(
|
||||
repo_group_name=test_repo_group.group_name)
|
||||
response = self.app.get(url)
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ class TestRepoGroupIntegrationsView(TestIntegrationsView):
|
|||
def test_index_with_integrations(
|
||||
self, test_repo_group, repogroup_integration_stub):
|
||||
|
||||
url = '/{repo_group_name}/settings/integrations'.format(
|
||||
url = '/{repo_group_name}/_settings/integrations'.format(
|
||||
repo_group_name=test_repo_group.group_name)
|
||||
|
||||
stub_name = repogroup_integration_stub.name
|
||||
|
|
@ -167,7 +167,7 @@ class TestRepoGroupIntegrationsView(TestIntegrationsView):
|
|||
|
||||
def test_new_integration_page(self, test_repo_group):
|
||||
repo_group_name = test_repo_group.group_name
|
||||
url = '/{repo_group_name}/settings/integrations/new'.format(
|
||||
url = '/{repo_group_name}/_settings/integrations/new'.format(
|
||||
repo_group_name=test_repo_group.group_name)
|
||||
|
||||
response = self.app.get(url)
|
||||
|
|
@ -177,7 +177,7 @@ class TestRepoGroupIntegrationsView(TestIntegrationsView):
|
|||
for integration_key, integration_obj in integration_type_registry.items():
|
||||
if not integration_obj.is_dummy:
|
||||
nurl = (
|
||||
'/{repo_group_name}/settings/integrations/{integration}/new').format(
|
||||
'/{repo_group_name}/_settings/integrations/{integration}/new').format(
|
||||
repo_group_name=repo_group_name,
|
||||
integration=integration_key)
|
||||
response.mustcontain(nurl)
|
||||
|
|
@ -188,7 +188,7 @@ class TestRepoGroupIntegrationsView(TestIntegrationsView):
|
|||
self, test_repo_group, IntegrationType):
|
||||
|
||||
repo_group_name = test_repo_group.group_name
|
||||
url = ('/{repo_group_name}/settings/integrations/{integration_key}/new'
|
||||
url = ('/{repo_group_name}/_settings/integrations/{integration_key}/new'
|
||||
).format(repo_group_name=repo_group_name,
|
||||
integration_key=IntegrationType.key)
|
||||
|
||||
|
|
@ -202,7 +202,7 @@ class TestRepoGroupIntegrationsView(TestIntegrationsView):
|
|||
StubIntegrationType, csrf_token):
|
||||
|
||||
repo_group_name = test_repo_group.group_name
|
||||
url = ('/{repo_group_name}/settings/integrations/{integration_key}/new'
|
||||
url = ('/{repo_group_name}/_settings/integrations/{integration_key}/new'
|
||||
).format(repo_group_name=repo_group_name,
|
||||
integration_key=StubIntegrationType.key)
|
||||
|
||||
|
|
@ -232,9 +232,9 @@ def _post_integration_test_helper(app, url, csrf_token, repo, repo_group,
|
|||
('repo:%s' % repo_name,
|
||||
'/%s/settings/integrations' % repo_name),
|
||||
('repogroup:%s' % repo_group_name,
|
||||
'/%s/settings/integrations' % repo_group_name),
|
||||
'/%s/_settings/integrations' % repo_group_name),
|
||||
('repogroup-recursive:%s' % repo_group_name,
|
||||
'/%s/settings/integrations' % repo_group_name),
|
||||
'/%s/_settings/integrations' % repo_group_name),
|
||||
]
|
||||
|
||||
for scope, destination in scopes_destinations:
|
||||
|
|
|
|||
|
|
@ -254,8 +254,11 @@ class RepoGroupModel(BaseModel):
|
|||
# functions can delete this
|
||||
cleanup_group = self.check_exist_filesystem(group_name,
|
||||
exc_on_failure=False)
|
||||
user = self._get_user(owner)
|
||||
if not user:
|
||||
raise ValueError('Owner %s not found as rhodecode user', owner)
|
||||
|
||||
try:
|
||||
user = self._get_user(owner)
|
||||
new_repo_group = RepoGroup()
|
||||
new_repo_group.user = user
|
||||
new_repo_group.group_description = group_description or group_name
|
||||
|
|
@ -736,3 +739,26 @@ class RepoGroupModel(BaseModel):
|
|||
repo_group_data.append(row)
|
||||
|
||||
return repo_group_data
|
||||
|
||||
def _get_defaults(self, repo_group_name):
|
||||
repo_group = RepoGroup.get_by_group_name(repo_group_name)
|
||||
|
||||
if repo_group is None:
|
||||
return None
|
||||
|
||||
defaults = repo_group.get_dict()
|
||||
defaults['repo_group_name'] = repo_group.name
|
||||
defaults['repo_group_description'] = repo_group.group_description
|
||||
defaults['repo_group_enable_locking'] = repo_group.enable_locking
|
||||
|
||||
# we use -1 as this is how in HTML, we mark an empty group
|
||||
defaults['repo_group'] = defaults['group_parent_id'] or -1
|
||||
|
||||
# fill owner
|
||||
if repo_group.user:
|
||||
defaults.update({'user': repo_group.user.username})
|
||||
else:
|
||||
replacement_user = User.get_first_super_admin().username
|
||||
defaults.update({'user': replacement_user})
|
||||
|
||||
return defaults
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
|
||||
import colander
|
||||
import deform.widget
|
||||
|
||||
from rhodecode.translation import _
|
||||
from rhodecode.model.validation_schema import validators, preparers, types
|
||||
|
|
@ -143,6 +144,19 @@ def deferred_repo_group_name_validator(node, kw):
|
|||
return validators.valid_name_validator
|
||||
|
||||
|
||||
@colander.deferred
|
||||
def deferred_repo_group_validator(node, kw):
|
||||
options = kw.get(
|
||||
'repo_group_repo_group_options')
|
||||
return colander.OneOf([x for x in options])
|
||||
|
||||
|
||||
@colander.deferred
|
||||
def deferred_repo_group_widget(node, kw):
|
||||
items = kw.get('repo_group_repo_group_items')
|
||||
return deform.widget.Select2Widget(values=items)
|
||||
|
||||
|
||||
class GroupType(colander.Mapping):
|
||||
def _validate(self, node, value):
|
||||
try:
|
||||
|
|
@ -208,15 +222,15 @@ class RepoGroupSchema(colander.Schema):
|
|||
validator=deferred_repo_group_owner_validator)
|
||||
|
||||
repo_group_description = colander.SchemaNode(
|
||||
colander.String(), missing='')
|
||||
colander.String(), missing='', widget=deform.widget.TextAreaWidget())
|
||||
|
||||
repo_group_copy_permissions = colander.SchemaNode(
|
||||
types.StringBooleanType(),
|
||||
missing=False)
|
||||
missing=False, widget=deform.widget.CheckboxWidget())
|
||||
|
||||
repo_group_enable_locking = colander.SchemaNode(
|
||||
types.StringBooleanType(),
|
||||
missing=False)
|
||||
missing=False, widget=deform.widget.CheckboxWidget())
|
||||
|
||||
def deserialize(self, cstruct):
|
||||
"""
|
||||
|
|
@ -238,3 +252,33 @@ class RepoGroupSchema(colander.Schema):
|
|||
third.deserialize({'unique_repo_group_name': validated_name})
|
||||
|
||||
return appstruct
|
||||
|
||||
|
||||
class RepoGroupSettingsSchema(RepoGroupSchema):
|
||||
repo_group = colander.SchemaNode(
|
||||
colander.Integer(),
|
||||
validator=deferred_repo_group_validator,
|
||||
widget=deferred_repo_group_widget,
|
||||
missing='')
|
||||
|
||||
def deserialize(self, cstruct):
|
||||
"""
|
||||
Custom deserialize that allows to chain validation, and verify
|
||||
permissions, and as last step uniqueness
|
||||
"""
|
||||
|
||||
# first pass, to validate given data
|
||||
appstruct = super(RepoGroupSchema, self).deserialize(cstruct)
|
||||
validated_name = appstruct['repo_group_name']
|
||||
|
||||
# second pass to validate permissions to repo_group
|
||||
second = RepoGroupAccessSchema().bind(**self.bindings)
|
||||
appstruct_second = second.deserialize({'repo_group': validated_name})
|
||||
# save result
|
||||
appstruct['repo_group'] = appstruct_second['repo_group']
|
||||
|
||||
# thirds to validate uniqueness
|
||||
third = RepoGroupNameUniqueSchema().bind(**self.bindings)
|
||||
third.deserialize({'unique_repo_group_name': validated_name})
|
||||
|
||||
return appstruct
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ function registerRCRoutes() {
|
|||
pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
|
||||
pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
|
||||
pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
|
||||
pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/settings/integrations', ['repo_group_name']);
|
||||
pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
|
||||
pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
|
||||
pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
|
||||
pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
|
||||
pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
|
||||
pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
|
||||
pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
|
||||
pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
|
||||
pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
|
||||
pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
|
||||
pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
|
||||
pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
|
||||
|
|
@ -100,6 +100,9 @@ function registerRCRoutes() {
|
|||
pyroutes.register('repos', '/_admin/repos', []);
|
||||
pyroutes.register('repo_new', '/_admin/repos/new', []);
|
||||
pyroutes.register('repo_create', '/_admin/repos/create', []);
|
||||
pyroutes.register('repo_groups', '/_admin/repo_groups', []);
|
||||
pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
|
||||
pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
|
||||
pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
|
||||
pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
|
||||
pyroutes.register('channelstream_proxy', '/_channelstream', []);
|
||||
|
|
@ -223,6 +226,11 @@ function registerRCRoutes() {
|
|||
pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
|
||||
pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
|
||||
pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
|
||||
pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
|
||||
pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
|
||||
pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
|
||||
pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
|
||||
pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_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']);
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@
|
|||
%elif c.repo_group:
|
||||
${h.link_to(_('Admin'),h.route_path('admin_home'))}
|
||||
»
|
||||
${h.link_to(_('Repository Groups'),h.url('repo_groups'))}
|
||||
${h.link_to(_('Repository Groups'),h.route_path('repo_groups'))}
|
||||
»
|
||||
${h.link_to(c.repo_group.group_name,h.url('edit_repo_group', group_name=c.repo_group.group_name))}
|
||||
${h.link_to(c.repo_group.group_name,h.route_path('edit_repo_group', repo_group_name=c.repo_group.group_name))}
|
||||
»
|
||||
${h.link_to(_('Integrations'),request.route_url(route_name='repo_group_integrations_home', repo_group_name=c.repo_group.group_name))}
|
||||
»
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
%elif c.repo_group:
|
||||
${h.link_to(_('Admin'),h.route_path('admin_home'))}
|
||||
»
|
||||
${h.link_to(_('Repository Groups'),h.url('repo_groups'))}
|
||||
${h.link_to(_('Repository Groups'),h.route_path('repo_groups'))}
|
||||
»
|
||||
${h.link_to(c.repo_group.group_name,h.url('edit_repo_group', group_name=c.repo_group.group_name))}
|
||||
${h.link_to(c.repo_group.group_name,h.route_path('edit_repo_group', repo_group_name=c.repo_group.group_name))}
|
||||
%else:
|
||||
${h.link_to(_('Admin'),h.route_path('admin_home'))}
|
||||
»
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
%elif c.repo_group:
|
||||
${h.link_to(_('Admin'),h.route_path('admin_home'))}
|
||||
»
|
||||
${h.link_to(_('Repository Groups'),h.url('repo_groups'))}
|
||||
${h.link_to(_('Repository Groups'),h.route_path('repo_groups'))}
|
||||
»
|
||||
${h.link_to(c.repo_group.group_name,h.url('edit_repo_group', group_name=c.repo_group.group_name))}
|
||||
${h.link_to(c.repo_group.group_name,h.route_path('edit_repo_group', repo_group_name=c.repo_group.group_name))}
|
||||
»
|
||||
${h.link_to(_('Integrations'),request.route_url(route_name='repo_group_integrations_home', repo_group_name=c.repo_group.group_name))}
|
||||
%else:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<%def name="breadcrumbs_links()">
|
||||
${h.link_to(_('Admin'),h.route_path('admin_home'))}
|
||||
»
|
||||
${h.link_to(_('Repository groups'),h.url('repo_groups'))}
|
||||
${h.link_to(_('Repository groups'),h.route_path('repo_groups'))}
|
||||
»
|
||||
${_('Add Repository Group')}
|
||||
</%def>
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
${self.breadcrumbs()}
|
||||
</div>
|
||||
<!-- end box / title -->
|
||||
${h.secure_form(h.url('repo_groups'), request=request)}
|
||||
${h.secure_form(h.route_path('repo_group_create'), request=request)}
|
||||
<div class="form">
|
||||
<!-- fields -->
|
||||
<div class="fields">
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<%def name="breadcrumbs_links()">
|
||||
${h.link_to(_('Admin'),h.route_path('admin_home'))}
|
||||
»
|
||||
${h.link_to(_('Repository Groups'),h.url('repo_groups'))}
|
||||
${h.link_to(_('Repository Groups'),h.route_path('repo_groups'))}
|
||||
%if c.repo_group.parent_group:
|
||||
» ${h.link_to(c.repo_group.parent_group.name, h.route_path('repo_group_home', repo_group_name=c.repo_group.parent_group.group_name))}
|
||||
%endif
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
<%def name="breadcrumbs_side_links()">
|
||||
<ul class="links">
|
||||
<li>
|
||||
<a href="${h.url('new_repo_group', parent_group=c.repo_group.group_id)}" class="btn btn-small btn-success">${_(u'Add Child Group')}</a>
|
||||
<a href="${h.route_path('repo_group_new', _query=dict(parent_group=c.repo_group.group_id))}" class="btn btn-small btn-success">${_(u'Add Child Group')}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</%def>
|
||||
|
|
@ -45,9 +45,9 @@
|
|||
##main
|
||||
<div class="sidebar">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li class="${'active' if c.active=='settings' else ''}"><a href="${h.url('edit_repo_group', group_name=c.repo_group.group_name)}">${_('Settings')}</a></li>
|
||||
<li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_repo_group_perms', group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li>
|
||||
<li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_repo_group_advanced', group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li>
|
||||
<li class="${'active' if c.active=='settings' else ''}"><a href="${h.route_path('edit_repo_group', repo_group_name=c.repo_group.group_name)}">${_('Settings')}</a></li>
|
||||
<li class="${'active' if c.active=='permissions' else ''}"><a href="${h.route_path('edit_repo_group_perms', repo_group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li>
|
||||
<li class="${'active' if c.active=='advanced' else ''}"><a href="${h.route_path('edit_repo_group_advanced', repo_group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li>
|
||||
<li class="${'active' if c.active=='integrations' else ''}"><a href="${h.route_path('repo_group_integrations_home', repo_group_name=c.repo_group.group_name)}">${_('Integrations')}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
<h3 class="panel-title">${_('Delete repository group')}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
${h.secure_form(h.url('delete_repo_group', group_name=c.repo_group.group_name),method='delete', request=request)}
|
||||
${h.secure_form(h.route_path('edit_repo_group_advanced_delete', repo_group_name=c.repo_group.group_name), request=request)}
|
||||
<table class="display">
|
||||
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@
|
|||
<h3 class="panel-title">${_('Repository Group Permissions')}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
${h.secure_form(h.url('edit_repo_group_perms', group_name=c.repo_group.group_name),method='put', request=request)}
|
||||
${h.secure_form(h.route_path('edit_repo_group_perms_update', repo_group_name=c.repo_group.group_name), request=request)}
|
||||
<table id="permissions_manage" class="rctable permissions">
|
||||
<tr>
|
||||
<th class="td-radio">${_('None')}</th>
|
||||
<th class="td-radio">${_('Read')}</th>
|
||||
<th class="td-radio">${_('Write')}</th>
|
||||
<th class="td-radio">${_('Admin')}</th>
|
||||
<th class="td-user">${_('User/User Group')}</th>
|
||||
<th class="td-owner">${_('User/User Group')}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
## USERS
|
||||
|
|
@ -25,7 +25,6 @@
|
|||
<td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td>
|
||||
<td class="td-user">
|
||||
${base.gravatar(_user.email, 16)}
|
||||
<span class="user">
|
||||
${h.link_to_user(_user.username)}
|
||||
%if getattr(_user, 'admin_row', None):
|
||||
(${_('super admin')})
|
||||
|
|
@ -33,18 +32,17 @@
|
|||
%if getattr(_user, 'owner_row', None):
|
||||
(${_('owner')})
|
||||
%endif
|
||||
</span>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
%else:
|
||||
##forbid revoking permission from yourself, except if you're an super admin
|
||||
<tr>
|
||||
##forbid revoking permission from yourself, except if you're an super admin
|
||||
%if c.rhodecode_user.user_id != _user.user_id or c.rhodecode_user.is_admin:
|
||||
<td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.none')}</td>
|
||||
<td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.read')}</td>
|
||||
<td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.write')}</td>
|
||||
<td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.admin')}</td>
|
||||
<td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.none', checked=_user.permission=='group.none')}</td>
|
||||
<td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.read', checked=_user.permission=='group.read')}</td>
|
||||
<td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.write', checked=_user.permission=='group.write')}</td>
|
||||
<td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.admin', checked=_user.permission=='group.admin')}</td>
|
||||
<td class="td-user">
|
||||
${base.gravatar(_user.email, 16)}
|
||||
<span class="user">
|
||||
|
|
@ -89,10 +87,10 @@
|
|||
## USER GROUPS
|
||||
%for _user_group in c.repo_group.permission_user_groups():
|
||||
<tr id="id${id(_user_group.users_group_name)}">
|
||||
<td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.none')}</td>
|
||||
<td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.read')}</td>
|
||||
<td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.write')}</td>
|
||||
<td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.admin')}</td>
|
||||
<td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.none', checked=_user_group.permission=='group.none')}</td>
|
||||
<td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.read', checked=_user_group.permission=='group.read')}</td>
|
||||
<td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.write', checked=_user_group.permission=='group.write')}</td>
|
||||
<td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.admin', checked=_user_group.permission=='group.admin')}</td>
|
||||
<td class="td-componentname">
|
||||
<i class="icon-group" ></i>
|
||||
%if h.HasPermissionAny('hg.admin')():
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<h3 class="panel-title">${_('Settings for Repository Group: %s') % c.repo_group.name}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
${h.secure_form(h.url('update_repo_group',group_name=c.repo_group.group_name),method='put', request=request)}
|
||||
${h.secure_form(h.route_path('edit_repo_group', repo_group_name=c.repo_group.group_name), request=request)}
|
||||
<div class="form">
|
||||
<!-- fields -->
|
||||
<div class="fields">
|
||||
|
|
@ -15,13 +15,26 @@
|
|||
<label for="group_name">${_('Group Name')}:</label>
|
||||
</div>
|
||||
<div class="input">
|
||||
${h.text('group_name',class_='medium')}
|
||||
${c.form['repo_group_name'].render(css_class='medium', oid='group_name')|n}
|
||||
${c.form.render_error(request, c.form['repo_group_name'])|n}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">
|
||||
<label for="repo_group">${_('Group parent')}:</label>
|
||||
</div>
|
||||
<div class="select">
|
||||
${c.form['repo_group'].render(css_class='medium', oid='repo_group')|n}
|
||||
${c.form.render_error(request, c.form['repo_group'])|n}
|
||||
|
||||
<p class="help-block">${_('Optional select a parent group to move this repository group into.')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field badged-field">
|
||||
<div class="label">
|
||||
<label for="user">${_('Owner')}:</label>
|
||||
<label for="repo_group_owner">${_('Owner')}:</label>
|
||||
</div>
|
||||
<div class="input">
|
||||
<div class="badge-input-container">
|
||||
|
|
@ -29,20 +42,22 @@
|
|||
${base.gravatar_with_user(c.repo_group.user.email, show_disabled=not c.repo_group.user.active)}
|
||||
</div>
|
||||
<div class="badge-input-wrap">
|
||||
${h.text('user', class_="medium", autocomplete="off")}
|
||||
${c.form['repo_group_owner'].render(css_class='medium', oid='repo_group_owner')|n}
|
||||
</div>
|
||||
</div>
|
||||
<form:error name="user"/>
|
||||
${c.form.render_error(request, c.form['repo_group_owner'])|n}
|
||||
<p class="help-block">${_('Change owner of this repository group.')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label label-textarea">
|
||||
<label for="group_description">${_('Description')}:</label>
|
||||
<label for="repo_group_description">${_('Description')}:</label>
|
||||
</div>
|
||||
<div class="textarea text-area editor">
|
||||
${h.textarea('group_description',cols=23,rows=5,class_="medium")}
|
||||
${c.form['repo_group_description'].render(css_class='medium', oid='repo_group_description')|n}
|
||||
${c.form.render_error(request, c.form['repo_group_description'])|n}
|
||||
|
||||
<% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
|
||||
<span class="help-block">${_('Plain text format with support of {metatags}').format(metatags=metatags_url)|n}</span>
|
||||
<span id="meta-tags-desc" style="display: none">
|
||||
|
|
@ -52,23 +67,18 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">
|
||||
<label for="group_parent_id">${_('Group parent')}:</label>
|
||||
</div>
|
||||
<div class="select">
|
||||
${h.select('group_parent_id','',c.repo_groups,class_="medium")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="label label-checkbox">
|
||||
<label for="enable_locking">${_('Enable Repository Locking')}:</label>
|
||||
<label for="repo_group_enable_locking">${_('Enable Repository Locking')}:</label>
|
||||
</div>
|
||||
<div class="checkboxes">
|
||||
${h.checkbox('enable_locking',value="True")}
|
||||
${c.form['repo_group_enable_locking'].render(css_class='medium', oid='repo_group_enable_locking')|n}
|
||||
${c.form.render_error(request, c.form['repo_group_enable_locking'])|n}
|
||||
|
||||
<span class="help-block">${_('Repository locking will be enabled on all subgroups and repositories inside this repository group. Pulling from a repository locks it, and it is unlocked by pushing back by the same user.')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
${h.submit('save',_('Save'),class_="btn")}
|
||||
${h.reset('reset',_('Reset'),class_="btn")}
|
||||
|
|
@ -80,11 +90,6 @@
|
|||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("#group_parent_id").select2({
|
||||
'containerCssClass': "drop-menu",
|
||||
'dropdownCssClass': "drop-menu-dropdown",
|
||||
'dropdownAutoWidth': true
|
||||
});
|
||||
UsersAutoComplete('user', '${c.rhodecode_user.user_id}');
|
||||
UsersAutoComplete('repo_group_owner', '${c.rhodecode_user.user_id}');
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<ul class="links">
|
||||
%if h.HasPermissionAny('hg.admin','hg.repogroup.create.true')():
|
||||
<li>
|
||||
<a href="${h.url('new_repo_group')}" class="btn btn-small btn-success">${_(u'Add Repository Group')}</a>
|
||||
<a href="${h.route_path('repo_group_new')}" class="btn btn-small btn-success">${_(u'Add Repository Group')}</a>
|
||||
</li>
|
||||
%endif
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@
|
|||
<ul class="admin_menu submenu">
|
||||
<li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
|
||||
<li><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
|
||||
<li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
|
||||
<li><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
|
||||
<li><a href="${h.route_path('users')}">${_('Users')}</a></li>
|
||||
<li><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
|
||||
<li><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
<li class="local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
|
||||
%endif
|
||||
%if repository_groups:
|
||||
<li class="local-admin-repo-groups"><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
|
||||
<li class="local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
|
||||
%endif
|
||||
%if user_groups:
|
||||
<li class="local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@
|
|||
%if section == 'repositories':
|
||||
<a href="${h.route_path('edit_repo_perms',repo_name=k,_anchor='permissions_manage')}">${_('edit')}</a>
|
||||
%elif section == 'repositories_groups':
|
||||
<a href="${h.url('edit_repo_group_perms',group_name=k,anchor='permissions_manage')}">${_('edit')}</a>
|
||||
<a href="${h.route_path('edit_repo_group_perms',repo_group_name=k,_anchor='permissions_manage')}">${_('edit')}</a>
|
||||
%elif section == 'user_groups':
|
||||
##<a href="${h.route_path('edit_user_group',user_group_id=k)}">${_('edit')}</a>
|
||||
%endif
|
||||
|
|
|
|||
|
|
@ -237,10 +237,10 @@
|
|||
|
||||
<%def name="repo_group_actions(repo_group_id, repo_group_name, gr_count)">
|
||||
<div class="grid_edit">
|
||||
<a href="${h.url('edit_repo_group',group_name=repo_group_name)}" title="${_('Edit')}">Edit</a>
|
||||
<a href="${h.route_path('edit_repo_group',repo_group_name=repo_group_name)}" title="${_('Edit')}">Edit</a>
|
||||
</div>
|
||||
<div class="grid_delete">
|
||||
${h.secure_form(h.url('delete_repo_group', group_name=repo_group_name),method='delete', request=request)}
|
||||
${h.secure_form(h.route_path('edit_repo_group_advanced_delete', repo_group_name=repo_group_name), request=request)}
|
||||
${h.submit('remove_%s' % repo_group_name,_('Delete'),class_="btn btn-link btn-danger",
|
||||
onclick="return confirm('"+_ungettext('Confirm to delete this group: %s with %s repository','Confirm to delete this group: %s with %s repositories',gr_count) % (repo_group_name, gr_count)+"');")}
|
||||
${h.end_form()}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
%endif
|
||||
|
||||
%if is_admin or create_repo_group:
|
||||
<a href="${h.url('new_repo_group')}" class="btn btn-small btn-default">${_(u'Add Repository Group')}</a>
|
||||
<a href="${h.route_path('repo_group_new')}" class="btn btn-small btn-default">${_(u'Add Repository Group')}</a>
|
||||
%endif
|
||||
%else:
|
||||
##we're inside other repository group other terms apply
|
||||
|
|
@ -39,10 +39,10 @@
|
|||
<a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}" class="btn btn-small btn-success btn-primary">${_('Add Repository')}</a>
|
||||
%endif
|
||||
%if is_admin or group_admin:
|
||||
<a href="${h.url('new_repo_group', parent_group=c.repo_group.group_id)}" class="btn btn-small btn-default">${_(u'Add Repository Group')}</a>
|
||||
<a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}" class="btn btn-small btn-default">${_(u'Add Repository Group')}</a>
|
||||
%endif
|
||||
%if is_admin or group_admin:
|
||||
<a href="${h.url('edit_repo_group',group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}" class="btn btn-small btn-primary">${_('Edit Repository Group')}</a>
|
||||
<a href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}" class="btn btn-small btn-primary">${_('Edit Repository Group')}</a>
|
||||
%endif
|
||||
%endif
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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 mock
|
||||
import pylons
|
||||
import pytest
|
||||
from pylons import tmpl_context as c
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def current_user(request, user_util):
|
||||
user = user_util.create_user()
|
||||
|
||||
request_mock = mock.Mock(user=user)
|
||||
pylons.request._push_object(request_mock)
|
||||
|
||||
@request.addfinalizer
|
||||
def cleanup():
|
||||
pylons.request._pop_object()
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def personal_group_with_parent(user_util, current_user):
|
||||
group_read_only = user_util.create_repo_group()
|
||||
user_util.grant_user_permission_to_repo_group(
|
||||
group_read_only, current_user, 'group.read')
|
||||
|
||||
# TODO: johbo: This should go into the business models
|
||||
group_as_admin = user_util.create_repo_group(
|
||||
owner=current_user)
|
||||
group_as_admin.parent_group = group_read_only
|
||||
group_as_admin.group_name = group_as_admin.get_new_name(
|
||||
group_as_admin.group_name)
|
||||
|
||||
return group_as_admin
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def controller():
|
||||
from rhodecode.controllers.admin import repo_groups
|
||||
return repo_groups.RepoGroupsController()
|
||||
|
||||
|
||||
def test_repo_groups_load_defaults(
|
||||
current_user, personal_group_with_parent, controller):
|
||||
personal_group = personal_group_with_parent
|
||||
controller._RepoGroupsController__load_defaults(True, personal_group)
|
||||
|
||||
expected_list = [-1, personal_group.parent_group.group_id]
|
||||
returned_group_ids = [group[0] for group in c.repo_groups]
|
||||
assert returned_group_ids == expected_list
|
||||
|
||||
|
||||
def test_repo_groups_load_defaults_with_missing_group(
|
||||
current_user, personal_group_with_parent, controller):
|
||||
personal_group = personal_group_with_parent
|
||||
controller._RepoGroupsController__load_defaults(True)
|
||||
|
||||
expected_list = sorted([-1, personal_group.group_id])
|
||||
returned_group_ids = sorted([group[0] for group in c.repo_groups])
|
||||
assert returned_group_ids == expected_list
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from rhodecode.tests import TestController, url
|
||||
from rhodecode.tests import TestController
|
||||
from rhodecode.tests.fixture import Fixture
|
||||
|
||||
|
||||
|
|
@ -32,6 +32,8 @@ def route_path(name, params=None, **kwargs):
|
|||
'home': '/',
|
||||
'repos':
|
||||
ADMIN_PREFIX + '/repos',
|
||||
'repo_groups':
|
||||
ADMIN_PREFIX + '/repo_groups',
|
||||
'user_groups':
|
||||
ADMIN_PREFIX + '/user_groups',
|
||||
'user_groups_data':
|
||||
|
|
@ -65,7 +67,7 @@ class TestAdminDelegatedUser(TestController):
|
|||
response = self.app.get(route_path('repos'), status=200)
|
||||
response.mustcontain('data: []')
|
||||
|
||||
response = self.app.get(url('repo_groups'), status=200)
|
||||
response = self.app.get(route_path('repo_groups'), status=200)
|
||||
response.mustcontain('data: []')
|
||||
|
||||
response = self.app.get(route_path('user_groups_data'),
|
||||
|
|
@ -100,7 +102,7 @@ class TestAdminDelegatedUser(TestController):
|
|||
response = self.app.get(route_path('repos'), status=200)
|
||||
response.mustcontain('"name_raw": "{}"'.format(repo_name))
|
||||
|
||||
response = self.app.get(url('repo_groups'), status=200)
|
||||
response = self.app.get(route_path('repo_groups'), status=200)
|
||||
response.mustcontain('"name_raw": "{}"'.format(repo_group_name))
|
||||
|
||||
response = self.app.get(route_path('user_groups_data'),
|
||||
|
|
@ -142,7 +144,7 @@ class TestAdminDelegatedUser(TestController):
|
|||
response = self.app.get(route_path('repos'), status=200)
|
||||
response.mustcontain('"name_raw": "{}"'.format(repo_name))
|
||||
|
||||
response = self.app.get(url('repo_groups'), status=200)
|
||||
response = self.app.get(route_path('repo_groups'), status=200)
|
||||
response.mustcontain('"name_raw": "{}"'.format(repo_group_name))
|
||||
|
||||
response = self.app.get(route_path('user_groups_data'),
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ from rhodecode.model.repo_group import RepoGroupModel
|
|||
from rhodecode.model.scm import ScmModel
|
||||
from rhodecode.model.settings import UiSetting, SettingsModel
|
||||
from rhodecode.tests.fixture import Fixture
|
||||
from rhodecode.tests import TEST_USER_ADMIN_LOGIN
|
||||
|
||||
|
||||
fixture = Fixture()
|
||||
|
|
@ -221,23 +220,6 @@ def platform_encodes_filenames():
|
|||
return path_with_latin1 != read_path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def repo_groups(request):
|
||||
session = meta.Session()
|
||||
zombie_group = fixture.create_repo_group('zombie')
|
||||
parent_group = fixture.create_repo_group('parent')
|
||||
child_group = fixture.create_repo_group('parent/child')
|
||||
groups_in_db = session.query(db.RepoGroup).all()
|
||||
assert len(groups_in_db) == 3
|
||||
assert child_group.group_parent_id == parent_group.group_id
|
||||
|
||||
@request.addfinalizer
|
||||
def cleanup():
|
||||
fixture.destroy_repo_group(zombie_group)
|
||||
fixture.destroy_repo_group(child_group)
|
||||
fixture.destroy_repo_group(parent_group)
|
||||
|
||||
return (zombie_group, parent_group, child_group)
|
||||
|
||||
|
||||
def test_repo2db_mapper_groups(repo_groups):
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ def _update_repo(name, **kwargs):
|
|||
return r
|
||||
|
||||
|
||||
class TestRepoGroups:
|
||||
class TestRepoGroups(object):
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def prepare(self, request):
|
||||
|
|
|
|||
|
|
@ -1830,3 +1830,29 @@ def disable_anonymous_user(request, pylonsapp):
|
|||
@request.addfinalizer
|
||||
def cleanup():
|
||||
set_anonymous_access(True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def rc_fixture(request):
|
||||
return Fixture()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def repo_groups(request):
|
||||
fixture = Fixture()
|
||||
|
||||
session = Session()
|
||||
zombie_group = fixture.create_repo_group('zombie')
|
||||
parent_group = fixture.create_repo_group('parent')
|
||||
child_group = fixture.create_repo_group('parent/child')
|
||||
groups_in_db = session.query(RepoGroup).all()
|
||||
assert len(groups_in_db) == 3
|
||||
assert child_group.group_parent_id == parent_group.group_id
|
||||
|
||||
@request.addfinalizer
|
||||
def cleanup():
|
||||
fixture.destroy_repo_group(zombie_group)
|
||||
fixture.destroy_repo_group(child_group)
|
||||
fixture.destroy_repo_group(parent_group)
|
||||
|
||||
return zombie_group, parent_group, child_group
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue