diff --git a/rhodecode/apps/admin/__init__.py b/rhodecode/apps/admin/__init__.py index 79d84dd8..23234457 100644 --- a/rhodecode/apps/admin/__init__.py +++ b/rhodecode/apps/admin/__init__.py @@ -205,6 +205,19 @@ def admin_routes(config): name='edit_user_group_perms_summary_json', pattern='/user_groups/{user_group_id:\d+}/edit/permissions_summary/json') + # repos admin + config.add_route( + name='repos', + pattern='/repos') + + config.add_route( + name='repo_new', + pattern='/repos/new') + + config.add_route( + name='repo_create', + pattern='/repos/create') + def includeme(config): settings = config.get_settings() diff --git a/rhodecode/apps/admin/tests/test_admin_repos.py b/rhodecode/apps/admin/tests/test_admin_repos.py new file mode 100644 index 00000000..ff268686 --- /dev/null +++ b/rhodecode/apps/admin/tests/test_admin_repos.py @@ -0,0 +1,509 @@ +# -*- 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 . +# +# 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 urllib + +import mock +import pytest + +from rhodecode.apps._base import ADMIN_PREFIX +from rhodecode.lib import auth +from rhodecode.lib.utils2 import safe_str +from rhodecode.lib import helpers as h +from rhodecode.model.db import ( + Repository, RepoGroup, UserRepoToPerm, User, Permission) +from rhodecode.model.meta import Session +from rhodecode.model.repo import RepoModel +from rhodecode.model.repo_group import RepoGroupModel +from rhodecode.model.user import UserModel +from rhodecode.tests import ( + login_user_session, assert_session_flash, TEST_USER_ADMIN_LOGIN, + TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) +from rhodecode.tests.fixture import Fixture, error_function +from rhodecode.tests.utils import AssertResponse, repo_on_filesystem + +fixture = Fixture() + + +def route_path(name, params=None, **kwargs): + import urllib + + base_url = { + 'repos': ADMIN_PREFIX + '/repos', + 'repo_new': ADMIN_PREFIX + '/repos/new', + 'repo_create': ADMIN_PREFIX + '/repos/create', + + 'repo_creating_check': '/{repo_name}/repo_creating_check', + }[name].format(**kwargs) + + if params: + base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) + return base_url + + +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 + + +@pytest.mark.usefixtures("app") +class TestAdminRepos(object): + + def test_repo_list(self, autologin_user, user_util): + repo = user_util.create_repo() + response = self.app.get( + route_path('repos'), status=200) + + response.mustcontain(repo.repo_name) + + def test_create_page_restricted_to_single_backend(self, autologin_user, backend): + with mock.patch('rhodecode.BACKENDS', {'git': 'git'}): + response = self.app.get(route_path('repo_new'), status=200) + assert_response = AssertResponse(response) + element = assert_response.get_element('#repo_type') + assert element.text_content() == '\ngit\n' + + def test_create_page_non_restricted_backends(self, autologin_user, backend): + response = self.app.get(route_path('repo_new'), status=200) + assert_response = AssertResponse(response) + assert_response.element_contains('#repo_type', 'git') + assert_response.element_contains('#repo_type', 'svn') + assert_response.element_contains('#repo_type', 'hg') + + @pytest.mark.parametrize( + "suffix", [u'', u'xxa'], ids=['', 'non-ascii']) + def test_create(self, autologin_user, backend, suffix, csrf_token): + repo_name_unicode = backend.new_repo_name(suffix=suffix) + repo_name = repo_name_unicode.encode('utf8') + description_unicode = u'description for newly created repo' + suffix + description = description_unicode.encode('utf8') + response = self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + csrf_token=csrf_token), + status=302) + + self.assert_repository_is_created_correctly( + repo_name, description, backend) + + def test_create_numeric_name(self, autologin_user, backend, csrf_token): + numeric_repo = '1234' + repo_name = numeric_repo + description = 'description for newly created repo' + numeric_repo + self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + csrf_token=csrf_token)) + + self.assert_repository_is_created_correctly( + repo_name, description, backend) + + @pytest.mark.parametrize("suffix", [u'', u'ąćę'], ids=['', 'non-ascii']) + def test_create_in_group( + self, autologin_user, backend, suffix, csrf_token): + # create GROUP + group_name = 'sometest_%s' % backend.alias + gr = RepoGroupModel().create(group_name=group_name, + group_description='test', + owner=TEST_USER_ADMIN_LOGIN) + Session().commit() + + repo_name = u'ingroup' + suffix + repo_name_full = RepoGroup.url_sep().join( + [group_name, repo_name]) + description = u'description for newly created repo' + self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=safe_str(repo_name), + repo_type=backend.alias, + repo_description=description, + repo_group=gr.group_id, + csrf_token=csrf_token)) + + # TODO: johbo: Cleanup work to fixture + try: + self.assert_repository_is_created_correctly( + repo_name_full, description, backend) + + new_repo = RepoModel().get_by_repo_name(repo_name_full) + inherited_perms = UserRepoToPerm.query().filter( + UserRepoToPerm.repository_id == new_repo.repo_id).all() + assert len(inherited_perms) == 1 + finally: + RepoModel().delete(repo_name_full) + RepoGroupModel().delete(group_name) + Session().commit() + + def test_create_in_group_numeric_name( + self, autologin_user, backend, csrf_token): + # create GROUP + group_name = 'sometest_%s' % backend.alias + gr = RepoGroupModel().create(group_name=group_name, + group_description='test', + owner=TEST_USER_ADMIN_LOGIN) + Session().commit() + + repo_name = '12345' + repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) + description = 'description for newly created repo' + self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + repo_group=gr.group_id, + csrf_token=csrf_token)) + + # TODO: johbo: Cleanup work to fixture + try: + self.assert_repository_is_created_correctly( + repo_name_full, description, backend) + + new_repo = RepoModel().get_by_repo_name(repo_name_full) + inherited_perms = UserRepoToPerm.query()\ + .filter(UserRepoToPerm.repository_id == new_repo.repo_id).all() + assert len(inherited_perms) == 1 + finally: + RepoModel().delete(repo_name_full) + RepoGroupModel().delete(group_name) + Session().commit() + + def test_create_in_group_without_needed_permissions(self, backend): + session = login_user_session( + self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) + csrf_token = auth.get_csrf_token(session) + # revoke + user_model = UserModel() + # disable fork and create on default user + user_model.revoke_perm(User.DEFAULT_USER, 'hg.create.repository') + user_model.grant_perm(User.DEFAULT_USER, 'hg.create.none') + user_model.revoke_perm(User.DEFAULT_USER, 'hg.fork.repository') + user_model.grant_perm(User.DEFAULT_USER, 'hg.fork.none') + + # disable on regular user + user_model.revoke_perm(TEST_USER_REGULAR_LOGIN, 'hg.create.repository') + user_model.grant_perm(TEST_USER_REGULAR_LOGIN, 'hg.create.none') + user_model.revoke_perm(TEST_USER_REGULAR_LOGIN, 'hg.fork.repository') + user_model.grant_perm(TEST_USER_REGULAR_LOGIN, 'hg.fork.none') + Session().commit() + + # create GROUP + group_name = 'reg_sometest_%s' % backend.alias + gr = RepoGroupModel().create(group_name=group_name, + group_description='test', + owner=TEST_USER_ADMIN_LOGIN) + Session().commit() + + group_name_allowed = 'reg_sometest_allowed_%s' % backend.alias + gr_allowed = RepoGroupModel().create( + group_name=group_name_allowed, + group_description='test', + owner=TEST_USER_REGULAR_LOGIN) + Session().commit() + + repo_name = 'ingroup' + description = 'description for newly created repo' + response = self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + repo_group=gr.group_id, + csrf_token=csrf_token)) + + response.mustcontain('Invalid value') + + # user is allowed to create in this group + repo_name = 'ingroup' + repo_name_full = RepoGroup.url_sep().join( + [group_name_allowed, repo_name]) + description = 'description for newly created repo' + response = self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + repo_group=gr_allowed.group_id, + csrf_token=csrf_token)) + + # TODO: johbo: Cleanup in pytest fixture + try: + self.assert_repository_is_created_correctly( + repo_name_full, description, backend) + + new_repo = RepoModel().get_by_repo_name(repo_name_full) + inherited_perms = UserRepoToPerm.query().filter( + UserRepoToPerm.repository_id == new_repo.repo_id).all() + assert len(inherited_perms) == 1 + + assert repo_on_filesystem(repo_name_full) + finally: + RepoModel().delete(repo_name_full) + RepoGroupModel().delete(group_name) + RepoGroupModel().delete(group_name_allowed) + Session().commit() + + def test_create_in_group_inherit_permissions(self, autologin_user, backend, + csrf_token): + # create GROUP + group_name = 'sometest_%s' % backend.alias + gr = RepoGroupModel().create(group_name=group_name, + group_description='test', + owner=TEST_USER_ADMIN_LOGIN) + perm = Permission.get_by_key('repository.write') + RepoGroupModel().grant_user_permission( + gr, TEST_USER_REGULAR_LOGIN, perm) + + # add repo permissions + Session().commit() + + repo_name = 'ingroup_inherited_%s' % backend.alias + repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) + description = 'description for newly created repo' + self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + repo_group=gr.group_id, + repo_copy_permissions=True, + csrf_token=csrf_token)) + + # TODO: johbo: Cleanup to pytest fixture + try: + self.assert_repository_is_created_correctly( + repo_name_full, description, backend) + except Exception: + RepoGroupModel().delete(group_name) + Session().commit() + raise + + # check if inherited permissions are applied + new_repo = RepoModel().get_by_repo_name(repo_name_full) + inherited_perms = UserRepoToPerm.query().filter( + UserRepoToPerm.repository_id == new_repo.repo_id).all() + assert len(inherited_perms) == 2 + + assert TEST_USER_REGULAR_LOGIN in [ + x.user.username for x in inherited_perms] + assert 'repository.write' in [ + x.permission.permission_name for x in inherited_perms] + + RepoModel().delete(repo_name_full) + RepoGroupModel().delete(group_name) + Session().commit() + + @pytest.mark.xfail_backends( + "git", "hg", reason="Missing reposerver support") + def test_create_with_clone_uri(self, autologin_user, backend, reposerver, + csrf_token): + source_repo = backend.create_repo(number_of_commits=2) + source_repo_name = source_repo.repo_name + reposerver.serve(source_repo.scm_instance()) + + repo_name = backend.new_repo_name() + response = self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description='', + clone_uri=reposerver.url, + csrf_token=csrf_token), + status=302) + + # Should be redirected to the creating page + response.mustcontain('repo_creating') + + # Expecting that both repositories have same history + source_repo = RepoModel().get_by_repo_name(source_repo_name) + source_vcs = source_repo.scm_instance() + repo = RepoModel().get_by_repo_name(repo_name) + repo_vcs = repo.scm_instance() + assert source_vcs[0].message == repo_vcs[0].message + assert source_vcs.count() == repo_vcs.count() + assert source_vcs.commit_ids == repo_vcs.commit_ids + + @pytest.mark.xfail_backends("svn", reason="Depends on import support") + def test_create_remote_repo_wrong_clone_uri(self, autologin_user, backend, + csrf_token): + repo_name = backend.new_repo_name() + description = 'description for newly created repo' + response = self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + clone_uri='http://repo.invalid/repo', + csrf_token=csrf_token)) + response.mustcontain('invalid clone url') + + @pytest.mark.xfail_backends("svn", reason="Depends on import support") + def test_create_remote_repo_wrong_clone_uri_hg_svn( + self, autologin_user, backend, csrf_token): + repo_name = backend.new_repo_name() + description = 'description for newly created repo' + response = self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + clone_uri='svn+http://svn.invalid/repo', + csrf_token=csrf_token)) + response.mustcontain('invalid clone url') + + def test_create_with_git_suffix( + self, autologin_user, backend, csrf_token): + repo_name = backend.new_repo_name() + ".git" + description = 'description for newly created repo' + response = self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + csrf_token=csrf_token)) + response.mustcontain('Repository name cannot end with .git') + + def test_default_user_cannot_access_private_repo_in_a_group( + self, autologin_user, user_util, backend): + + group = user_util.create_repo_group() + + repo = backend.create_repo( + repo_private=True, repo_group=group, repo_copy_permissions=True) + + permissions = _get_permission_for_user( + user='default', repo=repo.repo_name) + assert len(permissions) == 1 + assert permissions[0].permission.permission_name == 'repository.none' + assert permissions[0].repository.private is True + + def test_create_on_top_level_without_permissions(self, backend): + session = login_user_session( + self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) + csrf_token = auth.get_csrf_token(session) + + # revoke + user_model = UserModel() + # disable fork and create on default user + user_model.revoke_perm(User.DEFAULT_USER, 'hg.create.repository') + user_model.grant_perm(User.DEFAULT_USER, 'hg.create.none') + user_model.revoke_perm(User.DEFAULT_USER, 'hg.fork.repository') + user_model.grant_perm(User.DEFAULT_USER, 'hg.fork.none') + + # disable on regular user + user_model.revoke_perm(TEST_USER_REGULAR_LOGIN, 'hg.create.repository') + user_model.grant_perm(TEST_USER_REGULAR_LOGIN, 'hg.create.none') + user_model.revoke_perm(TEST_USER_REGULAR_LOGIN, 'hg.fork.repository') + user_model.grant_perm(TEST_USER_REGULAR_LOGIN, 'hg.fork.none') + Session().commit() + + repo_name = backend.new_repo_name() + description = 'description for newly created repo' + response = self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + csrf_token=csrf_token)) + + response.mustcontain( + u"You do not have the permission to store repositories in " + u"the root location.") + + @mock.patch.object(RepoModel, '_create_filesystem_repo', error_function) + def test_create_repo_when_filesystem_op_fails( + self, autologin_user, backend, csrf_token): + repo_name = backend.new_repo_name() + description = 'description for newly created repo' + + response = self.app.post( + route_path('repo_create'), + fixture._get_repo_create_params( + repo_private=False, + repo_name=repo_name, + repo_type=backend.alias, + repo_description=description, + csrf_token=csrf_token)) + + assert_session_flash( + response, 'Error creating repository %s' % repo_name) + # repo must not be in db + assert backend.repo is None + # repo must not be in filesystem ! + assert not repo_on_filesystem(repo_name) + + def assert_repository_is_created_correctly( + self, repo_name, description, backend): + repo_name_utf8 = safe_str(repo_name) + + # run the check page that triggers the flash message + response = self.app.get( + route_path('repo_creating_check', repo_name=safe_str(repo_name))) + assert response.json == {u'result': True} + + flash_msg = u'Created repository {}'.format( + urllib.quote(repo_name_utf8), repo_name) + assert_session_flash(response, flash_msg) + + # test if the repo was created in the database + new_repo = RepoModel().get_by_repo_name(repo_name) + + assert new_repo.repo_name == repo_name + assert new_repo.description == description + + # test if the repository is visible in the list ? + response = self.app.get( + h.route_path('repo_summary', repo_name=safe_str(repo_name))) + response.mustcontain(repo_name) + response.mustcontain(backend.alias) + + assert repo_on_filesystem(repo_name) diff --git a/rhodecode/apps/admin/views/open_source_licenses.py b/rhodecode/apps/admin/views/open_source_licenses.py index 04acf6b3..d8a11511 100644 --- a/rhodecode/apps/admin/views/open_source_licenses.py +++ b/rhodecode/apps/admin/views/open_source_licenses.py @@ -48,7 +48,7 @@ class OpenSourceLicensesAdminSettingsView(BaseAppView): c = self.load_default_context() c.active = 'open_source' c.navlist = navigation_list(self.request) - c.opensource_licenses = collections.OrderedDict( - sorted(read_opensource_licenses().items(), key=lambda t: t[0])) + items = sorted(read_opensource_licenses().items(), key=lambda t: t[0]) + c.opensource_licenses = collections.OrderedDict(items) return self._get_template_context(c) diff --git a/rhodecode/apps/admin/views/repositories.py b/rhodecode/apps/admin/views/repositories.py new file mode 100644 index 00000000..02fb1e5c --- /dev/null +++ b/rhodecode/apps/admin/views/repositories.py @@ -0,0 +1,180 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2016-2017 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging +import formencode + +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 +from rhodecode.lib.utils import repo_name_slug +from rhodecode.lib.utils2 import safe_int, safe_unicode +from rhodecode.model.forms import RepoForm +from rhodecode.model.repo import RepoModel +from rhodecode.model.scm import RepoList, RepoGroupList, ScmModel +from rhodecode.model.settings import SettingsModel +from rhodecode.model.db import Repository, RepoGroup + +log = logging.getLogger(__name__) + + +class AdminReposView(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): + acl_groups = RepoGroupList(RepoGroup.query().all(), + perm_set=['group.write', 'group.admin']) + c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) + c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups) + c.landing_revs_choices, c.landing_revs = \ + ScmModel().get_repo_landing_revs() + c.personal_repo_group = self._rhodecode_user.personal_repo_group + + @LoginRequired() + @NotAnonymous() + @view_config( + route_name='repos', request_method='GET', + renderer='rhodecode:templates/admin/repos/repos.mako') + def repository_list(self): + c = self.load_default_context() + + repo_list = Repository.get_all_repos() + c.repo_list = RepoList(repo_list, perm_set=['repository.admin']) + repos_data = RepoModel().get_repos_as_dict( + repo_list=c.repo_list, admin=True, super_user_actions=True) + # json used to render the grid + c.data = json.dumps(repos_data) + + return self._get_template_context(c) + + @LoginRequired() + @NotAnonymous() + # perms check inside + @view_config( + route_name='repo_new', request_method='GET', + renderer='rhodecode:templates/admin/repos/repo_add.mako') + def repository_new(self): + c = self.load_default_context() + + new_repo = self.request.GET.get('repo', '') + parent_group = safe_int(self.request.GET.get('parent_group')) + _gr = RepoGroup.get(parent_group) + + if not HasPermissionAny('hg.admin', 'hg.create.repository')(): + # you're not super admin nor have global create permissions, + # but maybe you have at least write permission to a parent group ? + + gr_name = _gr.group_name if _gr else None + # create repositories with write permission on group is set to true + create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')() + group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name) + group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name) + if not (group_admin or (group_write and create_on_write)): + raise HTTPForbidden() + + self._load_form_data(c) + c.new_repo = repo_name_slug(new_repo) + + # apply the defaults from defaults page + defaults = SettingsModel().get_default_repo_settings(strip_prefix=True) + # set checkbox to autochecked + defaults['repo_copy_permissions'] = True + + parent_group_choice = '-1' + if not self._rhodecode_user.is_admin and self._rhodecode_user.personal_repo_group: + parent_group_choice = self._rhodecode_user.personal_repo_group + + if parent_group and _gr: + if parent_group in [x[0] for x in c.repo_groups]: + parent_group_choice = safe_unicode(parent_group) + + defaults.update({'repo_group': parent_group_choice}) + + data = render('rhodecode:templates/admin/repos/repo_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() + # perms check inside + @view_config( + route_name='repo_create', request_method='POST', + renderer='rhodecode:templates/admin/repos/repos.mako') + def repository_create(self): + c = self.load_default_context() + + form_result = {} + task_id = None + self._load_form_data(c) + + try: + # CanWriteToGroup validators checks permissions of this POST + form_result = RepoForm(repo_groups=c.repo_groups_choices, + landing_revs=c.landing_revs_choices)()\ + .to_python(dict(self.request.POST)) + + # create is done sometimes async on celery, db transaction + # management is handled there. + task = RepoModel().create(form_result, self._rhodecode_user.user_id) + from celery.result import BaseAsyncResult + if isinstance(task, BaseAsyncResult): + task_id = task.task_id + except formencode.Invalid as errors: + data = render('rhodecode:templates/admin/repos/repo_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 as e: + msg = self._log_creation_exception(e, form_result.get('repo_name')) + h.flash(msg, category='error') + raise HTTPFound(h.route_path('home')) + + raise HTTPFound( + h.route_path('repo_creating', + repo_name=form_result['repo_name_full'], + _query=dict(task_id=task_id))) diff --git a/rhodecode/apps/admin/views/user_groups.py b/rhodecode/apps/admin/views/user_groups.py index ab286b0c..a25ac338 100644 --- a/rhodecode/apps/admin/views/user_groups.py +++ b/rhodecode/apps/admin/views/user_groups.py @@ -19,7 +19,6 @@ # and proprietary license terms, please see https://rhodecode.com/licenses/ import logging -import datetime from pyramid.httpexceptions import HTTPFound from pyramid.view import view_config @@ -28,12 +27,11 @@ from rhodecode.model.scm import UserGroupList from rhodecode.apps._base import BaseAppView, DataGridAppView from rhodecode.lib.auth import ( - LoginRequired, HasPermissionAllDecorator, CSRFRequired, NotAnonymous, + LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator) from rhodecode.lib import helpers as h from rhodecode.lib.utils import PartialRenderer -from rhodecode.lib.utils2 import safe_int, safe_unicode -from rhodecode.model.user_group import UserGroupModel +from rhodecode.lib.utils2 import safe_unicode from rhodecode.model.db import ( joinedload, or_, count, User, UserGroup, UserGroupMember, UserGroupRepoToPerm, UserGroupRepoGroupToPerm) diff --git a/rhodecode/apps/ops/tests/__init__.py b/rhodecode/apps/ops/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rhodecode/apps/repo_group/tests/__init__.py b/rhodecode/apps/repo_group/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rhodecode/apps/repository/__init__.py b/rhodecode/apps/repository/__init__.py index dbf4154c..25c9caf9 100644 --- a/rhodecode/apps/repository/__init__.py +++ b/rhodecode/apps/repository/__init__.py @@ -337,7 +337,76 @@ def includeme(config): name='edit_repo_perms', pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True) - # Repo Review Rules + # Maintenance + config.add_route( + name='edit_repo_maintenance', + pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True) + + config.add_route( + name='edit_repo_maintenance_execute', + pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True) + + # Fields + config.add_route( + name='edit_repo_fields', + pattern='/{repo_name:.*?[^/]}/settings/fields', repo_route=True) + config.add_route( + name='edit_repo_fields_create', + pattern='/{repo_name:.*?[^/]}/settings/fields/create', repo_route=True) + config.add_route( + name='edit_repo_fields_delete', + pattern='/{repo_name:.*?[^/]}/settings/fields/{field_id}/delete', repo_route=True) + + # Locking + config.add_route( + name='repo_edit_toggle_locking', + pattern='/{repo_name:.*?[^/]}/settings/toggle_locking', repo_route=True) + + # Remote + config.add_route( + name='edit_repo_remote', + pattern='/{repo_name:.*?[^/]}/settings/remote', repo_route=True) + config.add_route( + name='edit_repo_remote_pull', + pattern='/{repo_name:.*?[^/]}/settings/remote/pull', repo_route=True) + + + # Statistics + config.add_route( + name='edit_repo_statistics', + pattern='/{repo_name:.*?[^/]}/settings/statistics', repo_route=True) + config.add_route( + name='edit_repo_statistics_reset', + pattern='/{repo_name:.*?[^/]}/settings/statistics/update', repo_route=True) + + # Issue trackers + config.add_route( + name='edit_repo_issuetracker', + pattern='/{repo_name:.*?[^/]}/settings/issue_trackers', repo_route=True) + config.add_route( + name='edit_repo_issuetracker_test', + pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/test', repo_route=True) + config.add_route( + name='edit_repo_issuetracker_delete', + pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/delete', repo_route=True) + config.add_route( + name='edit_repo_issuetracker_update', + pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/update', repo_route=True) + + # VCS Settings + config.add_route( + name='edit_repo_vcs', + pattern='/{repo_name:.*?[^/]}/settings/vcs', repo_route=True) + config.add_route( + name='edit_repo_vcs_update', + pattern='/{repo_name:.*?[^/]}/settings/vcs/update', repo_route=True) + + # svn pattern + config.add_route( + name='edit_repo_vcs_svn_pattern_delete', + pattern='/{repo_name:.*?[^/]}/settings/vcs/svn_pattern/delete', repo_route=True) + + # Repo Review Rules (EE feature) config.add_route( name='repo_reviewers', pattern='/{repo_name:.*?[^/]}/settings/review/rules', repo_route=True) @@ -346,18 +415,9 @@ def includeme(config): name='repo_default_reviewers_data', pattern='/{repo_name:.*?[^/]}/settings/review/default-reviewers', repo_route=True) - # Maintenance - config.add_route( - name='repo_maintenance', - pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True) - - config.add_route( - name='repo_maintenance_execute', - pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True) - # Strip config.add_route( - name='strip', + name='edit_repo_strip', pattern='/{repo_name:.*?[^/]}/settings/strip', repo_route=True) config.add_route( diff --git a/rhodecode/tests/functional/test_admin_repos_issuetracker.py b/rhodecode/apps/repository/tests/test_repo_issue_tracker.py similarity index 73% rename from rhodecode/tests/functional/test_admin_repos_issuetracker.py rename to rhodecode/apps/repository/tests/test_repo_issue_tracker.py index f749f87d..0385b64b 100644 --- a/rhodecode/tests/functional/test_admin_repos_issuetracker.py +++ b/rhodecode/apps/repository/tests/test_repo_issue_tracker.py @@ -24,23 +24,38 @@ from rhodecode.lib.utils2 import md5 from rhodecode.model.db import Repository from rhodecode.model.meta import Session from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel -from rhodecode.tests import url + + +def route_path(name, params=None, **kwargs): + import urllib + + base_url = { + 'repo_summary': '/{repo_name}', + 'edit_repo_issuetracker': '/{repo_name}/settings/issue_trackers', + 'edit_repo_issuetracker_test': '/{repo_name}/settings/issue_trackers/test', + 'edit_repo_issuetracker_delete': '/{repo_name}/settings/issue_trackers/delete', + 'edit_repo_issuetracker_update': '/{repo_name}/settings/issue_trackers/update', + }[name].format(**kwargs) + + if params: + base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) + return base_url @pytest.mark.usefixtures("app") -class TestAdminRepos: +class TestRepoIssueTracker(object): def test_issuetracker_index(self, autologin_user, backend): repo = backend.create_repo() - response = self.app.get(url('repo_settings_issuetracker', + response = self.app.get(route_path('edit_repo_issuetracker', repo_name=repo.repo_name)) assert response.status_code == 200 - def test_add_issuetracker_patterns( - self, autologin_user, backend, csrf_token, request): + def test_add_and_test_issuetracker_patterns( + self, autologin_user, backend, csrf_token, request, xhr_header): pattern = 'issuetracker_pat' another_pattern = pattern+'1' - post_url = url('repo_issuetracker_save', - repo_name=backend.repo.repo_name) + post_url = route_path( + 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name) post_data = { 'new_pattern_pattern_0': pattern, 'new_pattern_url_0': 'url', @@ -60,6 +75,17 @@ class TestAdminRepos: self.another_uid = md5(another_pattern) assert settings[self.another_uid]['pat'] == another_pattern + # test pattern + data = {'test_text': 'example of issuetracker_pat replacement', + 'csrf_token': csrf_token} + response = self.app.post( + route_path('edit_repo_issuetracker_test', + repo_name=backend.repo.repo_name), + extra_environ=xhr_header, params=data) + + assert response.body == \ + 'example of prefix replacement' + @request.addfinalizer def cleanup(): self.settings_model.delete_entries(self.uid) @@ -76,8 +102,8 @@ class TestAdminRepos: entry_key+old_uid, old_pattern, 'unicode') Session().add(sett) Session().commit() - post_url = url('repo_issuetracker_save', - repo_name=backend.repo.repo_name) + post_url = route_path( + 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name) post_data = { 'new_pattern_pattern_0': pattern, 'new_pattern_url_0': 'url', @@ -92,7 +118,7 @@ class TestAdminRepos: self.uid = md5(pattern) assert settings[self.uid]['pat'] == pattern with pytest.raises(KeyError): - settings[old_uid] + key = settings[old_uid] @request.addfinalizer def cleanup(): @@ -110,10 +136,10 @@ class TestAdminRepos: value=entry_key, type_='unicode', cleanup=False) self.app.post( - url('repo_issuetracker_delete', + route_path( + 'edit_repo_issuetracker_delete', repo_name=backend.repo.repo_name), { - '_method': 'delete', 'uid': uid, 'csrf_token': csrf_token }, status=302) diff --git a/rhodecode/apps/repository/tests/test_repo_settings.py b/rhodecode/apps/repository/tests/test_repo_settings.py index 9262dda9..65af81c6 100644 --- a/rhodecode/apps/repository/tests/test_repo_settings.py +++ b/rhodecode/apps/repository/tests/test_repo_settings.py @@ -26,8 +26,7 @@ from rhodecode.lib.vcs.exceptions import RepositoryRequirementError from rhodecode.model.db import Repository, UserRepoToPerm, Permission, User from rhodecode.model.meta import Session from rhodecode.tests import ( - url, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, - assert_session_flash) + TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, assert_session_flash) from rhodecode.tests.fixture import Fixture fixture = Fixture() @@ -41,6 +40,11 @@ def route_path(name, params=None, **kwargs): 'edit_repo_advanced': '/{repo_name}/settings/advanced', 'edit_repo_caches': '/{repo_name}/settings/caches', 'edit_repo_perms': '/{repo_name}/settings/permissions', + 'edit_repo_vcs': '/{repo_name}/settings/vcs', + 'edit_repo_issuetracker': '/{repo_name}/settings/issue_trackers', + 'edit_repo_fields': '/{repo_name}/settings/fields', + 'edit_repo_remote': '/{repo_name}/settings/remote', + 'edit_repo_statistics': '/{repo_name}/settings/statistics', }[name].format(**kwargs) if params: @@ -64,6 +68,11 @@ class TestAdminRepoSettings(object): 'edit_repo_caches', 'edit_repo_perms', 'edit_repo_advanced', + 'edit_repo_vcs', + 'edit_repo_issuetracker', + 'edit_repo_fields', + 'edit_repo_remote', + 'edit_repo_statistics', ]) def test_show_page(self, urlname, app, backend): app.get(route_path(urlname, repo_name=backend.repo_name), status=200) @@ -75,16 +84,6 @@ class TestAdminRepoSettings(object): with scm_patcher: self.app.get(route_path('edit_repo', repo_name=backend_hg.repo_name)) - @pytest.mark.parametrize('urlname', [ - 'repo_vcs_settings', - 'repo_settings_issuetracker', - 'edit_repo_fields', - 'edit_repo_remote', - 'edit_repo_statistics', - ]) - def test_show_page_pylons(self, urlname, app): - app.get(url(urlname, repo_name=HG_REPO)) - @pytest.mark.parametrize('update_settings', [ {'repo_description': 'alter-desc'}, {'repo_owner': TEST_USER_REGULAR_LOGIN}, diff --git a/rhodecode/tests/functional/test_admin_repos.py b/rhodecode/apps/repository/tests/test_repo_vcs_settings.py similarity index 53% rename from rhodecode/tests/functional/test_admin_repos.py rename to rhodecode/apps/repository/tests/test_repo_vcs_settings.py index 2ac30ccb..71dde8cf 100644 --- a/rhodecode/tests/functional/test_admin_repos.py +++ b/rhodecode/apps/repository/tests/test_repo_vcs_settings.py @@ -18,26 +18,21 @@ # RhodeCode Enterprise Edition, including its added features, Support services, # and proprietary license terms, please see https://rhodecode.com/licenses/ -import urllib - import mock import pytest from rhodecode.lib import auth -from rhodecode.lib.utils2 import safe_str, str2bool -from rhodecode.lib import helpers as h +from rhodecode.lib.utils2 import str2bool from rhodecode.model.db import ( - Repository, RepoGroup, UserRepoToPerm, User, Permission) + Repository, UserRepoToPerm, User) from rhodecode.model.meta import Session -from rhodecode.model.repo import RepoModel -from rhodecode.model.repo_group import RepoGroupModel from rhodecode.model.settings import SettingsModel, VcsSettingsModel from rhodecode.model.user import UserModel from rhodecode.tests import ( - login_user_session, url, assert_session_flash, TEST_USER_ADMIN_LOGIN, - TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, logout_user_session) -from rhodecode.tests.fixture import Fixture, error_function -from rhodecode.tests.utils import AssertResponse, repo_on_filesystem + login_user_session, logout_user_session, + TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) +from rhodecode.tests.fixture import Fixture +from rhodecode.tests.utils import AssertResponse fixture = Fixture() @@ -48,6 +43,10 @@ def route_path(name, params=None, **kwargs): base_url = { 'repo_summary': '/{repo_name}', 'repo_creating_check': '/{repo_name}/repo_creating_check', + 'edit_repo': '/{repo_name}/settings', + 'edit_repo_vcs': '/{repo_name}/settings/vcs', + 'edit_repo_vcs_update': '/{repo_name}/settings/vcs/update', + 'edit_repo_vcs_svn_pattern_delete': '/{repo_name}/settings/vcs/svn_pattern/delete' }[name].format(**kwargs) if params: @@ -55,447 +54,6 @@ def route_path(name, params=None, **kwargs): return base_url -@pytest.mark.usefixtures("app") -class TestAdminRepos(object): - - def test_index(self): - self.app.get(url('repos')) - - def test_create_page_restricted(self, autologin_user, backend): - with mock.patch('rhodecode.BACKENDS', {'git': 'git'}): - response = self.app.get(url('new_repo'), status=200) - assert_response = AssertResponse(response) - element = assert_response.get_element('#repo_type') - assert element.text_content() == '\ngit\n' - - def test_create_page_non_restricted(self, autologin_user, backend): - response = self.app.get(url('new_repo'), status=200) - assert_response = AssertResponse(response) - assert_response.element_contains('#repo_type', 'git') - assert_response.element_contains('#repo_type', 'svn') - assert_response.element_contains('#repo_type', 'hg') - - @pytest.mark.parametrize("suffix", - [u'', u'xxa'], ids=['', 'non-ascii']) - def test_create(self, autologin_user, backend, suffix, csrf_token): - repo_name_unicode = backend.new_repo_name(suffix=suffix) - repo_name = repo_name_unicode.encode('utf8') - description_unicode = u'description for newly created repo' + suffix - description = description_unicode.encode('utf8') - response = self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - csrf_token=csrf_token), - status=302) - - self.assert_repository_is_created_correctly( - repo_name, description, backend) - - def test_create_numeric(self, autologin_user, backend, csrf_token): - numeric_repo = '1234' - repo_name = numeric_repo - description = 'description for newly created repo' + numeric_repo - self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - csrf_token=csrf_token)) - - self.assert_repository_is_created_correctly( - repo_name, description, backend) - - @pytest.mark.parametrize("suffix", [u'', u'ąćę'], ids=['', 'non-ascii']) - def test_create_in_group( - self, autologin_user, backend, suffix, csrf_token): - # create GROUP - group_name = 'sometest_%s' % backend.alias - gr = RepoGroupModel().create(group_name=group_name, - group_description='test', - owner=TEST_USER_ADMIN_LOGIN) - Session().commit() - - repo_name = u'ingroup' + suffix - repo_name_full = RepoGroup.url_sep().join( - [group_name, repo_name]) - description = u'description for newly created repo' - self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=safe_str(repo_name), - repo_type=backend.alias, - repo_description=description, - repo_group=gr.group_id, - csrf_token=csrf_token)) - - # TODO: johbo: Cleanup work to fixture - try: - self.assert_repository_is_created_correctly( - repo_name_full, description, backend) - - new_repo = RepoModel().get_by_repo_name(repo_name_full) - inherited_perms = UserRepoToPerm.query().filter( - UserRepoToPerm.repository_id == new_repo.repo_id).all() - assert len(inherited_perms) == 1 - finally: - RepoModel().delete(repo_name_full) - RepoGroupModel().delete(group_name) - Session().commit() - - def test_create_in_group_numeric( - self, autologin_user, backend, csrf_token): - # create GROUP - group_name = 'sometest_%s' % backend.alias - gr = RepoGroupModel().create(group_name=group_name, - group_description='test', - owner=TEST_USER_ADMIN_LOGIN) - Session().commit() - - repo_name = '12345' - repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) - description = 'description for newly created repo' - self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - repo_group=gr.group_id, - csrf_token=csrf_token)) - - # TODO: johbo: Cleanup work to fixture - try: - self.assert_repository_is_created_correctly( - repo_name_full, description, backend) - - new_repo = RepoModel().get_by_repo_name(repo_name_full) - inherited_perms = UserRepoToPerm.query()\ - .filter(UserRepoToPerm.repository_id == new_repo.repo_id).all() - assert len(inherited_perms) == 1 - finally: - RepoModel().delete(repo_name_full) - RepoGroupModel().delete(group_name) - Session().commit() - - def test_create_in_group_without_needed_permissions(self, backend): - session = login_user_session( - self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) - csrf_token = auth.get_csrf_token(session) - # revoke - user_model = UserModel() - # disable fork and create on default user - user_model.revoke_perm(User.DEFAULT_USER, 'hg.create.repository') - user_model.grant_perm(User.DEFAULT_USER, 'hg.create.none') - user_model.revoke_perm(User.DEFAULT_USER, 'hg.fork.repository') - user_model.grant_perm(User.DEFAULT_USER, 'hg.fork.none') - - # disable on regular user - user_model.revoke_perm(TEST_USER_REGULAR_LOGIN, 'hg.create.repository') - user_model.grant_perm(TEST_USER_REGULAR_LOGIN, 'hg.create.none') - user_model.revoke_perm(TEST_USER_REGULAR_LOGIN, 'hg.fork.repository') - user_model.grant_perm(TEST_USER_REGULAR_LOGIN, 'hg.fork.none') - Session().commit() - - # create GROUP - group_name = 'reg_sometest_%s' % backend.alias - gr = RepoGroupModel().create(group_name=group_name, - group_description='test', - owner=TEST_USER_ADMIN_LOGIN) - Session().commit() - - group_name_allowed = 'reg_sometest_allowed_%s' % backend.alias - gr_allowed = RepoGroupModel().create( - group_name=group_name_allowed, - group_description='test', - owner=TEST_USER_REGULAR_LOGIN) - Session().commit() - - repo_name = 'ingroup' - description = 'description for newly created repo' - response = self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - repo_group=gr.group_id, - csrf_token=csrf_token)) - - response.mustcontain('Invalid value') - - # user is allowed to create in this group - repo_name = 'ingroup' - repo_name_full = RepoGroup.url_sep().join( - [group_name_allowed, repo_name]) - description = 'description for newly created repo' - response = self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - repo_group=gr_allowed.group_id, - csrf_token=csrf_token)) - - # TODO: johbo: Cleanup in pytest fixture - try: - self.assert_repository_is_created_correctly( - repo_name_full, description, backend) - - new_repo = RepoModel().get_by_repo_name(repo_name_full) - inherited_perms = UserRepoToPerm.query().filter( - UserRepoToPerm.repository_id == new_repo.repo_id).all() - assert len(inherited_perms) == 1 - - assert repo_on_filesystem(repo_name_full) - finally: - RepoModel().delete(repo_name_full) - RepoGroupModel().delete(group_name) - RepoGroupModel().delete(group_name_allowed) - Session().commit() - - def test_create_in_group_inherit_permissions(self, autologin_user, backend, - csrf_token): - # create GROUP - group_name = 'sometest_%s' % backend.alias - gr = RepoGroupModel().create(group_name=group_name, - group_description='test', - owner=TEST_USER_ADMIN_LOGIN) - perm = Permission.get_by_key('repository.write') - RepoGroupModel().grant_user_permission( - gr, TEST_USER_REGULAR_LOGIN, perm) - - # add repo permissions - Session().commit() - - repo_name = 'ingroup_inherited_%s' % backend.alias - repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) - description = 'description for newly created repo' - self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - repo_group=gr.group_id, - repo_copy_permissions=True, - csrf_token=csrf_token)) - - # TODO: johbo: Cleanup to pytest fixture - try: - self.assert_repository_is_created_correctly( - repo_name_full, description, backend) - except Exception: - RepoGroupModel().delete(group_name) - Session().commit() - raise - - # check if inherited permissions are applied - new_repo = RepoModel().get_by_repo_name(repo_name_full) - inherited_perms = UserRepoToPerm.query().filter( - UserRepoToPerm.repository_id == new_repo.repo_id).all() - assert len(inherited_perms) == 2 - - assert TEST_USER_REGULAR_LOGIN in [ - x.user.username for x in inherited_perms] - assert 'repository.write' in [ - x.permission.permission_name for x in inherited_perms] - - RepoModel().delete(repo_name_full) - RepoGroupModel().delete(group_name) - Session().commit() - - @pytest.mark.xfail_backends( - "git", "hg", reason="Missing reposerver support") - def test_create_with_clone_uri(self, autologin_user, backend, reposerver, - csrf_token): - source_repo = backend.create_repo(number_of_commits=2) - source_repo_name = source_repo.repo_name - reposerver.serve(source_repo.scm_instance()) - - repo_name = backend.new_repo_name() - response = self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description='', - clone_uri=reposerver.url, - csrf_token=csrf_token), - status=302) - - # Should be redirected to the creating page - response.mustcontain('repo_creating') - - # Expecting that both repositories have same history - source_repo = RepoModel().get_by_repo_name(source_repo_name) - source_vcs = source_repo.scm_instance() - repo = RepoModel().get_by_repo_name(repo_name) - repo_vcs = repo.scm_instance() - assert source_vcs[0].message == repo_vcs[0].message - assert source_vcs.count() == repo_vcs.count() - assert source_vcs.commit_ids == repo_vcs.commit_ids - - @pytest.mark.xfail_backends("svn", reason="Depends on import support") - def test_create_remote_repo_wrong_clone_uri(self, autologin_user, backend, - csrf_token): - repo_name = backend.new_repo_name() - description = 'description for newly created repo' - response = self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - clone_uri='http://repo.invalid/repo', - csrf_token=csrf_token)) - response.mustcontain('invalid clone url') - - @pytest.mark.xfail_backends("svn", reason="Depends on import support") - def test_create_remote_repo_wrong_clone_uri_hg_svn( - self, autologin_user, backend, csrf_token): - repo_name = backend.new_repo_name() - description = 'description for newly created repo' - response = self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - clone_uri='svn+http://svn.invalid/repo', - csrf_token=csrf_token)) - response.mustcontain('invalid clone url') - - def test_create_with_git_suffix( - self, autologin_user, backend, csrf_token): - repo_name = backend.new_repo_name() + ".git" - description = 'description for newly created repo' - response = self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - csrf_token=csrf_token)) - response.mustcontain('Repository name cannot end with .git') - - def test_show(self, autologin_user, backend): - self.app.get(url('repo', repo_name=backend.repo_name)) - - def test_default_user_cannot_access_private_repo_in_a_group( - self, autologin_user, user_util, backend, csrf_token): - - group = user_util.create_repo_group() - - repo = backend.create_repo( - repo_private=True, repo_group=group, repo_copy_permissions=True) - - permissions = _get_permission_for_user( - user='default', repo=repo.repo_name) - assert len(permissions) == 1 - assert permissions[0].permission.permission_name == 'repository.none' - assert permissions[0].repository.private is True - - def test_create_on_top_level_without_permissions(self, backend): - session = login_user_session( - self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) - csrf_token = auth.get_csrf_token(session) - - # revoke - user_model = UserModel() - # disable fork and create on default user - user_model.revoke_perm(User.DEFAULT_USER, 'hg.create.repository') - user_model.grant_perm(User.DEFAULT_USER, 'hg.create.none') - user_model.revoke_perm(User.DEFAULT_USER, 'hg.fork.repository') - user_model.grant_perm(User.DEFAULT_USER, 'hg.fork.none') - - # disable on regular user - user_model.revoke_perm(TEST_USER_REGULAR_LOGIN, 'hg.create.repository') - user_model.grant_perm(TEST_USER_REGULAR_LOGIN, 'hg.create.none') - user_model.revoke_perm(TEST_USER_REGULAR_LOGIN, 'hg.fork.repository') - user_model.grant_perm(TEST_USER_REGULAR_LOGIN, 'hg.fork.none') - Session().commit() - - repo_name = backend.new_repo_name() - description = 'description for newly created repo' - response = self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - csrf_token=csrf_token)) - - response.mustcontain( - u"You do not have the permission to store repositories in " - u"the root location.") - - @mock.patch.object(RepoModel, '_create_filesystem_repo', error_function) - def test_create_repo_when_filesystem_op_fails( - self, autologin_user, backend, csrf_token): - repo_name = backend.new_repo_name() - description = 'description for newly created repo' - - response = self.app.post( - url('repos'), - fixture._get_repo_create_params( - repo_private=False, - repo_name=repo_name, - repo_type=backend.alias, - repo_description=description, - csrf_token=csrf_token)) - - assert_session_flash( - response, 'Error creating repository %s' % repo_name) - # repo must not be in db - assert backend.repo is None - # repo must not be in filesystem ! - assert not repo_on_filesystem(repo_name) - - def assert_repository_is_created_correctly( - self, repo_name, description, backend): - repo_name_utf8 = safe_str(repo_name) - - # run the check page that triggers the flash message - response = self.app.get( - route_path('repo_creating_check', repo_name=safe_str(repo_name))) - assert response.json == {u'result': True} - - flash_msg = u'Created repository {}'.format( - urllib.quote(repo_name_utf8), repo_name) - assert_session_flash(response, flash_msg) - - # test if the repo was created in the database - new_repo = RepoModel().get_by_repo_name(repo_name) - - assert new_repo.repo_name == repo_name - assert new_repo.description == description - - # test if the repository is visible in the list ? - response = self.app.get( - h.route_path('repo_summary', repo_name=safe_str(repo_name))) - response.mustcontain(repo_name) - response.mustcontain(backend.alias) - - assert repo_on_filesystem(repo_name) - - @pytest.mark.usefixtures("app") class TestVcsSettings(object): FORM_DATA = { @@ -515,7 +73,7 @@ class TestVcsSettings(object): @pytest.mark.skip_backends('svn') def test_global_settings_initial_values(self, autologin_user, backend): repo_name = backend.repo_name - response = self.app.get(url('repo_vcs_settings', repo_name=repo_name)) + response = self.app.get(route_path('edit_repo_vcs', repo_name=repo_name)) expected_settings = ( 'rhodecode_use_outdated_comments', 'rhodecode_pr_merge_enabled', @@ -533,12 +91,12 @@ class TestVcsSettings(object): user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') login_user_session( self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) - self.app.get(url('repo_vcs_settings', repo_name=repo_name), status=200) + self.app.get(route_path('edit_repo_vcs', repo_name=repo_name), status=200) def test_inherit_global_settings_flag_is_true_by_default( self, autologin_user, backend): repo_name = backend.repo_name - response = self.app.get(url('repo_vcs_settings', repo_name=repo_name)) + response = self.app.get(route_path('edit_repo_vcs', repo_name=repo_name)) assert_response = AssertResponse(response) element = assert_response.get_element('#inherit_global_settings') @@ -551,7 +109,7 @@ class TestVcsSettings(object): repo_name = repo.repo_name settings_util.create_repo_rhodecode_setting( repo, 'inherit_vcs_settings', checked_value, 'bool') - response = self.app.get(url('repo_vcs_settings', repo_name=repo_name)) + response = self.app.get(route_path('edit_repo_vcs', repo_name=repo_name)) assert_response = AssertResponse(response) element = assert_response.get_element('#inherit_global_settings') @@ -564,7 +122,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) try: for section, key in VcsSettingsModel.HOOKS_SETTINGS: @@ -579,7 +137,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) try: for section, key in VcsSettingsModel.HOOKS_SETTINGS: @@ -599,7 +157,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) try: for section, key in VcsSettingsModel.HOOKS_SETTINGS: ui = settings.get_ui_by_section_and_key(section, key) @@ -617,7 +175,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) try: for section, key in VcsSettingsModel.HOOKS_SETTINGS: ui = settings.get_ui_by_section_and_key(section, key) @@ -632,7 +190,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) try: for name in VcsSettingsModel.GENERAL_SETTINGS: @@ -647,7 +205,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) try: for name in VcsSettingsModel.GENERAL_SETTINGS: @@ -675,7 +233,7 @@ class TestVcsSettings(object): try: self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) finally: self._cleanup_repo_settings(settings) @@ -691,7 +249,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) try: for name in VcsSettingsModel.GENERAL_SETTINGS: setting = settings.get_setting_by_name(name) @@ -709,7 +267,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) try: for name in VcsSettingsModel.GENERAL_SETTINGS: setting = settings.get_setting_by_name(name) @@ -733,7 +291,7 @@ class TestVcsSettings(object): VcsSettingsModel.SVN_TAG_SECTION, 'svn-tag') self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) try: svn_branches = settings.get_ui_by_section( @@ -761,7 +319,7 @@ class TestVcsSettings(object): repo, VcsSettingsModel.SVN_TAG_SECTION, 'test_tag') response = self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=200) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=200) response.mustcontain('Pattern already exists') def test_svn_settings_with_empty_values_are_not_created( @@ -770,7 +328,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) try: svn_branches = settings.get_ui_by_section( @@ -786,7 +344,7 @@ class TestVcsSettings(object): self, autologin_user, backend_svn, csrf_token): repo_name = backend_svn.repo_name response = self.app.get( - url('repo_vcs_settings', repo_name=repo_name), status=200) + route_path('edit_repo_vcs', repo_name=repo_name), status=200) response.mustcontain('Subversion Settings') @pytest.mark.skip_backends('svn') @@ -796,7 +354,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) try: svn_branches = settings.get_ui_by_section( @@ -813,7 +371,7 @@ class TestVcsSettings(object): self, autologin_user, backend, csrf_token): repo_name = backend.repo_name response = self.app.get( - url('repo_vcs_settings', repo_name=repo_name), status=200) + route_path('edit_repo_vcs', repo_name=repo_name), status=200) response.mustcontain(no='Subversion Settings') def test_hg_settings_are_created( @@ -824,7 +382,7 @@ class TestVcsSettings(object): data['new_svn_branch'] = 'svn-branch' data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) try: largefiles_ui = settings.get_ui_by_section_and_key( @@ -848,7 +406,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) try: largefiles_ui = settings.get_ui_by_section_and_key( 'extensions', 'largefiles') @@ -863,7 +421,7 @@ class TestVcsSettings(object): self, autologin_user, backend_hg, csrf_token): repo_name = backend_hg.repo_name response = self.app.get( - url('repo_vcs_settings', repo_name=repo_name), status=200) + route_path('edit_repo_vcs', repo_name=repo_name), status=200) response.mustcontain('Mercurial Settings') @pytest.mark.skip_backends('hg') @@ -873,7 +431,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) try: largefiles_ui = settings.get_ui_by_section_and_key( @@ -890,7 +448,7 @@ class TestVcsSettings(object): self, autologin_user, backend, csrf_token): repo_name = backend.repo_name response = self.app.get( - url('repo_vcs_settings', repo_name=repo_name), status=200) + route_path('edit_repo_vcs', repo_name=repo_name), status=200) response.mustcontain(no='Mercurial Settings') @pytest.mark.skip_backends('hg') @@ -906,7 +464,7 @@ class TestVcsSettings(object): data = self.FORM_DATA.copy() data['csrf_token'] = csrf_token self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) try: largefiles_ui = settings.get_ui_by_section_and_key( 'extensions', 'largefiles') @@ -932,7 +490,7 @@ class TestVcsSettings(object): for i in range(10)] response = self.app.get( - url('repo_vcs_settings', repo_name=repo_name), status=200) + route_path('edit_repo_vcs', repo_name=repo_name), status=200) assert_response = AssertResponse(response) for branch in branches: css_selector = '[name=branch_value_{}]'.format(branch.ui_id) @@ -948,7 +506,7 @@ class TestVcsSettings(object): repo = backend_svn.create_repo() repo_name = repo.repo_name response = self.app.get( - url('repo_vcs_settings', repo_name=repo_name), status=200) + route_path('edit_repo_vcs', repo_name=repo_name), status=200) response.mustcontain(no='') response.mustcontain(no='') @@ -959,7 +517,7 @@ class TestVcsSettings(object): data['csrf_token'] = csrf_token data['inherit_global_settings'] = True self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) vcs_settings = VcsSettingsModel(repo=repo_name) @@ -977,10 +535,10 @@ class TestVcsSettings(object): settings = SettingsModel(repo=repo_name) invalidation_patcher = mock.patch( - 'rhodecode.controllers.admin.repos.ScmModel.mark_for_invalidation') + 'rhodecode.model.scm.ScmModel.mark_for_invalidation') with invalidation_patcher as invalidation_mock: self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) try: invalidation_mock.assert_called_once_with(repo_name, delete=True) @@ -994,7 +552,7 @@ class TestVcsSettings(object): data['csrf_token'] = csrf_token data['inherit_global_settings'] = True self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, status=302) + route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) settings = SettingsModel(repo=repo_name) ui_settings = ( @@ -1019,7 +577,7 @@ class TestVcsSettings(object): self._cleanup_repo_settings(settings) def test_delete_svn_branch_and_tag_patterns( - self, autologin_user, backend_svn, settings_util, csrf_token): + self, autologin_user, backend_svn, settings_util, csrf_token, xhr_header): repo = backend_svn.create_repo() repo_name = repo.repo_name branch = settings_util.create_repo_rhodecode_ui( @@ -1028,19 +586,18 @@ class TestVcsSettings(object): tag = settings_util.create_repo_rhodecode_ui( repo, VcsSettingsModel.SVN_TAG_SECTION, 'test_tag', cleanup=False) data = { - '_method': 'delete', 'csrf_token': csrf_token } for id_ in (branch.ui_id, tag.ui_id): data['delete_svn_pattern'] = id_, self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, - headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) + route_path('edit_repo_vcs_svn_pattern_delete', repo_name=repo_name), + data, extra_environ=xhr_header, status=200) settings = VcsSettingsModel(repo=repo_name) assert settings.get_repo_svn_branch_patterns() == [] def test_delete_svn_branch_requires_repo_admin_permission( - self, backend_svn, user_util, settings_util, csrf_token): + self, backend_svn, user_util, settings_util, csrf_token, xhr_header): repo = backend_svn.create_repo() repo_name = repo.repo_name @@ -1056,36 +613,33 @@ class TestVcsSettings(object): repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch', cleanup=False) data = { - '_method': 'delete', 'csrf_token': csrf_token, 'delete_svn_pattern': branch.ui_id } self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, - headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) + route_path('edit_repo_vcs_svn_pattern_delete', repo_name=repo_name), + data, extra_environ=xhr_header, status=200) def test_delete_svn_branch_raises_400_when_not_found( - self, autologin_user, backend_svn, settings_util, csrf_token): + self, autologin_user, backend_svn, settings_util, csrf_token, xhr_header): repo_name = backend_svn.repo_name data = { - '_method': 'delete', 'delete_svn_pattern': 123, 'csrf_token': csrf_token } self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, - headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=400) + route_path('edit_repo_vcs_svn_pattern_delete', repo_name=repo_name), + data, extra_environ=xhr_header, status=400) def test_delete_svn_branch_raises_400_when_no_id_specified( - self, autologin_user, backend_svn, settings_util, csrf_token): + self, autologin_user, backend_svn, settings_util, csrf_token, xhr_header): repo_name = backend_svn.repo_name data = { - '_method': 'delete', 'csrf_token': csrf_token } self.app.post( - url('repo_vcs_settings', repo_name=repo_name), data, - headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=400) + route_path('edit_repo_vcs_svn_pattern_delete', repo_name=repo_name), + data, extra_environ=xhr_header, status=400) def _cleanup_repo_settings(self, settings_model): cleanup = [] diff --git a/rhodecode/apps/repository/tests/test_vcs_settings.py b/rhodecode/apps/repository/tests/test_vcs_settings.py index 206077ee..4fc127ff 100644 --- a/rhodecode/apps/repository/tests/test_vcs_settings.py +++ b/rhodecode/apps/repository/tests/test_vcs_settings.py @@ -24,7 +24,6 @@ import pytest import rhodecode from rhodecode.model.db import Repository from rhodecode.model.settings import SettingsModel -from rhodecode.tests import url from rhodecode.tests.utils import AssertResponse @@ -33,6 +32,8 @@ def route_path(name, params=None, **kwargs): base_url = { 'edit_repo': '/{repo_name}/settings', + 'edit_repo_vcs': '/{repo_name}/settings/vcs', + 'edit_repo_vcs_update': '/{repo_name}/settings/vcs/update', }[name].format(**kwargs) if params: @@ -51,8 +52,8 @@ class TestAdminRepoVcsSettings(object): if backend.alias not in setting_backends: pytest.skip('Setting not available for backend {}'.format(backend)) - vcs_settings_url = url( - 'repo_vcs_settings', repo_name=backend.repo.repo_name) + vcs_settings_url = route_path( + 'edit_repo_vcs', repo_name=backend.repo.repo_name) with mock.patch.dict( rhodecode.CONFIG, {'labs_settings_active': 'true'}): @@ -61,24 +62,6 @@ class TestAdminRepoVcsSettings(object): assertr = AssertResponse(response) assertr.one_element_exists('#rhodecode_{}'.format(setting_name)) - @pytest.mark.parametrize('setting_name, setting_backends', [ - ('hg_use_rebase_for_merging', ['hg']), - ]) - def test_labs_settings_not_visible_if_disabled( - self, setting_name, setting_backends, backend): - if backend.alias not in setting_backends: - pytest.skip('Setting not available for backend {}'.format(backend)) - - vcs_settings_url = url( - 'repo_vcs_settings', repo_name=backend.repo.repo_name) - - with mock.patch.dict( - rhodecode.CONFIG, {'labs_settings_active': 'false'}): - response = self.app.get(vcs_settings_url) - - assertr = AssertResponse(response) - assertr.no_element_exists('#rhodecode_{}'.format(setting_name)) - @pytest.mark.parametrize('setting_name, setting_backends', [ ('hg_use_rebase_for_merging', ['hg']), ]) @@ -91,8 +74,8 @@ class TestAdminRepoVcsSettings(object): repo_name = repo.repo_name settings_model = SettingsModel(repo=repo) - vcs_settings_url = url( - 'repo_vcs_settings', repo_name=repo_name) + vcs_settings_url = route_path( + 'edit_repo_vcs_update', repo_name=repo_name) self.app.post( vcs_settings_url, diff --git a/rhodecode/apps/repository/views/repo_commits.py b/rhodecode/apps/repository/views/repo_commits.py index 301d98f6..02da8067 100644 --- a/rhodecode/apps/repository/views/repo_commits.py +++ b/rhodecode/apps/repository/views/repo_commits.py @@ -36,7 +36,7 @@ from rhodecode.lib.auth import ( from rhodecode.lib.compat import OrderedDict from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError import rhodecode.lib.helpers as h -from rhodecode.lib.utils2 import safe_unicode, safe_int +from rhodecode.lib.utils2 import safe_unicode from rhodecode.lib.vcs.backends.base import EmptyCommit from rhodecode.lib.vcs.exceptions import ( RepositoryError, CommitDoesNotExistError, NodeDoesNotExistError) diff --git a/rhodecode/apps/repository/views/repo_feed.py b/rhodecode/apps/repository/views/repo_feed.py index 8a53cdcb..357ae4b4 100644 --- a/rhodecode/apps/repository/views/repo_feed.py +++ b/rhodecode/apps/repository/views/repo_feed.py @@ -29,10 +29,9 @@ from webhelpers.feedgenerator import Rss201rev2Feed, Atom1Feed from rhodecode.apps._base import RepoAppView from rhodecode.lib import audit_logger from rhodecode.lib import helpers as h -from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator, - NotAnonymous, CSRFRequired) +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator) from rhodecode.lib.diffs import DiffProcessor, LimitedDiffContainer -from rhodecode.lib.ext_json import json from rhodecode.lib.utils2 import str2bool, safe_int from rhodecode.model.db import UserApiKeys, CacheKey diff --git a/rhodecode/apps/repository/views/repo_maintainance.py b/rhodecode/apps/repository/views/repo_maintainance.py index 9e8274e7..f0dac266 100644 --- a/rhodecode/apps/repository/views/repo_maintainance.py +++ b/rhodecode/apps/repository/views/repo_maintainance.py @@ -23,8 +23,7 @@ import logging from pyramid.view import view_config from rhodecode.apps._base import RepoAppView -from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator, - NotAnonymous) +from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator from rhodecode.lib import repo_maintenance log = logging.getLogger(__name__) @@ -43,7 +42,7 @@ class RepoMaintenanceView(RepoAppView): @LoginRequired() @HasRepoPermissionAnyDecorator('repository.admin') @view_config( - route_name='repo_maintenance', request_method='GET', + route_name='edit_repo_maintenance', request_method='GET', renderer='rhodecode:templates/admin/repos/repo_edit.mako') def repo_maintenance(self): c = self.load_default_context() @@ -55,7 +54,7 @@ class RepoMaintenanceView(RepoAppView): @LoginRequired() @HasRepoPermissionAnyDecorator('repository.admin') @view_config( - route_name='repo_maintenance_execute', request_method='GET', + route_name='edit_repo_maintenance_execute', request_method='GET', renderer='json', xhr=True) def repo_maintenance_execute(self): c = self.load_default_context() diff --git a/rhodecode/apps/repository/views/repo_permissions.py b/rhodecode/apps/repository/views/repo_permissions.py index 305cf3b0..5b1974e7 100644 --- a/rhodecode/apps/repository/views/repo_permissions.py +++ b/rhodecode/apps/repository/views/repo_permissions.py @@ -20,23 +20,17 @@ import logging -import deform from pyramid.httpexceptions import HTTPFound from pyramid.view import view_config from rhodecode.apps._base import RepoAppView -from rhodecode.forms import RcForm from rhodecode.lib import helpers as h from rhodecode.lib import audit_logger from rhodecode.lib.auth import ( - LoginRequired, HasRepoPermissionAnyDecorator, - HasRepoPermissionAllDecorator, CSRFRequired) -from rhodecode.model.db import RepositoryField, RepoGroup + LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) from rhodecode.model.forms import RepoPermsForm from rhodecode.model.meta import Session from rhodecode.model.repo import RepoModel -from rhodecode.model.scm import RepoGroupList, ScmModel -from rhodecode.model.validation_schema.schemas import repo_schema log = logging.getLogger(__name__) @@ -63,7 +57,7 @@ class RepoSettingsPermissionsView(RepoAppView): return self._get_template_context(c) @LoginRequired() - @HasRepoPermissionAllDecorator('repository.admin') + @HasRepoPermissionAnyDecorator('repository.admin') @CSRFRequired() @view_config( route_name='edit_repo_perms', request_method='POST', @@ -74,7 +68,7 @@ class RepoSettingsPermissionsView(RepoAppView): c.active = 'permissions' data = self.request.POST # store private flag outside of HTML to verify if we can modify - # default user permissions, prevents submition of FAKE post data + # default user permissions, prevents submission of FAKE post data # into the form for private repos data['repo_private'] = self.db_repo.private form = RepoPermsForm()().to_python(data) @@ -95,4 +89,4 @@ class RepoSettingsPermissionsView(RepoAppView): h.flash(_('Repository permissions updated'), category='success') raise HTTPFound( - self.request.route_path('edit_repo_perms', repo_name=self.db_repo_name)) + h.route_path('edit_repo_perms', repo_name=self.db_repo_name)) diff --git a/rhodecode/apps/repository/views/repo_settings.py b/rhodecode/apps/repository/views/repo_settings.py index dcf8be72..08b870c8 100644 --- a/rhodecode/apps/repository/views/repo_settings.py +++ b/rhodecode/apps/repository/views/repo_settings.py @@ -29,9 +29,8 @@ from rhodecode.forms import RcForm from rhodecode.lib import helpers as h from rhodecode.lib import audit_logger from rhodecode.lib.auth import ( - LoginRequired, HasRepoPermissionAnyDecorator, - HasRepoPermissionAllDecorator, CSRFRequired) -from rhodecode.model.db import RepositoryField, RepoGroup + LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) +from rhodecode.model.db import RepositoryField, RepoGroup, Repository from rhodecode.model.meta import Session from rhodecode.model.repo import RepoModel from rhodecode.model.scm import RepoGroupList, ScmModel @@ -109,7 +108,7 @@ class RepoSettingsView(RepoAppView): return self._get_template_context(c) @LoginRequired() - @HasRepoPermissionAllDecorator('repository.admin') + @HasRepoPermissionAnyDecorator('repository.admin') @CSRFRequired() @view_config( route_name='edit_repo', request_method='POST', @@ -176,4 +175,80 @@ class RepoSettingsView(RepoAppView): old_repo_name), category='error') raise HTTPFound( - self.request.route_path('edit_repo', repo_name=new_repo_name)) + h.route_path('edit_repo', repo_name=new_repo_name)) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + @view_config( + route_name='repo_edit_toggle_locking', request_method='GET', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def toggle_locking(self): + """ + Toggle locking of repository by simple GET call to url + """ + _ = self.request.translate + repo = self.db_repo + + try: + if repo.enable_locking: + if repo.locked[0]: + Repository.unlock(repo) + action = _('Unlocked') + else: + Repository.lock( + repo, self._rhodecode_user.user_id, + lock_reason=Repository.LOCK_WEB) + action = _('Locked') + + h.flash(_('Repository has been %s') % action, + category='success') + except Exception: + log.exception("Exception during unlocking") + h.flash(_('An error occurred during unlocking'), + category='error') + raise HTTPFound( + h.route_path('repo_summary', repo_name=self.db_repo_name)) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @view_config( + route_name='edit_repo_statistics', request_method='GET', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def edit_statistics_form(self): + c = self.load_default_context() + + if self.db_repo.stats: + # this is on what revision we ended up so we add +1 for count + last_rev = self.db_repo.stats.stat_on_revision + 1 + else: + last_rev = 0 + + c.active = 'statistics' + c.stats_revision = last_rev + c.repo_last_rev = self.rhodecode_vcs_repo.count() + + if last_rev == 0 or c.repo_last_rev == 0: + c.stats_percentage = 0 + else: + c.stats_percentage = '%.2f' % ( + (float((last_rev)) / c.repo_last_rev) * 100) + return self._get_template_context(c) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo_statistics_reset', request_method='POST', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_statistics_reset(self): + _ = self.request.translate + + try: + RepoModel().delete_stats(self.db_repo_name) + Session().commit() + except Exception: + log.exception('Edit statistics failure') + h.flash(_('An error occurred during deletion of repository stats'), + category='error') + raise HTTPFound( + h.route_path('edit_repo_statistics', repo_name=self.db_repo_name)) diff --git a/rhodecode/apps/repository/views/repo_settings_advanced.py b/rhodecode/apps/repository/views/repo_settings_advanced.py index 986a36ff..173a0a7f 100644 --- a/rhodecode/apps/repository/views/repo_settings_advanced.py +++ b/rhodecode/apps/repository/views/repo_settings_advanced.py @@ -61,7 +61,7 @@ class RepoSettingsView(RepoAppView): c.default_user_id = User.get_default_user().user_id c.in_public_journal = UserFollowing.query() \ .filter(UserFollowing.user_id == c.default_user_id) \ - .filter(UserFollowing.follows_repository == c.repo_info).scalar() + .filter(UserFollowing.follows_repository == self.db_repo).scalar() c.has_origin_repo_read_perm = False if self.db_repo.fork: diff --git a/rhodecode/apps/repository/views/repo_settings_fields.py b/rhodecode/apps/repository/views/repo_settings_fields.py new file mode 100644 index 00000000..d7c1c891 --- /dev/null +++ b/rhodecode/apps/repository/views/repo_settings_fields.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2017-2017 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +import formencode + +from pyramid.httpexceptions import HTTPFound +from pyramid.view import view_config + +from rhodecode.apps._base import RepoAppView +from rhodecode.lib import audit_logger +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) +from rhodecode.model.db import RepositoryField +from rhodecode.model.forms import RepoFieldForm +from rhodecode.model.meta import Session +from rhodecode.model.repo import RepoModel + +log = logging.getLogger(__name__) + + +class RepoSettingsFieldsView(RepoAppView): + def load_default_context(self): + c = self._get_local_tmpl_context() + + # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead + c.repo_info = self.db_repo + + self._register_global_c(c) + return c + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @view_config( + route_name='edit_repo_fields', request_method='GET', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_field_edit(self): + c = self.load_default_context() + + c.active = 'fields' + c.repo_fields = RepositoryField.query() \ + .filter(RepositoryField.repository == self.db_repo).all() + + return self._get_template_context(c) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo_fields_create', request_method='POST', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_field_create(self): + _ = self.request.translate + + try: + form_result = RepoFieldForm()().to_python(dict(self.request.POST)) + RepoModel().add_repo_field( + self.db_repo_name, + form_result['new_field_key'], + field_type=form_result['new_field_type'], + field_value=form_result['new_field_value'], + field_label=form_result['new_field_label'], + field_desc=form_result['new_field_desc']) + + Session().commit() + except Exception as e: + log.exception("Exception creating field") + msg = _('An error occurred during creation of field') + if isinstance(e, formencode.Invalid): + msg += ". " + e.msg + h.flash(msg, category='error') + + raise HTTPFound( + h.route_path('edit_repo_fields', repo_name=self.db_repo_name)) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo_fields_delete', request_method='POST', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_field_delete(self): + _ = self.request.translate + field = RepositoryField.get_or_404(self.request.matchdict['field_id']) + try: + RepoModel().delete_repo_field(self.db_repo_name, field.field_key) + Session().commit() + except Exception: + log.exception('Exception during removal of field') + msg = _('An error occurred during removal of field') + h.flash(msg, category='error') + + raise HTTPFound( + h.route_path('edit_repo_fields', repo_name=self.db_repo_name)) diff --git a/rhodecode/apps/repository/views/repo_settings_issue_trackers.py b/rhodecode/apps/repository/views/repo_settings_issue_trackers.py new file mode 100644 index 00000000..8c6c3fea --- /dev/null +++ b/rhodecode/apps/repository/views/repo_settings_issue_trackers.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2017-2017 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +from pyramid.httpexceptions import HTTPFound +from pyramid.view import view_config + +from rhodecode.apps._base import RepoAppView +from rhodecode.lib import audit_logger +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) +from rhodecode.model.forms import IssueTrackerPatternsForm +from rhodecode.model.meta import Session +from rhodecode.model.settings import IssueTrackerSettingsModel + +log = logging.getLogger(__name__) + + +class RepoSettingsIssueTrackersView(RepoAppView): + def load_default_context(self): + c = self._get_local_tmpl_context() + + # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead + c.repo_info = self.db_repo + + self._register_global_c(c) + return c + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @view_config( + route_name='edit_repo_issuetracker', request_method='GET', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_issuetracker(self): + c = self.load_default_context() + c.active = 'issuetracker' + c.data = 'data' + + c.settings_model = IssueTrackerSettingsModel(repo=self.db_repo) + c.global_patterns = c.settings_model.get_global_settings() + c.repo_patterns = c.settings_model.get_repo_settings() + + return self._get_template_context(c) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo_issuetracker_test', request_method='POST', + xhr=True, renderer='string') + def repo_issuetracker_test(self): + return h.urlify_commit_message( + self.request.POST.get('test_text', ''), + self.db_repo_name) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo_issuetracker_delete', request_method='POST', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_issuetracker_delete(self): + _ = self.request.translate + uid = self.request.POST.get('uid') + repo_settings = IssueTrackerSettingsModel(repo=self.db_repo_name) + try: + repo_settings.delete_entries(uid) + except Exception: + h.flash(_('Error occurred during deleting issue tracker entry'), + category='error') + else: + h.flash(_('Removed issue tracker entry'), category='success') + raise HTTPFound( + h.route_path('edit_repo_issuetracker', repo_name=self.db_repo_name)) + + def _update_patterns(self, form, repo_settings): + for uid in form['delete_patterns']: + repo_settings.delete_entries(uid) + + for pattern_data in form['patterns']: + for setting_key, pattern, type_ in pattern_data: + sett = repo_settings.create_or_update_setting( + setting_key, pattern.strip(), type_) + Session().add(sett) + + Session().commit() + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo_issuetracker_update', request_method='POST', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_issuetracker_update(self): + _ = self.request.translate + # Save inheritance + repo_settings = IssueTrackerSettingsModel(repo=self.db_repo_name) + inherited = ( + self.request.POST.get('inherit_global_issuetracker') == "inherited") + repo_settings.inherit_global_settings = inherited + Session().commit() + + form = IssueTrackerPatternsForm()().to_python(self.request.POST) + if form: + self._update_patterns(form, repo_settings) + + h.flash(_('Updated issue tracker entries'), category='success') + raise HTTPFound( + h.route_path('edit_repo_issuetracker', repo_name=self.db_repo_name)) + diff --git a/rhodecode/apps/repository/views/repo_settings_remote.py b/rhodecode/apps/repository/views/repo_settings_remote.py new file mode 100644 index 00000000..eaecb6b0 --- /dev/null +++ b/rhodecode/apps/repository/views/repo_settings_remote.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2017-2017 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +from pyramid.httpexceptions import HTTPFound +from pyramid.view import view_config + +from rhodecode.apps._base import RepoAppView +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import ( + LoginRequired, CSRFRequired, HasRepoPermissionAnyDecorator) +from rhodecode.model.scm import ScmModel + +log = logging.getLogger(__name__) + + +class RepoSettingsRemoteView(RepoAppView): + def load_default_context(self): + c = self._get_local_tmpl_context() + + # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead + c.repo_info = self.db_repo + + self._register_global_c(c) + return c + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @view_config( + route_name='edit_repo_remote', request_method='GET', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_remote_edit_form(self): + c = self.load_default_context() + c.active = 'remote' + + return self._get_template_context(c) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo_remote_pull', request_method='POST', + renderer=None) + def repo_remote_pull_changes(self): + _ = self.request.translate + self.load_default_context() + + try: + ScmModel().pull_changes( + self.db_repo_name, self._rhodecode_user.username) + h.flash(_('Pulled from remote location'), category='success') + except Exception: + log.exception("Exception during pull from remote") + h.flash(_('An error occurred during pull from remote location'), + category='error') + raise HTTPFound( + h.route_path('edit_repo_remote', repo_name=self.db_repo_name)) diff --git a/rhodecode/apps/repository/views/repo_settings_vcs.py b/rhodecode/apps/repository/views/repo_settings_vcs.py new file mode 100644 index 00000000..95c0bcee --- /dev/null +++ b/rhodecode/apps/repository/views/repo_settings_vcs.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2017-2017 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +import formencode +from pyramid.httpexceptions import HTTPFound, HTTPBadRequest +from pyramid.response import Response +from pyramid.renderers import render +from pyramid.view import view_config + +from rhodecode.apps._base import RepoAppView +from rhodecode.lib import audit_logger +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) +from rhodecode.model.forms import RepoVcsSettingsForm +from rhodecode.model.meta import Session +from rhodecode.model.settings import VcsSettingsModel, SettingNotFound + +log = logging.getLogger(__name__) + + +class RepoSettingsVcsView(RepoAppView): + def load_default_context(self): + c = self._get_local_tmpl_context() + + # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead + c.repo_info = self.db_repo + + self._register_global_c(c) + return c + + def _vcs_form_defaults(self, repo_name): + model = VcsSettingsModel(repo=repo_name) + global_defaults = model.get_global_settings() + + repo_defaults = {} + repo_defaults.update(global_defaults) + repo_defaults.update(model.get_repo_settings()) + + global_defaults = { + '{}_inherited'.format(k): global_defaults[k] + for k in global_defaults} + + defaults = { + 'inherit_global_settings': model.inherit_global_settings + } + defaults.update(global_defaults) + defaults.update(repo_defaults) + defaults.update({ + 'new_svn_branch': '', + 'new_svn_tag': '', + }) + return defaults + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @view_config( + route_name='edit_repo_vcs', request_method='GET', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_vcs_settings(self): + c = self.load_default_context() + model = VcsSettingsModel(repo=self.db_repo_name) + + c.active = 'vcs' + c.global_svn_branch_patterns = model.get_global_svn_branch_patterns() + c.global_svn_tag_patterns = model.get_global_svn_tag_patterns() + c.svn_branch_patterns = model.get_repo_svn_branch_patterns() + c.svn_tag_patterns = model.get_repo_svn_tag_patterns() + + defaults = self._vcs_form_defaults(self.db_repo_name) + c.inherit_global_settings = defaults['inherit_global_settings'] + + data = render('rhodecode:templates/admin/repos/repo_edit.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo_vcs_update', request_method='POST', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def repo_settings_vcs_update(self): + _ = self.request.translate + c = self.load_default_context() + c.active = 'vcs' + + model = VcsSettingsModel(repo=self.db_repo_name) + c.global_svn_branch_patterns = model.get_global_svn_branch_patterns() + c.global_svn_tag_patterns = model.get_global_svn_tag_patterns() + c.svn_branch_patterns = model.get_repo_svn_branch_patterns() + c.svn_tag_patterns = model.get_repo_svn_tag_patterns() + + defaults = self._vcs_form_defaults(self.db_repo_name) + c.inherit_global_settings = defaults['inherit_global_settings'] + + application_form = RepoVcsSettingsForm(self.db_repo_name)() + try: + form_result = application_form.to_python(dict(self.request.POST)) + except formencode.Invalid as errors: + h.flash(_("Some form inputs contain invalid data."), + category='error') + + data = render('rhodecode:templates/admin/repos/repo_edit.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=errors.value, + errors=errors.error_dict or {}, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + try: + inherit_global_settings = form_result['inherit_global_settings'] + model.create_or_update_repo_settings( + form_result, inherit_global_settings=inherit_global_settings) + Session().commit() + h.flash(_('Updated VCS settings'), category='success') + except Exception: + log.exception("Exception while updating settings") + h.flash( + _('Error occurred during updating repository VCS settings'), + category='error') + + raise HTTPFound( + h.route_path('edit_repo_vcs', repo_name=self.db_repo_name)) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo_vcs_svn_pattern_delete', request_method='POST', + renderer='json_ext', xhr=True) + def repo_settings_delete_svn_pattern(self): + self.load_default_context() + delete_pattern_id = self.request.POST.get('delete_svn_pattern') + model = VcsSettingsModel(repo=self.db_repo_name) + try: + model.delete_repo_svn_pattern(delete_pattern_id) + except SettingNotFound: + log.exception('Failed to delete SVN pattern') + raise HTTPBadRequest() + + Session().commit() + return True diff --git a/rhodecode/apps/repository/views/repo_strip.py b/rhodecode/apps/repository/views/repo_strip.py index c711b41e..854ad964 100644 --- a/rhodecode/apps/repository/views/repo_strip.py +++ b/rhodecode/apps/repository/views/repo_strip.py @@ -24,8 +24,8 @@ from pyramid.view import view_config from rhodecode.apps._base import RepoAppView from rhodecode.lib import audit_logger from rhodecode.lib import helpers as h -from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator, - NotAnonymous, CSRFRequired) +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) from rhodecode.lib.ext_json import json log = logging.getLogger(__name__) @@ -44,7 +44,7 @@ class StripView(RepoAppView): @LoginRequired() @HasRepoPermissionAnyDecorator('repository.admin') @view_config( - route_name='strip', request_method='GET', + route_name='edit_repo_strip', request_method='GET', renderer='rhodecode:templates/admin/repos/repo_edit.mako') def strip(self): c = self.load_default_context() @@ -99,10 +99,10 @@ class StripView(RepoAppView): continue try: ScmModel().strip( - repo=c.repo_info, + repo=self.db_repo, commit_id=commit['rev'], branch=commit['branch']) log.info('Stripped commit %s from repo `%s` by %s' % ( - commit['rev'], c.repo_info.repo_name, user)) + commit['rev'], self.db_repo_name, user)) data[commit['rev']] = True audit_logger.store_web( diff --git a/rhodecode/apps/repository/views/repo_summary.py b/rhodecode/apps/repository/views/repo_summary.py index bc10ff10..5c8f915e 100644 --- a/rhodecode/apps/repository/views/repo_summary.py +++ b/rhodecode/apps/repository/views/repo_summary.py @@ -22,12 +22,9 @@ import logging import string from pyramid.view import view_config - from beaker.cache import cache_region - from rhodecode.controllers import utils - from rhodecode.apps._base import RepoAppView from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP) from rhodecode.lib import caches, helpers as h @@ -74,11 +71,16 @@ class RepoSummaryView(RepoAppView): log.debug("Searching for a README file.") readme_node = ReadmeFinder(default_renderer).search(commit) if readme_node: - relative_url = h.route_path( - 'repo_file_raw', repo_name=repo_name, - commit_id=commit.raw_id, f_path=readme_node.path) + relative_urls = { + 'raw': h.route_path( + 'repo_file_raw', repo_name=repo_name, + commit_id=commit.raw_id, f_path=readme_node.path), + 'standard': h.route_path( + 'repo_files', repo_name=repo_name, + commit_id=commit.raw_id, f_path=readme_node.path), + } readme_data = self._render_readme_or_none( - commit, readme_node, relative_url) + commit, readme_node, relative_urls) readme_filename = readme_node.path return readme_data, readme_filename @@ -103,15 +105,15 @@ class RepoSummaryView(RepoAppView): log.exception( "Problem getting commit when trying to render the README.") - def _render_readme_or_none(self, commit, readme_node, relative_url): + def _render_readme_or_none(self, commit, readme_node, relative_urls): log.debug( 'Found README file `%s` rendering...', readme_node.path) renderer = MarkupRenderer() try: html_source = renderer.render( readme_node.content, filename=readme_node.path) - if relative_url: - return relative_links(html_source, relative_url) + if relative_urls: + return relative_links(html_source, relative_urls) return html_source except Exception: log.exception( diff --git a/rhodecode/config/environment.py b/rhodecode/config/environment.py index ddf0e3b0..4df00eb2 100644 --- a/rhodecode/config/environment.py +++ b/rhodecode/config/environment.py @@ -143,6 +143,8 @@ def load_pyramid_environment(global_config, settings): # Store the settings to make them available to other modules. rhodecode.PYRAMID_SETTINGS = settings_merged + # NOTE(marcink): needs to be enabled after full port to pyramid + # rhodecode.CONFIG = config # If this is a test run we prepare the test environment like # creating a test database, test search index and test repositories. diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py index 8598d8a4..fd33839a 100644 --- a/rhodecode/config/routing.py +++ b/rhodecode/config/routing.py @@ -176,23 +176,6 @@ def make_map(config): rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping') rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test') - # ADMIN REPOSITORY ROUTES - with rmap.submapper(path_prefix=ADMIN_PREFIX, - controller='admin/repos') as m: - m.connect('repos', '/repos', - action='create', conditions={'method': ['POST']}) - m.connect('repos', '/repos', - action='index', conditions={'method': ['GET']}) - m.connect('new_repo', '/create_repository', jsroute=True, - action='create_repository', conditions={'method': ['GET']}) - m.connect('delete_repo', '/repos/{repo_name}', - action='delete', conditions={'method': ['DELETE']}, - requirements=URL_NAME_REQUIREMENTS) - m.connect('repo', '/repos/{repo_name}', - action='show', conditions={'method': ['GET'], - 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - # ADMIN REPOSITORY GROUPS ROUTES with rmap.submapper(path_prefix=ADMIN_PREFIX, controller='admin/repo_groups') as m: @@ -406,81 +389,5 @@ def make_map(config): m.connect('my_account_password', '/my_account/password', action='my_account_password', conditions={'method': ['GET']}) - #========================================================================== - # REPOSITORY ROUTES - #========================================================================== - - # repo edit options - rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields', - controller='admin/repos', action='edit_fields', - conditions={'method': ['GET'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new', - controller='admin/repos', action='create_repo_field', - conditions={'method': ['PUT'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}', - controller='admin/repos', action='delete_repo_field', - conditions={'method': ['DELETE'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - - rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle', - controller='admin/repos', action='toggle_locking', - conditions={'method': ['GET'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - - rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', - controller='admin/repos', action='edit_remote_form', - conditions={'method': ['GET'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', - controller='admin/repos', action='edit_remote', - conditions={'method': ['PUT'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - - rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics', - controller='admin/repos', action='edit_statistics_form', - conditions={'method': ['GET'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics', - controller='admin/repos', action='edit_statistics', - conditions={'method': ['PUT'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('repo_settings_issuetracker', - '/{repo_name}/settings/issue-tracker', - controller='admin/repos', action='repo_issuetracker', - conditions={'method': ['GET'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('repo_issuetracker_test', - '/{repo_name}/settings/issue-tracker/test', - controller='admin/repos', action='repo_issuetracker_test', - conditions={'method': ['POST'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('repo_issuetracker_delete', - '/{repo_name}/settings/issue-tracker/delete', - controller='admin/repos', action='repo_issuetracker_delete', - conditions={'method': ['DELETE'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('repo_issuetracker_save', - '/{repo_name}/settings/issue-tracker/save', - controller='admin/repos', action='repo_issuetracker_save', - conditions={'method': ['POST'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', - controller='admin/repos', action='repo_settings_vcs_update', - conditions={'method': ['POST'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', - controller='admin/repos', action='repo_settings_vcs', - conditions={'method': ['GET'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', - controller='admin/repos', action='repo_delete_svn_pattern', - conditions={'method': ['DELETE'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest', - controller='admin/repos', action='repo_settings_pullrequest', - conditions={'method': ['GET', 'POST'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) return rmap diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py deleted file mode 100644 index 58b7bdad..00000000 --- a/rhodecode/controllers/admin/repos.py +++ /dev/null @@ -1,563 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (C) 2013-2017 RhodeCode GmbH -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License, version 3 -# (only), as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# This program is dual-licensed. If you wish to learn more about the -# RhodeCode Enterprise Edition, including its added features, Support services, -# and proprietary license terms, please see https://rhodecode.com/licenses/ - - -""" -Repositories controller for RhodeCode -""" - -import logging -import traceback - -import formencode -from formencode import htmlfill -from pylons import request, tmpl_context as c, url -from pylons.controllers.util import redirect -from pylons.i18n.translation import _ -from webob.exc import HTTPForbidden, HTTPBadRequest - -from pyramid.httpexceptions import HTTPFound -import rhodecode -from rhodecode.lib import auth, helpers as h -from rhodecode.lib.auth import ( - LoginRequired, HasPermissionAllDecorator, - HasRepoPermissionAllDecorator, NotAnonymous, HasPermissionAny, - HasRepoGroupPermissionAny, HasRepoPermissionAnyDecorator) -from rhodecode.lib.base import BaseRepoController, render -from rhodecode.lib.ext_json import json -from rhodecode.lib.utils import repo_name_slug, jsonify -from rhodecode.lib.utils2 import safe_int, str2bool -from rhodecode.model.db import (Repository, RepoGroup, RepositoryField) -from rhodecode.model.forms import ( - RepoForm, RepoFieldForm, RepoVcsSettingsForm, IssueTrackerPatternsForm) -from rhodecode.model.meta import Session -from rhodecode.model.repo import RepoModel -from rhodecode.model.scm import ScmModel, RepoGroupList, RepoList -from rhodecode.model.settings import ( - SettingsModel, IssueTrackerSettingsModel, VcsSettingsModel, - SettingNotFound) - -log = logging.getLogger(__name__) - - -class ReposController(BaseRepoController): - """ - REST Controller styled on the Atom Publishing Protocol""" - # To properly map this controller, ensure your config/routing.py - # file has a resource setup: - # map.resource('repo', 'repos') - - @LoginRequired() - def __before__(self): - super(ReposController, self).__before__() - - def _load_repo(self, repo_name): - repo_obj = Repository.get_by_repo_name(repo_name) - - if repo_obj is None: - h.not_mapped_error(repo_name) - return redirect(url('repos')) - - return repo_obj - - def __load_defaults(self, repo=None): - acl_groups = RepoGroupList(RepoGroup.query().all(), - perm_set=['group.write', 'group.admin']) - c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) - c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) - - # in case someone no longer have a group.write access to a repository - # pre fill the list with this entry, we don't care if this is the same - # but it will allow saving repo data properly. - - repo_group = None - if repo: - repo_group = repo.group - if repo_group and unicode(repo_group.group_id) not in c.repo_groups_choices: - c.repo_groups_choices.append(unicode(repo_group.group_id)) - c.repo_groups.append(RepoGroup._generate_choice(repo_group)) - - choices, c.landing_revs = ScmModel().get_repo_landing_revs() - c.landing_revs_choices = choices - - def __load_data(self, repo_name=None): - """ - Load defaults settings for edit, and update - - :param repo_name: - """ - c.repo_info = self._load_repo(repo_name) - self.__load_defaults(c.repo_info) - - # override defaults for exact repo info here git/hg etc - if not c.repository_requirements_missing: - choices, c.landing_revs = ScmModel().get_repo_landing_revs( - c.repo_info) - c.landing_revs_choices = choices - defaults = RepoModel()._get_defaults(repo_name) - - return defaults - - def _log_creation_exception(self, e, repo_name): - reason = None - if len(e.args) == 2: - reason = e.args[1] - - if reason == 'INVALID_CERTIFICATE': - log.exception( - 'Exception creating a repository: invalid certificate') - msg = (_('Error creating repository %s: invalid certificate') - % repo_name) - else: - log.exception("Exception creating a repository") - msg = (_('Error creating repository %s') - % repo_name) - - return msg - - @NotAnonymous() - def index(self, format='html'): - """GET /repos: All items in the collection""" - # url('repos') - - repo_list = Repository.get_all_repos() - c.repo_list = RepoList(repo_list, perm_set=['repository.admin']) - repos_data = RepoModel().get_repos_as_dict( - repo_list=c.repo_list, admin=True, super_user_actions=True) - # json used to render the grid - c.data = json.dumps(repos_data) - - return render('admin/repos/repos.mako') - - # perms check inside - @NotAnonymous() - @auth.CSRFRequired() - def create(self): - """ - POST /repos: Create a new item""" - # url('repos') - - self.__load_defaults() - form_result = {} - task_id = None - c.personal_repo_group = c.rhodecode_user.personal_repo_group - try: - # CanWriteToGroup validators checks permissions of this POST - form_result = RepoForm(repo_groups=c.repo_groups_choices, - landing_revs=c.landing_revs_choices)()\ - .to_python(dict(request.POST)) - - # create is done sometimes async on celery, db transaction - # management is handled there. - task = RepoModel().create(form_result, c.rhodecode_user.user_id) - from celery.result import BaseAsyncResult - if isinstance(task, BaseAsyncResult): - task_id = task.task_id - except formencode.Invalid as errors: - return htmlfill.render( - render('admin/repos/repo_add.mako'), - defaults=errors.value, - errors=errors.error_dict or {}, - prefix_error=False, - encoding="UTF-8", - force_defaults=False) - - except Exception as e: - msg = self._log_creation_exception(e, form_result.get('repo_name')) - h.flash(msg, category='error') - return redirect(h.route_path('home')) - - raise HTTPFound( - h.route_path('repo_creating', - repo_name=form_result['repo_name_full'], - _query=dict(task_id=task_id))) - - # perms check inside - @NotAnonymous() - def create_repository(self): - """GET /_admin/create_repository: Form to create a new item""" - new_repo = request.GET.get('repo', '') - parent_group = safe_int(request.GET.get('parent_group')) - _gr = RepoGroup.get(parent_group) - - if not HasPermissionAny('hg.admin', 'hg.create.repository')(): - # you're not super admin nor have global create permissions, - # but maybe you have at least write permission to a parent group ? - - gr_name = _gr.group_name if _gr else None - # create repositories with write permission on group is set to true - create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')() - group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name) - group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name) - if not (group_admin or (group_write and create_on_write)): - raise HTTPForbidden - - acl_groups = RepoGroupList(RepoGroup.query().all(), - perm_set=['group.write', 'group.admin']) - c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) - c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) - choices, c.landing_revs = ScmModel().get_repo_landing_revs() - c.personal_repo_group = c.rhodecode_user.personal_repo_group - c.new_repo = repo_name_slug(new_repo) - - # apply the defaults from defaults page - defaults = SettingsModel().get_default_repo_settings(strip_prefix=True) - # set checkbox to autochecked - defaults['repo_copy_permissions'] = True - - parent_group_choice = '-1' - if not c.rhodecode_user.is_admin and c.rhodecode_user.personal_repo_group: - parent_group_choice = c.rhodecode_user.personal_repo_group - - if parent_group and _gr: - if parent_group in [x[0] for x in c.repo_groups]: - parent_group_choice = unicode(parent_group) - - defaults.update({'repo_group': parent_group_choice}) - - return htmlfill.render( - render('admin/repos/repo_add.mako'), - defaults=defaults, - errors={}, - prefix_error=False, - encoding="UTF-8", - force_defaults=False - ) - - @HasPermissionAllDecorator('hg.admin') - def show(self, repo_name, format='html'): - """GET /repos/repo_name: Show a specific item""" - # url('repo', repo_name=ID) - - @HasRepoPermissionAllDecorator('repository.admin') - def edit_fields(self, repo_name): - """GET /repo_name/settings: Form to edit an existing item""" - c.repo_info = self._load_repo(repo_name) - c.repo_fields = RepositoryField.query()\ - .filter(RepositoryField.repository == c.repo_info).all() - c.active = 'fields' - if request.POST: - - return redirect(url('repo_edit_fields')) - return render('admin/repos/repo_edit.mako') - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() - def create_repo_field(self, repo_name): - try: - form_result = RepoFieldForm()().to_python(dict(request.POST)) - RepoModel().add_repo_field( - repo_name, form_result['new_field_key'], - field_type=form_result['new_field_type'], - field_value=form_result['new_field_value'], - field_label=form_result['new_field_label'], - field_desc=form_result['new_field_desc']) - - Session().commit() - except Exception as e: - log.exception("Exception creating field") - msg = _('An error occurred during creation of field') - if isinstance(e, formencode.Invalid): - msg += ". " + e.msg - h.flash(msg, category='error') - return redirect(url('edit_repo_fields', repo_name=repo_name)) - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() - def delete_repo_field(self, repo_name, field_id): - field = RepositoryField.get_or_404(field_id) - try: - RepoModel().delete_repo_field(repo_name, field.field_key) - Session().commit() - except Exception as e: - log.exception("Exception during removal of field") - msg = _('An error occurred during removal of field') - h.flash(msg, category='error') - return redirect(url('edit_repo_fields', repo_name=repo_name)) - - @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') - @auth.CSRFRequired() - def toggle_locking(self, repo_name): - """ - Toggle locking of repository by simple GET call to url - - :param repo_name: - """ - - try: - repo = Repository.get_by_repo_name(repo_name) - - if repo.enable_locking: - if repo.locked[0]: - Repository.unlock(repo) - action = _('Unlocked') - else: - Repository.lock(repo, c.rhodecode_user.user_id, - lock_reason=Repository.LOCK_WEB) - action = _('Locked') - - h.flash(_('Repository has been %s') % action, - category='success') - except Exception: - log.exception("Exception during unlocking") - h.flash(_('An error occurred during unlocking'), - category='error') - return redirect(h.route_path('repo_summary', repo_name=repo_name)) - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() - def edit_remote(self, repo_name): - """PUT /{repo_name}/settings/remote: edit the repo remote.""" - try: - ScmModel().pull_changes(repo_name, c.rhodecode_user.username) - h.flash(_('Pulled from remote location'), category='success') - except Exception: - log.exception("Exception during pull from remote") - h.flash(_('An error occurred during pull from remote location'), - category='error') - return redirect(url('edit_repo_remote', repo_name=c.repo_name)) - - @HasRepoPermissionAllDecorator('repository.admin') - def edit_remote_form(self, repo_name): - """GET /repo_name/settings: Form to edit an existing item""" - c.repo_info = self._load_repo(repo_name) - c.active = 'remote' - - return render('admin/repos/repo_edit.mako') - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() - def edit_statistics(self, repo_name): - """PUT /{repo_name}/settings/statistics: reset the repo statistics.""" - try: - RepoModel().delete_stats(repo_name) - Session().commit() - except Exception as e: - log.error(traceback.format_exc()) - h.flash(_('An error occurred during deletion of repository stats'), - category='error') - return redirect(url('edit_repo_statistics', repo_name=c.repo_name)) - - @HasRepoPermissionAllDecorator('repository.admin') - def edit_statistics_form(self, repo_name): - """GET /repo_name/settings: Form to edit an existing item""" - c.repo_info = self._load_repo(repo_name) - repo = c.repo_info.scm_instance() - - if c.repo_info.stats: - # this is on what revision we ended up so we add +1 for count - last_rev = c.repo_info.stats.stat_on_revision + 1 - else: - last_rev = 0 - c.stats_revision = last_rev - - c.repo_last_rev = repo.count() - - if last_rev == 0 or c.repo_last_rev == 0: - c.stats_percentage = 0 - else: - c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100) - - c.active = 'statistics' - - return render('admin/repos/repo_edit.mako') - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() - def repo_issuetracker_test(self, repo_name): - if request.is_xhr: - return h.urlify_commit_message( - request.POST.get('test_text', ''), - repo_name) - else: - raise HTTPBadRequest() - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() - def repo_issuetracker_delete(self, repo_name): - uid = request.POST.get('uid') - repo_settings = IssueTrackerSettingsModel(repo=repo_name) - try: - repo_settings.delete_entries(uid) - except Exception: - h.flash(_('Error occurred during deleting issue tracker entry'), - category='error') - else: - h.flash(_('Removed issue tracker entry'), category='success') - return redirect(url('repo_settings_issuetracker', - repo_name=repo_name)) - - def _update_patterns(self, form, repo_settings): - for uid in form['delete_patterns']: - repo_settings.delete_entries(uid) - - for pattern in form['patterns']: - for setting, value, type_ in pattern: - sett = repo_settings.create_or_update_setting( - setting, value, type_) - Session().add(sett) - - Session().commit() - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() - def repo_issuetracker_save(self, repo_name): - # Save inheritance - repo_settings = IssueTrackerSettingsModel(repo=repo_name) - inherited = (request.POST.get('inherit_global_issuetracker') - == "inherited") - repo_settings.inherit_global_settings = inherited - Session().commit() - - form = IssueTrackerPatternsForm()().to_python(request.POST) - if form: - self._update_patterns(form, repo_settings) - - h.flash(_('Updated issue tracker entries'), category='success') - return redirect(url('repo_settings_issuetracker', - repo_name=repo_name)) - - @HasRepoPermissionAllDecorator('repository.admin') - def repo_issuetracker(self, repo_name): - """GET /admin/settings/issue-tracker: All items in the collection""" - c.active = 'issuetracker' - c.data = 'data' - c.repo_info = self._load_repo(repo_name) - - repo = Repository.get_by_repo_name(repo_name) - c.settings_model = IssueTrackerSettingsModel(repo=repo) - c.global_patterns = c.settings_model.get_global_settings() - c.repo_patterns = c.settings_model.get_repo_settings() - - return render('admin/repos/repo_edit.mako') - - @HasRepoPermissionAllDecorator('repository.admin') - def repo_settings_vcs(self, repo_name): - """GET /{repo_name}/settings/vcs/: All items in the collection""" - - model = VcsSettingsModel(repo=repo_name) - - c.active = 'vcs' - c.global_svn_branch_patterns = model.get_global_svn_branch_patterns() - c.global_svn_tag_patterns = model.get_global_svn_tag_patterns() - c.svn_branch_patterns = model.get_repo_svn_branch_patterns() - c.svn_tag_patterns = model.get_repo_svn_tag_patterns() - c.repo_info = self._load_repo(repo_name) - defaults = self._vcs_form_defaults(repo_name) - c.inherit_global_settings = defaults['inherit_global_settings'] - c.labs_active = str2bool( - rhodecode.CONFIG.get('labs_settings_active', 'true')) - - return htmlfill.render( - render('admin/repos/repo_edit.mako'), - defaults=defaults, - encoding="UTF-8", - force_defaults=False) - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() - def repo_settings_vcs_update(self, repo_name): - """POST /{repo_name}/settings/vcs/: All items in the collection""" - c.active = 'vcs' - - model = VcsSettingsModel(repo=repo_name) - c.global_svn_branch_patterns = model.get_global_svn_branch_patterns() - c.global_svn_tag_patterns = model.get_global_svn_tag_patterns() - c.svn_branch_patterns = model.get_repo_svn_branch_patterns() - c.svn_tag_patterns = model.get_repo_svn_tag_patterns() - c.repo_info = self._load_repo(repo_name) - defaults = self._vcs_form_defaults(repo_name) - c.inherit_global_settings = defaults['inherit_global_settings'] - - application_form = RepoVcsSettingsForm(repo_name)() - try: - form_result = application_form.to_python(dict(request.POST)) - except formencode.Invalid as errors: - h.flash( - _("Some form inputs contain invalid data."), - category='error') - return htmlfill.render( - render('admin/repos/repo_edit.mako'), - defaults=errors.value, - errors=errors.error_dict or {}, - prefix_error=False, - encoding="UTF-8", - force_defaults=False - ) - - try: - inherit_global_settings = form_result['inherit_global_settings'] - model.create_or_update_repo_settings( - form_result, inherit_global_settings=inherit_global_settings) - except Exception: - log.exception("Exception while updating settings") - h.flash( - _('Error occurred during updating repository VCS settings'), - category='error') - else: - Session().commit() - h.flash(_('Updated VCS settings'), category='success') - return redirect(url('repo_vcs_settings', repo_name=repo_name)) - - return htmlfill.render( - render('admin/repos/repo_edit.mako'), - defaults=self._vcs_form_defaults(repo_name), - encoding="UTF-8", - force_defaults=False) - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() - @jsonify - def repo_delete_svn_pattern(self, repo_name): - if not request.is_xhr: - return False - - delete_pattern_id = request.POST.get('delete_svn_pattern') - model = VcsSettingsModel(repo=repo_name) - try: - model.delete_repo_svn_pattern(delete_pattern_id) - except SettingNotFound: - raise HTTPBadRequest() - - Session().commit() - return True - - def _vcs_form_defaults(self, repo_name): - model = VcsSettingsModel(repo=repo_name) - global_defaults = model.get_global_settings() - - repo_defaults = {} - repo_defaults.update(global_defaults) - repo_defaults.update(model.get_repo_settings()) - - global_defaults = { - '{}_inherited'.format(k): global_defaults[k] - for k in global_defaults} - - defaults = { - 'inherit_global_settings': model.inherit_global_settings - } - defaults.update(global_defaults) - defaults.update(repo_defaults) - defaults.update({ - 'new_svn_branch': '', - 'new_svn_tag': '', - }) - return defaults diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py index 716293d5..4ae182f0 100644 --- a/rhodecode/controllers/admin/settings.py +++ b/rhodecode/controllers/admin/settings.py @@ -32,6 +32,7 @@ from formencode import htmlfill from pylons import request, tmpl_context as c, url, config from pylons.controllers.util import redirect from pylons.i18n.translation import _ +from pylons.decorators import jsonify from pyramid.threadlocal import get_current_registry from webob.exc import HTTPBadRequest @@ -47,7 +48,6 @@ from rhodecode.lib.utils import repo2db_mapper from rhodecode.lib.utils2 import ( str2bool, safe_unicode, AttributeDict, safe_int) from rhodecode.lib.compat import OrderedDict -from rhodecode.lib.utils import jsonify from rhodecode.model.db import RhodeCodeUi, Repository from rhodecode.model.forms import ApplicationSettingsForm, \ diff --git a/rhodecode/controllers/admin/user_groups.py b/rhodecode/controllers/admin/user_groups.py index 67acabdc..2c723871 100644 --- a/rhodecode/controllers/admin/user_groups.py +++ b/rhodecode/controllers/admin/user_groups.py @@ -31,25 +31,19 @@ from pylons import request, tmpl_context as c, url, config from pylons.controllers.util import redirect from pylons.i18n.translation import _ -from sqlalchemy.orm import joinedload - 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.exceptions import UserGroupAssignedException,\ RepoGroupAssignmentError -from rhodecode.lib.utils import jsonify from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int from rhodecode.lib.auth import ( LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator, HasPermissionAnyDecorator) from rhodecode.lib.base import BaseController, render from rhodecode.model.permission import PermissionModel -from rhodecode.model.scm import UserGroupList from rhodecode.model.user_group import UserGroupModel -from rhodecode.model.db import ( - User, UserGroup, UserGroupRepoToPerm, UserGroupRepoGroupToPerm) +from rhodecode.model.db import User, UserGroup from rhodecode.model.forms import ( UserGroupForm, UserGroupPermsForm, UserIndividualPermissionsForm, UserPermissionsForm) diff --git a/rhodecode/lib/base.py b/rhodecode/lib/base.py index cb1c4db2..eeffb998 100644 --- a/rhodecode/lib/base.py +++ b/rhodecode/lib/base.py @@ -34,15 +34,6 @@ import pyramid.threadlocal from paste.auth.basic import AuthBasicAuthenticator from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION -from pylons import tmpl_context as c, request, url -from pylons.controllers import WSGIController -from pylons.controllers.util import redirect -from pylons.i18n import translation -# marcink: don't remove this import -from pylons.templating import render_mako, pylons_globals, literal, cached_template -from pylons.i18n.translation import _ -from webob.exc import HTTPFound - import rhodecode from rhodecode.authentication.base import VCS_TYPE @@ -55,13 +46,15 @@ from rhodecode.lib.utils import ( get_enabled_hook_classes) from rhodecode.lib.utils2 import ( str2bool, safe_unicode, AttributeDict, safe_int, md5, aslist) -from rhodecode.lib.vcs.exceptions import RepositoryRequirementError from rhodecode.model import meta from rhodecode.model.db import Repository, User, ChangesetComment from rhodecode.model.notification import NotificationModel from rhodecode.model.scm import ScmModel from rhodecode.model.settings import VcsSettingsModel, SettingsModel +# NOTE(marcink): remove after base controller is no longer required +from pylons.controllers import WSGIController +from pylons.i18n import translation log = logging.getLogger(__name__) @@ -75,6 +68,9 @@ def render(template_name, extra_vars=None, cache_key=None, ``cache_expire``. """ + from pylons.templating import literal + from pylons.templating import cached_template, pylons_globals + # Create a render callable for the cache function def render_template(): # Pull in extra vars if needed @@ -411,10 +407,6 @@ def attach_context_attributes(context, request, user_id): 'refresh_time': 120 * 1000, 'cutoff_limit': 1000 * 60 * 60 * 24 * 7 }, - 'pylons_dispatch': { - # 'controller': request.environ['pylons.routes_dict']['controller'], - # 'action': request.environ['pylons.routes_dict']['action'], - }, 'pyramid_dispatch': { }, @@ -512,6 +504,7 @@ class BaseController(WSGIController): """ # on each call propagate settings calls into global settings. from pylons import config + from pylons import tmpl_context as c, request, url set_rhodecode_config(config) attach_context_attributes(c, request, self._rhodecode_user.user_id) @@ -531,6 +524,7 @@ class BaseController(WSGIController): user_lang, self._rhodecode_user) def _dispatch_redirect(self, with_url, environ, start_response): + from webob.exc import HTTPFound resp = HTTPFound(with_url) environ['SCRIPT_NAME'] = '' # handle prefix middleware environ['PATH_INFO'] = with_url @@ -542,6 +536,7 @@ class BaseController(WSGIController): # the request is routed to. This routing information is # available in environ['pylons.routes_dict'] from rhodecode.lib import helpers as h + from pylons import tmpl_context as c, request, url # Provide the Pylons context to Pyramid's debugtoolbar if it asks if environ.get('debugtoolbar.wants_pylons_context', False): @@ -620,93 +615,3 @@ def bootstrap_request(**kwargs): config = pyramid.testing.setUp(request=request) add_events_routes(config) - - -class BaseRepoController(BaseController): - """ - Base class for controllers responsible for loading all needed data for - repository loaded items are - - c.rhodecode_repo: instance of scm repository - c.rhodecode_db_repo: instance of db - c.repository_requirements_missing: shows that repository specific data - could not be displayed due to the missing requirements - c.repository_pull_requests: show number of open pull requests - """ - - def __before__(self): - super(BaseRepoController, self).__before__() - if c.repo_name: # extracted from routes - db_repo = Repository.get_by_repo_name(c.repo_name) - if not db_repo: - return - - log.debug( - 'Found repository in database %s with state `%s`', - safe_unicode(db_repo), safe_unicode(db_repo.repo_state)) - route = getattr(request.environ.get('routes.route'), 'name', '') - - # allow to delete repos that are somehow damages in filesystem - if route in ['delete_repo']: - return - - if db_repo.repo_state in [Repository.STATE_PENDING]: - if route in ['repo_creating_home']: - return - check_url = url('repo_creating_home', repo_name=c.repo_name) - return redirect(check_url) - - self.rhodecode_db_repo = db_repo - - missing_requirements = False - try: - self.rhodecode_repo = self.rhodecode_db_repo.scm_instance() - except RepositoryRequirementError as e: - missing_requirements = True - self._handle_missing_requirements(e) - - if self.rhodecode_repo is None and not missing_requirements: - log.error('%s this repository is present in database but it ' - 'cannot be created as an scm instance', c.repo_name) - - h.flash(_( - "The repository at %(repo_name)s cannot be located.") % - {'repo_name': c.repo_name}, - category='error', ignore_duplicate=True) - redirect(h.route_path('home')) - - # update last change according to VCS data - if not missing_requirements: - commit = db_repo.get_commit( - pre_load=["author", "date", "message", "parents"]) - db_repo.update_commit_cache(commit) - - # Prepare context - c.rhodecode_db_repo = db_repo - c.rhodecode_repo = self.rhodecode_repo - c.repository_requirements_missing = missing_requirements - - self._update_global_counters(self.scm_model, db_repo) - - def _update_global_counters(self, scm_model, db_repo): - """ - Base variables that are exposed to every page of repository - """ - c.repository_pull_requests = scm_model.get_pull_requests(db_repo) - - def _handle_missing_requirements(self, error): - self.rhodecode_repo = None - log.error( - 'Requirements are missing for repository %s: %s', - c.repo_name, error.message) - - summary_url = h.route_path('repo_summary', repo_name=c.repo_name) - statistics_url = url('edit_repo_statistics', repo_name=c.repo_name) - settings_update_url = url('repo', repo_name=c.repo_name) - path = request.path - should_redirect = ( - path not in (summary_url, settings_update_url) - and '/settings' not in path or path == statistics_url - ) - if should_redirect: - redirect(summary_url) diff --git a/rhodecode/lib/rc_commands/__init__.py b/rhodecode/lib/rc_commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py index 3b8ecd7b..0e7de95b 100644 --- a/rhodecode/lib/utils.py +++ b/rhodecode/lib/utils.py @@ -852,30 +852,6 @@ class BasePasterCommand(Command): initialize_database(config) -@decorator.decorator -def jsonify(func, *args, **kwargs): - """Action decorator that formats output for JSON - - Given a function that will return content, this decorator will turn - the result into JSON, with a content-type of 'application/json' and - output it. - - """ - from pylons.decorators.util import get_pylons - from rhodecode.lib.ext_json import json - pylons = get_pylons(args) - pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8' - data = func(*args, **kwargs) - if isinstance(data, (list, tuple)): - msg = "JSON responses with Array envelopes are susceptible to " \ - "cross-site data leak attacks, see " \ - "http://wiki.pylonshq.com/display/pylonsfaq/Warnings" - warnings.warn(msg, Warning, 2) - log.warning(msg) - log.debug("Returning JSON wrapped action output") - return json.dumps(data, encoding='utf-8') - - class PartialRenderer(object): """ Partial renderer used to render chunks of html used in datagrids diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py index 97b88cc0..c049e6df 100644 --- a/rhodecode/model/repo.py +++ b/rhodecode/model/repo.py @@ -18,10 +18,6 @@ # RhodeCode Enterprise Edition, including its added features, Support services, # and proprietary license terms, please see https://rhodecode.com/licenses/ -""" -Repository model for rhodecode -""" - import logging import os import re diff --git a/rhodecode/public/js/rhodecode/base/keyboard-bindings.js b/rhodecode/public/js/rhodecode/base/keyboard-bindings.js index c7463f86..0ea25838 100644 --- a/rhodecode/public/js/rhodecode/base/keyboard-bindings.js +++ b/rhodecode/public/js/rhodecode/base/keyboard-bindings.js @@ -55,7 +55,7 @@ function setRCMouseBindings(repoName, repoLandingRev) { window.location = pyroutes.url('gists_new'); }); Mousetrap.bind(['n r'], function(e) { - window.location = pyroutes.url('new_repo'); + window.location = pyroutes.url('repo_new'); }); if (repoName && repoName != '') { diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js index 39586deb..b1803c6f 100644 --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -12,7 +12,6 @@ ******************************************************************************/ function registerRCRoutes() { // routes registration - pyroutes.register('new_repo', '/_admin/create_repository', []); pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']); pyroutes.register('favicon', '/favicon.ico', []); pyroutes.register('robots', '/robots.txt', []); @@ -82,6 +81,9 @@ function registerRCRoutes() { pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']); pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']); pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']); + pyroutes.register('repos', '/_admin/repos', []); + pyroutes.register('repo_new', '/_admin/repos/new', []); + pyroutes.register('repo_create', '/_admin/repos/create', []); pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []); pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []); pyroutes.register('channelstream_proxy', '/_channelstream', []); @@ -177,11 +179,26 @@ function registerRCRoutes() { pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']); pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); + pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']); + pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']); + pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']); + pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']); + pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']); + pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']); + pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']); + pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']); + pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']); + pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']); + pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']); + pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']); + pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']); + pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']); + pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']); + pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']); + pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']); pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']); pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']); - pyroutes.register('repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']); - pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']); - pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']); + pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']); pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']); pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']); pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']); diff --git a/rhodecode/templates/admin/repos/repo_add.mako b/rhodecode/templates/admin/repos/repo_add.mako index 3ec71cbb..eaf30242 100644 --- a/rhodecode/templates/admin/repos/repo_add.mako +++ b/rhodecode/templates/admin/repos/repo_add.mako @@ -10,9 +10,9 @@ <%def name="breadcrumbs_links()"> %if c.rhodecode_user.is_admin: - ${h.link_to(_('Admin'),h.route_path('admin_home'))} + ${h.link_to(_('Admin'), h.route_path('admin_home'))} » - ${h.link_to(_('Repositories'),h.url('repos'))} + ${h.link_to(_('Repositories'), h.route_path('repos'))} %else: ${_('Admin')} » diff --git a/rhodecode/templates/admin/repos/repo_add_base.mako b/rhodecode/templates/admin/repos/repo_add_base.mako index ba47776a..abcd498f 100644 --- a/rhodecode/templates/admin/repos/repo_add_base.mako +++ b/rhodecode/templates/admin/repos/repo_add_base.mako @@ -1,6 +1,6 @@ ## -*- coding: utf-8 -*- -${h.secure_form(h.url('repos'))} +${h.secure_form(h.route_path('repo_create'), method='POST', request=request)}
diff --git a/rhodecode/templates/admin/repos/repo_edit.mako b/rhodecode/templates/admin/repos/repo_edit.mako index 800d95f0..2024feca 100644 --- a/rhodecode/templates/admin/repos/repo_edit.mako +++ b/rhodecode/templates/admin/repos/repo_edit.mako @@ -52,24 +52,24 @@ ${_('Advanced')}
  • - ${_('VCS')} + ${_('VCS')}
  • - ${_('Extra Fields')} + ${_('Extra Fields')}
  • - ${_('Issue Tracker')} + ${_('Issue Tracker')}
  • ${_('Caches')}
  • %if c.repo_info.repo_type != 'svn':
  • - ${_('Remote')} + ${_('Remote')}
  • %endif
  • - ${_('Statistics')} + ${_('Statistics')}
  • ${_('Integrations')} @@ -80,10 +80,10 @@
  • %endif
  • - ${_('Maintenance')} + ${_('Maintenance')}
  • - ${_('Strip')} + ${_('Strip')}
  • diff --git a/rhodecode/templates/admin/repos/repo_edit_fields.mako b/rhodecode/templates/admin/repos/repo_edit_fields.mako index fa32469a..2bbad84d 100644 --- a/rhodecode/templates/admin/repos/repo_edit_fields.mako +++ b/rhodecode/templates/admin/repos/repo_edit_fields.mako @@ -18,7 +18,7 @@ ${field.field_key} ${field.field_type} - ${h.secure_form(h.url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')} + ${h.secure_form(h.route_path('edit_repo_fields_delete', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id), method='POST', request=request)} ${h.hidden('del_repo_field',field.repo_field_id)}
    %endif - ${h.secure_form(h.url('create_repo_fields', repo_name=c.repo_name),method='put')} + ${h.secure_form(h.route_path('edit_repo_fields_create', repo_name=c.repo_name), method='POST', request=request)}
    diff --git a/rhodecode/templates/admin/repos/repo_edit_issuetracker.mako b/rhodecode/templates/admin/repos/repo_edit_issuetracker.mako index fe4c2106..60c483da 100644 --- a/rhodecode/templates/admin/repos/repo_edit_issuetracker.mako +++ b/rhodecode/templates/admin/repos/repo_edit_issuetracker.mako @@ -1,7 +1,7 @@ <%namespace name="its" file="/base/issue_tracker_settings.mako"/>
    - ${h.secure_form(h.url('repo_issuetracker_save', repo_name=c.repo_name), method='post', id="inherit-form")} + ${h.secure_form(h.route_path('edit_repo_issuetracker_update', repo_name=c.repo_name), id="inherit-form", method='POST', request=request)}
    @@ -72,8 +72,8 @@
    ${its.issue_tracker_settings_table( patterns=c.repo_patterns.items(), - form_url=h.url('repo_settings_issuetracker', repo_name=c.repo_info.repo_name), - delete_url=h.url('repo_issuetracker_delete', repo_name=c.repo_info.repo_name) + form_url=h.route_path('edit_repo_issuetracker', repo_name=c.repo_info.repo_name), + delete_url=h.route_path('edit_repo_issuetracker_delete', repo_name=c.repo_info.repo_name) )}
    @@ -92,7 +92,7 @@
    ${its.issue_tracker_new_row()} - ${its.issue_tracker_settings_test(test_url=h.url('repo_issuetracker_test', repo_name=c.repo_info.repo_name))} + ${its.issue_tracker_settings_test(test_url=h.route_path('edit_repo_issuetracker_test', repo_name=c.repo_info.repo_name))}
    diff --git a/rhodecode/templates/admin/repos/repo_edit_remote.mako b/rhodecode/templates/admin/repos/repo_edit_remote.mako index 3dcd0c98..9a1ec390 100644 --- a/rhodecode/templates/admin/repos/repo_edit_remote.mako +++ b/rhodecode/templates/admin/repos/repo_edit_remote.mako @@ -19,7 +19,7 @@

    - ${h.secure_form(h.url('edit_repo_remote', repo_name=c.repo_name), method='put')} + ${h.secure_form(h.route_path('edit_repo_remote_pull', repo_name=c.repo_name), method='POST', request=request)}
    ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")} diff --git a/rhodecode/templates/admin/repos/repo_edit_settings.mako b/rhodecode/templates/admin/repos/repo_edit_settings.mako index 264ee500..d59fc69f 100644 --- a/rhodecode/templates/admin/repos/repo_edit_settings.mako +++ b/rhodecode/templates/admin/repos/repo_edit_settings.mako @@ -83,7 +83,7 @@ ${h.hidden('repo_clone_uri_change', 'NEW')} %endif

    - <% pull_link = h.literal(h.link_to('remote sync', h.url('edit_repo_remote', repo_name=c.repo_name))) %> + <% pull_link = h.literal(h.link_to('remote sync', h.route_path('edit_repo_remote', repo_name=c.repo_name))) %> ${_('http[s] url where from repository was imported, this field can used for doing {pull_link}.').format(pull_link=pull_link)|n}
    ${_('This field is stored encrypted inside Database, a format of http://user:password@server.com/repo_name can be used and will be hidden from display.')}

    diff --git a/rhodecode/templates/admin/repos/repo_edit_statistics.mako b/rhodecode/templates/admin/repos/repo_edit_statistics.mako index bcd8c5ea..00537b4c 100644 --- a/rhodecode/templates/admin/repos/repo_edit_statistics.mako +++ b/rhodecode/templates/admin/repos/repo_edit_statistics.mako @@ -3,7 +3,7 @@

    ${_('Repository statistics')}

    - ${h.secure_form(h.url('edit_repo_statistics', repo_name=c.repo_info.repo_name), method='put')} + ${h.secure_form(h.route_path('edit_repo_statistics_reset', repo_name=c.repo_info.repo_name), method='POST', request=request)}
    diff --git a/rhodecode/templates/admin/repos/repo_edit_vcs.mako b/rhodecode/templates/admin/repos/repo_edit_vcs.mako index ac373302..32d8b6b9 100644 --- a/rhodecode/templates/admin/repos/repo_edit_vcs.mako +++ b/rhodecode/templates/admin/repos/repo_edit_vcs.mako @@ -1,7 +1,7 @@ <%namespace name="vcss" file="/base/vcs_settings.mako"/>
    - ${h.secure_form(h.url('repo_vcs_settings', repo_name=c.repo_info.repo_name), method='post')} + ${h.secure_form(h.route_path('edit_repo_vcs_update', repo_name=c.repo_info.repo_name), method='POST', request=request)}
    @@ -50,13 +50,12 @@