repo-settings: moved advanced setion into pyramid views.

- improved delete method, and actions.
This commit is contained in:
Marcin Kuzminski 2017-05-16 12:43:58 +02:00
parent 27a8d62042
commit 208136ab4d
13 changed files with 435 additions and 281 deletions

View file

@ -21,6 +21,11 @@
def includeme(config):
# Summary
config.add_route(
name='repo_summary_explicit',
pattern='/{repo_name:.*?[^/]}/summary', repo_route=True)
# Tags
config.add_route(
name='tags_home',
@ -41,6 +46,23 @@ def includeme(config):
name='edit_repo',
pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
# Settings advanced
config.add_route(
name='edit_repo_advanced',
pattern='/{repo_name:.*?[^/]}/settings/advanced', repo_route=True)
config.add_route(
name='edit_repo_advanced_delete',
pattern='/{repo_name:.*?[^/]}/settings/advanced/delete', repo_route=True)
config.add_route(
name='edit_repo_advanced_locking',
pattern='/{repo_name:.*?[^/]}/settings/advanced/locking', repo_route=True)
config.add_route(
name='edit_repo_advanced_journal',
pattern='/{repo_name:.*?[^/]}/settings/advanced/journal', repo_route=True)
config.add_route(
name='edit_repo_advanced_fork',
pattern='/{repo_name:.*?[^/]}/settings/advanced/fork', repo_route=True)
# Caches
config.add_route(
name='edit_repo_caches',
@ -77,5 +99,11 @@ def includeme(config):
config.add_route(
name='strip_execute',
pattern='/{repo_name:.*?[^/]}/settings/strip_execute', repo_route=True)
# NOTE(marcink): needs to be at the end for catch-all
# config.add_route(
# name='repo_summary',
# pattern='/{repo_name:.*?[^/]}', repo_route=True)
# Scan module for configuration decorators.
config.scan()

View file

@ -38,6 +38,7 @@ def route_path(name, params=None, **kwargs):
base_url = {
'edit_repo': '/{repo_name}/settings',
'edit_repo_advanced': '/{repo_name}/settings/advanced',
'edit_repo_caches': '/{repo_name}/settings/caches',
'edit_repo_perms': '/{repo_name}/settings/permissions',
}[name].format(**kwargs)
@ -62,6 +63,7 @@ class TestAdminRepoSettings(object):
'edit_repo',
'edit_repo_caches',
'edit_repo_perms',
'edit_repo_advanced',
])
def test_show_page(self, urlname, app, backend):
app.get(route_path(urlname, repo_name=backend.repo_name), status=200)
@ -74,10 +76,9 @@ class TestAdminRepoSettings(object):
self.app.get(route_path('edit_repo', repo_name=backend_hg.repo_name))
@pytest.mark.parametrize('urlname', [
'edit_repo_advanced',
'repo_vcs_settings',
'edit_repo_fields',
'repo_settings_issuetracker',
'edit_repo_fields',
'edit_repo_remote',
'edit_repo_statistics',
])

View file

@ -0,0 +1,150 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2010-2017 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import pytest
from rhodecode.lib.utils2 import safe_unicode, safe_str
from rhodecode.model.db import Repository
from rhodecode.model.repo import RepoModel
from rhodecode.tests import (
HG_REPO, GIT_REPO, assert_session_flash, no_newline_id_generator)
from rhodecode.tests.fixture import Fixture
from rhodecode.tests.utils import repo_on_filesystem
fixture = Fixture()
def route_path(name, params=None, **kwargs):
import urllib
base_url = {
'repo_summary_explicit': '/{repo_name}/summary',
'repo_summary': '/{repo_name}',
'edit_repo_advanced': '/{repo_name}/settings/advanced',
'edit_repo_advanced_delete': '/{repo_name}/settings/advanced/delete',
'edit_repo_advanced_fork': '/{repo_name}/settings/advanced/fork',
'edit_repo_advanced_locking': '/{repo_name}/settings/advanced/locking',
'edit_repo_advanced_journal': '/{repo_name}/settings/advanced/journal',
}[name].format(**kwargs)
if params:
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
return base_url
@pytest.mark.usefixtures('autologin_user', 'app')
class TestAdminRepoSettingsAdvanced(object):
def test_set_repo_fork_has_no_self_id(self, autologin_user, backend):
repo = backend.repo
response = self.app.get(
route_path('edit_repo_advanced', repo_name=backend.repo_name))
opt = """<option value="%s">vcs_test_git</option>""" % repo.repo_id
response.mustcontain(no=[opt])
def test_set_fork_of_target_repo(
self, autologin_user, backend, csrf_token):
target_repo = 'target_%s' % backend.alias
fixture.create_repo(target_repo, repo_type=backend.alias)
repo2 = Repository.get_by_repo_name(target_repo)
response = self.app.post(
route_path('edit_repo_advanced_fork', repo_name=backend.repo_name),
params={'id_fork_of': repo2.repo_id,
'csrf_token': csrf_token})
repo = Repository.get_by_repo_name(backend.repo_name)
repo2 = Repository.get_by_repo_name(target_repo)
assert_session_flash(
response,
'Marked repo %s as fork of %s' % (repo.repo_name, repo2.repo_name))
assert repo.fork == repo2
response = response.follow()
# check if given repo is selected
opt = 'This repository is a fork of <a href="%s">%s</a>' % (
route_path('repo_summary', repo_name=repo2.repo_name),
repo2.repo_name)
response.mustcontain(opt)
fixture.destroy_repo(target_repo, forks='detach')
@pytest.mark.backends("hg", "git")
def test_set_fork_of_other_type_repo(
self, autologin_user, backend, csrf_token):
TARGET_REPO_MAP = {
'git': {
'type': 'hg',
'repo_name': HG_REPO},
'hg': {
'type': 'git',
'repo_name': GIT_REPO},
}
target_repo = TARGET_REPO_MAP[backend.alias]
repo2 = Repository.get_by_repo_name(target_repo['repo_name'])
response = self.app.post(
route_path('edit_repo_advanced_fork', repo_name=backend.repo_name),
params={'id_fork_of': repo2.repo_id,
'csrf_token': csrf_token})
assert_session_flash(
response,
'Cannot set repository as fork of repository with other type')
def test_set_fork_of_none(self, autologin_user, backend, csrf_token):
# mark it as None
response = self.app.post(
route_path('edit_repo_advanced_fork', repo_name=backend.repo_name),
params={'id_fork_of': None, '_method': 'put',
'csrf_token': csrf_token})
assert_session_flash(
response,
'Marked repo %s as fork of %s'
% (backend.repo_name, "Nothing"))
assert backend.repo.fork is None
def test_set_fork_of_same_repo(self, autologin_user, backend, csrf_token):
repo = Repository.get_by_repo_name(backend.repo_name)
response = self.app.post(
route_path('edit_repo_advanced_fork', repo_name=backend.repo_name),
params={'id_fork_of': repo.repo_id, 'csrf_token': csrf_token})
assert_session_flash(
response, 'An error occurred during this operation')
@pytest.mark.parametrize(
"suffix",
['', u'ąęł' , '123'],
ids=no_newline_id_generator)
def test_advanced_delete(self, autologin_user, backend, suffix, csrf_token):
repo = backend.create_repo(name_suffix=suffix)
repo_name = repo.repo_name
repo_name_str = safe_str(repo.repo_name)
response = self.app.post(
route_path('edit_repo_advanced_delete', repo_name=repo_name_str),
params={'csrf_token': csrf_token})
assert_session_flash(response,
u'Deleted repository `{}`'.format(repo_name))
response.follow()
# check if repo was deleted from db
assert RepoModel().get_by_repo_name(repo_name) is None
assert not repo_on_filesystem(repo_name_str)

View file

@ -0,0 +1,225 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2011-2017 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
from pyramid.view import view_config
from pyramid.httpexceptions import HTTPFound
from rhodecode.apps._base import RepoAppView
from rhodecode.lib import helpers as h
from rhodecode.lib import audit_logger
from rhodecode.lib.auth import (
LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
from rhodecode.lib.exceptions import AttachedForksError
from rhodecode.lib.utils2 import safe_int
from rhodecode.lib.vcs import RepositoryError
from rhodecode.model.db import Session, UserFollowing, User, Repository
from rhodecode.model.repo import RepoModel
from rhodecode.model.scm import ScmModel
log = logging.getLogger(__name__)
class RepoSettingsView(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_advanced', request_method='GET',
renderer='rhodecode:templates/admin/repos/repo_edit.mako')
def edit_advanced(self):
c = self.load_default_context()
c.active = 'advanced'
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()
c.has_origin_repo_read_perm = False
if self.db_repo.fork:
c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
'repository.write', 'repository.read', 'repository.admin')(
self.db_repo.fork.repo_name, 'repo set as fork page')
return self._get_template_context(c)
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.admin')
@view_config(
route_name='edit_repo_advanced_delete', request_method='POST',
renderer='rhodecode:templates/admin/repos/repo_edit.mako')
def edit_advanced_delete(self):
"""
Deletes the repository, or shows warnings if deletion is not possible
because of attached forks or other errors.
"""
_ = self.request.translate
handle_forks = self.request.POST.get('forks', None)
try:
_forks = self.db_repo.forks.count()
if _forks and handle_forks:
if handle_forks == 'detach_forks':
handle_forks = 'detach'
h.flash(_('Detached %s forks') % _forks, category='success')
elif handle_forks == 'delete_forks':
handle_forks = 'delete'
h.flash(_('Deleted %s forks') % _forks, category='success')
repo_data = self.db_repo.get_api_data()
RepoModel().delete(self.db_repo, forks=handle_forks)
repo = audit_logger.RepoWrap(repo_id=self.db_repo.repo_id,
repo_name=self.db_repo.repo_name)
audit_logger.store(
action='repo.delete', action_data={'repo_data': repo_data},
user=self._rhodecode_user, repo=repo, commit=False)
ScmModel().mark_for_invalidation(self.db_repo_name)
h.flash(
_('Deleted repository `%s`') % self.db_repo_name,
category='success')
Session().commit()
except AttachedForksError:
repo_advanced_url = h.route_path(
'edit_repo_advanced', repo_name=self.db_repo_name,
_anchor='advanced-delete')
delete_anchor = h.link_to(_('detach or delete'), repo_advanced_url)
h.flash(_('Cannot delete `{repo}` it still contains attached forks. '
'Try using {delete_or_detach} option.')
.format(repo=self.db_repo_name, delete_or_detach=delete_anchor),
category='warning')
# redirect to advanced for forks handle action ?
raise HTTPFound(repo_advanced_url)
except Exception:
log.exception("Exception during deletion of repository")
h.flash(_('An error occurred during deletion of `%s`')
% self.db_repo_name, category='error')
# redirect to advanced for more deletion options
raise HTTPFound(
h.route_path('edit_repo_advanced', repo_name=self.db_repo_name),
_anchor='advanced-delete')
raise HTTPFound(h.route_path('home'))
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.admin')
@CSRFRequired()
@view_config(
route_name='edit_repo_advanced_journal', request_method='POST',
renderer='rhodecode:templates/admin/repos/repo_edit.mako')
def edit_advanced_journal(self):
"""
Set's this repository to be visible in public journal,
in other words making default user to follow this repo
"""
_ = self.request.translate
try:
user_id = User.get_default_user().user_id
ScmModel().toggle_following_repo(self.db_repo.repo_id, user_id)
h.flash(_('Updated repository visibility in public journal'),
category='success')
Session().commit()
except Exception:
h.flash(_('An error occurred during setting this '
'repository in public journal'),
category='error')
raise HTTPFound(
h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.admin')
@CSRFRequired()
@view_config(
route_name='edit_repo_advanced_fork', request_method='POST',
renderer='rhodecode:templates/admin/repos/repo_edit.mako')
def edit_advanced_fork(self):
"""
Mark given repository as a fork of another
"""
_ = self.request.translate
new_fork_id = self.request.POST.get('id_fork_of')
try:
if new_fork_id and not new_fork_id.isdigit():
log.error('Given fork id %s is not an INT', new_fork_id)
fork_id = safe_int(new_fork_id)
repo = ScmModel().mark_as_fork(
self.db_repo_name, fork_id, self._rhodecode_user.user_id)
fork = repo.fork.repo_name if repo.fork else _('Nothing')
Session().commit()
h.flash(_('Marked repo %s as fork of %s') % (self.db_repo_name, fork),
category='success')
except RepositoryError as e:
log.exception("Repository Error occurred")
h.flash(str(e), category='error')
except Exception as e:
log.exception("Exception while editing fork")
h.flash(_('An error occurred during this operation'),
category='error')
raise HTTPFound(
h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.admin')
@CSRFRequired()
@view_config(
route_name='edit_repo_advanced_locking', request_method='POST',
renderer='rhodecode:templates/admin/repos/repo_edit.mako')
def edit_advanced_locking(self):
"""
Toggle locking of repository
"""
_ = self.request.translate
set_lock = self.request.POST.get('set_lock')
set_unlock = self.request.POST.get('set_unlock')
try:
if set_lock:
Repository.lock(self.db_repo, self._rhodecode_user.user_id,
lock_reason=Repository.LOCK_WEB)
h.flash(_('Locked repository'), category='success')
elif set_unlock:
Repository.unlock(self.db_repo)
h.flash(_('Unlocked repository'), category='success')
except Exception as e:
log.exception("Exception during unlocking")
h.flash(_('An error occurred during unlocking'), category='error')
raise HTTPFound(
h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))

View file

@ -185,7 +185,7 @@ def make_map(config):
#==========================================================================
# MAIN PAGE
rmap.connect('home', '/', controller='home', action='index', jsroute=True)
rmap.connect('home', '/', controller='home', action='index')
# ping and pylons error test
rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
@ -674,30 +674,11 @@ def make_map(config):
conditions={'method': ['DELETE'], 'function': check_repo},
requirements=URL_NAME_REQUIREMENTS)
rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
controller='admin/repos', action='edit_advanced',
conditions={'method': ['GET'], 'function': check_repo},
requirements=URL_NAME_REQUIREMENTS)
rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
controller='admin/repos', action='edit_advanced_locking',
conditions={'method': ['PUT'], '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_advanced_journal', '/{repo_name}/settings/advanced/journal',
controller='admin/repos', action='edit_advanced_journal',
conditions={'method': ['PUT'], 'function': check_repo},
requirements=URL_NAME_REQUIREMENTS)
rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
controller='admin/repos', action='edit_advanced_fork',
conditions={'method': ['PUT'], '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},

View file

@ -288,51 +288,6 @@ class ReposController(BaseRepoController):
return {'result': True}
return {'result': False}
@HasRepoPermissionAllDecorator('repository.admin')
@auth.CSRFRequired()
def delete(self, repo_name):
"""
DELETE /repos/repo_name: Delete an existing item"""
# Forms posted to this method should contain a hidden field:
# <input type="hidden" name="_method" value="DELETE" />
# Or using helpers:
# h.form(url('repo', repo_name=ID),
# method='delete')
# url('repo', repo_name=ID)
repo_model = RepoModel()
repo = repo_model.get_by_repo_name(repo_name)
if not repo:
h.not_mapped_error(repo_name)
return redirect(url('repos'))
try:
_forks = repo.forks.count()
handle_forks = None
if _forks and request.POST.get('forks'):
do = request.POST['forks']
if do == 'detach_forks':
handle_forks = 'detach'
h.flash(_('Detached %s forks') % _forks, category='success')
elif do == 'delete_forks':
handle_forks = 'delete'
h.flash(_('Deleted %s forks') % _forks, category='success')
repo_model.delete(repo, forks=handle_forks)
action_logger(c.rhodecode_user, 'admin_deleted_repo',
repo_name, self.ip_addr, self.sa)
ScmModel().mark_for_invalidation(repo_name)
h.flash(_('Deleted repository %s') % repo_name, category='success')
Session().commit()
except AttachedForksError:
h.flash(_('Cannot delete %s it still contains attached forks')
% repo_name, category='warning')
except Exception:
log.exception("Exception during deletion of repository")
h.flash(_('An error occurred during deletion of %s') % repo_name,
category='error')
return redirect(url('repos'))
@HasPermissionAllDecorator('hg.admin')
def show(self, repo_name, format='html'):
"""GET /repos/repo_name: Show a specific item"""
@ -384,105 +339,6 @@ class ReposController(BaseRepoController):
h.flash(msg, category='error')
return redirect(url('edit_repo_fields', repo_name=repo_name))
@HasRepoPermissionAllDecorator('repository.admin')
def edit_advanced(self, repo_name):
"""GET /repo_name/settings: Form to edit an existing item"""
c.repo_info = self._load_repo(repo_name)
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()
c.active = 'advanced'
c.has_origin_repo_read_perm = False
if c.repo_info.fork:
c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
'repository.write', 'repository.read', 'repository.admin')(
c.repo_info.fork.repo_name, 'repo set as fork page')
if request.POST:
return redirect(url('repo_edit_advanced'))
return render('admin/repos/repo_edit.mako')
@HasRepoPermissionAllDecorator('repository.admin')
@auth.CSRFRequired()
def edit_advanced_journal(self, repo_name):
"""
Set's this repository to be visible in public journal,
in other words assing default user to follow this repo
:param repo_name:
"""
try:
repo_id = Repository.get_by_repo_name(repo_name).repo_id
user_id = User.get_default_user().user_id
self.scm_model.toggle_following_repo(repo_id, user_id)
h.flash(_('Updated repository visibility in public journal'),
category='success')
Session().commit()
except Exception:
h.flash(_('An error occurred during setting this'
' repository in public journal'),
category='error')
return redirect(url('edit_repo_advanced', repo_name=repo_name))
@HasRepoPermissionAllDecorator('repository.admin')
@auth.CSRFRequired()
def edit_advanced_fork(self, repo_name):
"""
Mark given repository as a fork of another
:param repo_name:
"""
new_fork_id = request.POST.get('id_fork_of')
try:
if new_fork_id and not new_fork_id.isdigit():
log.error('Given fork id %s is not an INT', new_fork_id)
fork_id = safe_int(new_fork_id)
repo = ScmModel().mark_as_fork(repo_name, fork_id,
c.rhodecode_user.username)
fork = repo.fork.repo_name if repo.fork else _('Nothing')
Session().commit()
h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
category='success')
except RepositoryError as e:
log.exception("Repository Error occurred")
h.flash(str(e), category='error')
except Exception as e:
log.exception("Exception while editing fork")
h.flash(_('An error occurred during this operation'),
category='error')
return redirect(url('edit_repo_advanced', repo_name=repo_name))
@HasRepoPermissionAllDecorator('repository.admin')
@auth.CSRFRequired()
def edit_advanced_locking(self, repo_name):
"""
Unlock repository when it is locked !
:param repo_name:
"""
try:
repo = Repository.get_by_repo_name(repo_name)
if request.POST.get('set_lock'):
Repository.lock(repo, c.rhodecode_user.user_id,
lock_reason=Repository.LOCK_WEB)
h.flash(_('Locked repository'), category='success')
elif request.POST.get('set_unlock'):
Repository.unlock(repo)
h.flash(_('Unlocked repository'), category='success')
except Exception as e:
log.exception("Exception during unlocking")
h.flash(_('An error occurred during unlocking'),
category='error')
return redirect(url('edit_repo_advanced', repo_name=repo_name))
@HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
@auth.CSRFRequired()
def toggle_locking(self, repo_name):

View file

@ -36,9 +36,10 @@ ACTIONS = {
'user.push': {},
'user.pull': {},
'repo.add': {},
'repo.create': {},
'repo.edit': {},
'repo.edit.permissions': {},
'repo.delete': {},
'repo.commit.strip': {},
'repo.archive.download': {},
}
@ -101,7 +102,7 @@ def store(
audit_logger.store(
action='repo.edit', user=self._rhodecode_user)
audit_logger.store(
action='repo.delete',
action='repo.delete', action_data={'repo_data': repo_data},
user=audit_logger.UserWrap(username='itried-login', ip_addr='8.8.8.8'))
# repo action

View file

@ -96,10 +96,16 @@ function registerRCRoutes() {
pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
pyroutes.register('repo_list_data', '/_repos', []);
pyroutes.register('goto_switcher_data', '/_goto_data', []);
pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
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('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);

View file

@ -45,7 +45,7 @@
<a href="${h.route_path('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a>
</li>
<li class="${'active' if c.active=='advanced' else ''}">
<a href="${h.url('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a>
<a href="${h.route_path('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a>
</li>
<li class="${'active' if c.active=='vcs' else ''}">
<a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">${_('VCS')}</a>

View file

@ -10,8 +10,8 @@
%>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">${_('Repository: %s') % c.repo_info.repo_name}</h3>
<div class="panel-heading" id="advanced-info" >
<h3 class="panel-title">${_('Repository: %s') % c.repo_info.repo_name} <a class="permalink" href="#advanced-info"> ¶</a></h3>
</div>
<div class="panel-body">
${base.dt_info_panel(elems)}
@ -20,11 +20,11 @@
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">${_('Fork Reference')}</h3>
<div class="panel-heading" id="advanced-fork">
<h3 class="panel-title">${_('Fork Reference')} <a class="permalink" href="#advanced-fork"> ¶</a></h3>
</div>
<div class="panel-body">
${h.secure_form(url('edit_repo_advanced_fork', repo_name=c.repo_info.repo_name), method='put')}
${h.secure_form(h.route_path('edit_repo_advanced_fork', repo_name=c.repo_info.repo_name), method='POST')}
% if c.repo_info.fork:
<div class="panel-body-title-text">${h.literal(_('This repository is a fork of %(repo_link)s') % {'repo_link': h.link_to_if(c.has_origin_repo_read_perm,c.repo_info.fork.repo_name, h.url('summary_home', repo_name=c.repo_info.fork.repo_name))})}
@ -44,15 +44,14 @@
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">${_('Public Journal Visibility')}</h3>
<div class="panel-heading" id="advanced-journal">
<h3 class="panel-title">${_('Public Journal Visibility')} <a class="permalink" href="#advanced-journal"> ¶</a></h3>
</div>
<div class="panel-body">
${h.secure_form(url('edit_repo_advanced_journal', repo_name=c.repo_info.repo_name), method='put')}
${h.secure_form(h.route_path('edit_repo_advanced_journal', repo_name=c.repo_info.repo_name), method='POST')}
<div class="field">
%if c.in_public_journal:
<button class="btn btn-small" type="submit">
<i class="icon-minus"></i>
${_('Remove from Public Journal')}
</button>
%else:
@ -70,11 +69,11 @@
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">${_('Locking state')}</h3>
<div class="panel-heading" id="advanced-locking">
<h3 class="panel-title">${_('Locking state')} <a class="permalink" href="#advanced-locking"> ¶</a></h3>
</div>
<div class="panel-body">
${h.secure_form(url('edit_repo_advanced_locking', repo_name=c.repo_info.repo_name), method='put')}
${h.secure_form(h.route_path('edit_repo_advanced_locking', repo_name=c.repo_info.repo_name), method='POST')}
%if c.repo_info.locked[0]:
<div class="panel-body-title-text">${'Locked by %s on %s. Lock reason: %s' % (h.person_by_id(c.repo_info.locked[0]),
@ -110,15 +109,15 @@
</div>
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">${_('Delete repository')}</h3>
<div class="panel-heading" id="advanced-delete">
<h3 class="panel-title">${_('Delete repository')} <a class="permalink" href="#advanced-delete"> ¶</a></h3>
</div>
<div class="panel-body">
${h.secure_form(url('repo', repo_name=c.repo_name),method='delete')}
${h.secure_form(h.route_path('edit_repo_advanced_delete', repo_name=c.repo_name), method='POST')}
<table class="display">
<tr>
<td>
${ungettext('This repository has %s fork.', 'This repository has %s forks.', c.repo_info. forks.count()) % c.repo_info.forks.count()}
${_ungettext('This repository has %s fork.', 'This repository has %s forks.', c.repo_info.forks.count()) % c.repo_info.forks.count()}
</td>
<td>
%if c.repo_info.forks.count():
@ -143,7 +142,7 @@
</div>
<div class="field">
<span class="help-block">
${_('This repository will be renamed in a special way in order to make it inaccessible to RhodeCode Enterprise and its VCS systems. If you need to fully delete it from the file system, please do it manually, or with rhodecode-cleanup-repos command.')}
${_('This repository will be renamed in a special way in order to make it inaccessible to RhodeCode Enterprise and its VCS systems. If you need to fully delete it from the file system, please do it manually, or with rhodecode-cleanup-repos command available in rhodecode-tools.')}
</span>
</div>

View file

@ -119,7 +119,7 @@
<i class="icon-pencil"></i>Edit</a>
</div>
<div class="grid_delete">
${h.secure_form(h.url('repo', repo_name=repo_name),method='delete')}
${h.secure_form(h.route_path('edit_repo_advanced_delete', repo_name=repo_name), method='POST')}
${h.submit('remove_%s' % repo_name,_('Delete'),class_="btn btn-link btn-danger",
onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
${h.end_form()}

View file

@ -382,21 +382,6 @@ class TestAdminRepos(object):
csrf_token=csrf_token))
response.mustcontain('Repository name cannot end with .git')
@pytest.mark.parametrize("suffix", [u'', u'ąęł'], ids=['', 'non-ascii'])
def test_delete(self, autologin_user, backend, suffix, csrf_token):
repo = backend.create_repo(name_suffix=suffix)
repo_name = repo.repo_name
response = self.app.post(url('repo', repo_name=repo_name),
params={'_method': 'delete',
'csrf_token': csrf_token})
assert_session_flash(response, 'Deleted repository %s' % (repo_name))
response.follow()
# check if repo was deleted from db
assert RepoModel().get_by_repo_name(repo_name) is None
assert not repo_on_filesystem(repo_name)
def test_show(self, autologin_user, backend):
self.app.get(url('repo', repo_name=backend.repo_name))
@ -414,82 +399,6 @@ class TestAdminRepos(object):
assert permissions[0].permission.permission_name == 'repository.none'
assert permissions[0].repository.private is True
def test_set_repo_fork_has_no_self_id(self, autologin_user, backend):
repo = backend.repo
response = self.app.get(
url('edit_repo_advanced', repo_name=backend.repo_name))
opt = """<option value="%s">vcs_test_git</option>""" % repo.repo_id
response.mustcontain(no=[opt])
def test_set_fork_of_target_repo(
self, autologin_user, backend, csrf_token):
target_repo = 'target_%s' % backend.alias
fixture.create_repo(target_repo, repo_type=backend.alias)
repo2 = Repository.get_by_repo_name(target_repo)
response = self.app.post(
url('edit_repo_advanced_fork', repo_name=backend.repo_name),
params={'id_fork_of': repo2.repo_id, '_method': 'put',
'csrf_token': csrf_token})
repo = Repository.get_by_repo_name(backend.repo_name)
repo2 = Repository.get_by_repo_name(target_repo)
assert_session_flash(
response,
'Marked repo %s as fork of %s' % (repo.repo_name, repo2.repo_name))
assert repo.fork == repo2
response = response.follow()
# check if given repo is selected
opt = 'This repository is a fork of <a href="%s">%s</a>' % (
url('summary_home', repo_name=repo2.repo_name), repo2.repo_name)
response.mustcontain(opt)
fixture.destroy_repo(target_repo, forks='detach')
@pytest.mark.backends("hg", "git")
def test_set_fork_of_other_type_repo(self, autologin_user, backend,
csrf_token):
TARGET_REPO_MAP = {
'git': {
'type': 'hg',
'repo_name': HG_REPO},
'hg': {
'type': 'git',
'repo_name': GIT_REPO},
}
target_repo = TARGET_REPO_MAP[backend.alias]
repo2 = Repository.get_by_repo_name(target_repo['repo_name'])
response = self.app.post(
url('edit_repo_advanced_fork', repo_name=backend.repo_name),
params={'id_fork_of': repo2.repo_id, '_method': 'put',
'csrf_token': csrf_token})
assert_session_flash(
response,
'Cannot set repository as fork of repository with other type')
def test_set_fork_of_none(self, autologin_user, backend, csrf_token):
# mark it as None
response = self.app.post(
url('edit_repo_advanced_fork', repo_name=backend.repo_name),
params={'id_fork_of': None, '_method': 'put',
'csrf_token': csrf_token})
assert_session_flash(
response,
'Marked repo %s as fork of %s'
% (backend.repo_name, "Nothing"))
assert backend.repo.fork is None
def test_set_fork_of_same_repo(self, autologin_user, backend, csrf_token):
repo = Repository.get_by_repo_name(backend.repo_name)
response = self.app.post(
url('edit_repo_advanced_fork', repo_name=backend.repo_name),
params={'id_fork_of': repo.repo_id, '_method': 'put',
'csrf_token': csrf_token})
assert_session_flash(
response, 'An error occurred during this operation')
def test_create_on_top_level_without_permissions(self, backend):
session = login_user_session(
self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)

View file

@ -106,9 +106,7 @@ class _BaseTest(TestController):
)
# remove this fork
response = self.app.post(
url('repo', repo_name=fork_name),
params={'_method': 'delete', 'csrf_token': self.csrf_token})
fixture.destroy_repo(fork_name)
def test_fork_create_into_group(self):
self.log_user()