repo-summary: re-implemented summary view as pyramid.

- changed exception handler, to now work in pure pyramid mode
- changed missing requirements logic on repo based views that require vcs-connection
This commit is contained in:
Marcin Kuzminski 2017-06-07 13:23:21 +02:00
parent 3d2de9920e
commit 53b4ac98f8
51 changed files with 415 additions and 410 deletions

View file

@ -105,9 +105,14 @@ class BaseAppView(object):
raise HTTPFound(
self.request.route_path('my_account_password'))
def _get_local_tmpl_context(self):
def _get_local_tmpl_context(self, include_app_defaults=False):
c = TemplateArgs()
c.auth_user = self.request.user
if include_app_defaults:
# NOTE(marcink): after full pyramid migration include_app_defaults
# should be turned on by default
from rhodecode.lib.base import attach_context_attributes
attach_context_attributes(c, self.request, self.request.user.user_id)
return c
def _register_global_c(self, tmpl_args):
@ -154,8 +159,10 @@ class RepoAppView(BaseAppView):
'Requirements are missing for repository %s: %s',
self.db_repo_name, error.message)
def _get_local_tmpl_context(self):
c = super(RepoAppView, self)._get_local_tmpl_context()
def _get_local_tmpl_context(self, include_app_defaults=False):
c = super(RepoAppView, self)._get_local_tmpl_context(
include_app_defaults=include_app_defaults)
# register common vars for this type of view
c.rhodecode_db_repo = self.db_repo
c.repo_name = self.db_repo_name
@ -309,7 +316,7 @@ class RepoTypeRoutePredicate(object):
# _('Action not supported for %s.' % rhodecode_repo.alias)),
# category='warning')
# return redirect(
# url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
# route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
return False

View file

@ -123,7 +123,7 @@ class HomeView(BaseAppView):
'text': obj['name'],
'type': 'repo',
'obj': obj['dbrepo'],
'url': h.url('summary_home', repo_name=obj['name'])
'url': h.route_path('repo_summary', repo_name=obj['name'])
}
for obj in repo_iter]

View file

@ -17,18 +17,33 @@
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
from rhodecode.apps._base import add_route_with_slash
def includeme(config):
# Summary
config.add_route(
name='repo_summary',
pattern='/{repo_name:.*?[^/]}', repo_route=True)
# NOTE(marcink): one additional route is defined in very bottom, catch
# all pattern
config.add_route(
name='repo_summary_explicit',
pattern='/{repo_name:.*?[^/]}/summary', repo_route=True)
config.add_route(
name='repo_summary_commits',
pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
# refs data
config.add_route(
name='repo_refs_data',
pattern='/{repo_name:.*?[^/]}/refs-data', repo_route=True)
config.add_route(
name='repo_refs_changelog_data',
pattern='/{repo_name:.*?[^/]}/refs-data-changelog', repo_route=True)
config.add_route(
name='repo_stats',
pattern='/{repo_name:.*?[^/]}/repo_stats/{commit_id}', repo_route=True)
# Tags
config.add_route(
@ -40,7 +55,6 @@ def includeme(config):
name='branches_home',
pattern='/{repo_name:.*?[^/]}/branches', repo_route=True)
# Bookmarks
config.add_route(
name='bookmarks_home',
pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True)
@ -125,9 +139,10 @@ def includeme(config):
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)
add_route_with_slash(
config,
name='repo_summary',
pattern='/{repo_name:.*?[^/]}', repo_route=True)
# Scan module for configuration decorators.
config.scan()

View file

@ -23,16 +23,16 @@ import re
import mock
import pytest
from rhodecode.controllers import summary
from rhodecode.apps.repository.views.repo_summary import RepoSummaryView
from rhodecode.lib import helpers as h
from rhodecode.lib.compat import OrderedDict
from rhodecode.lib.utils2 import AttributeDict
from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
from rhodecode.model.db import Repository
from rhodecode.model.meta import Session
from rhodecode.model.repo import RepoModel
from rhodecode.model.scm import ScmModel
from rhodecode.tests import (
TestController, url, HG_REPO, assert_session_flash)
from rhodecode.tests import assert_session_flash
from rhodecode.tests.fixture import Fixture
from rhodecode.tests.utils import AssertResponse, repo_on_filesystem
@ -40,14 +40,31 @@ from rhodecode.tests.utils import AssertResponse, repo_on_filesystem
fixture = Fixture()
class TestSummaryController(TestController):
def test_index(self, backend, http_host_only_stub):
self.log_user()
def route_path(name, params=None, **kwargs):
import urllib
base_url = {
'repo_summary': '/{repo_name}',
'repo_stats': '/{repo_name}/repo_stats/{commit_id}',
'repo_refs_data': '/{repo_name}/refs-data',
'repo_refs_changelog_data': '/{repo_name}/refs-data-changelog'
}[name].format(**kwargs)
if params:
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
return base_url
@pytest.mark.usefixtures('app')
class TestSummaryView(object):
def test_index(self, autologin_user, backend, http_host_only_stub):
repo_id = backend.repo.repo_id
repo_name = backend.repo_name
with mock.patch('rhodecode.lib.helpers.is_svn_without_proxy',
return_value=False):
response = self.app.get(url('summary_home', repo_name=repo_name))
response = self.app.get(
route_path('repo_summary', repo_name=repo_name))
# repo type
response.mustcontain(
@ -66,11 +83,11 @@ class TestSummaryController(TestController):
'id="clone_url_id" readonly="readonly"'
' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
def test_index_svn_without_proxy(self, backend_svn, http_host_only_stub):
self.log_user()
def test_index_svn_without_proxy(
self, autologin_user, backend_svn, http_host_only_stub):
repo_id = backend_svn.repo.repo_id
repo_name = backend_svn.repo_name
response = self.app.get(url('summary_home', repo_name=repo_name))
response = self.app.get(route_path('repo_summary', repo_name=repo_name))
# clone url...
response.mustcontain(
'id="clone_url" disabled'
@ -79,14 +96,15 @@ class TestSummaryController(TestController):
'id="clone_url_id" disabled'
' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
def test_index_with_trailing_slash(self, autologin_user, backend,
http_host_only_stub):
def test_index_with_trailing_slash(
self, autologin_user, backend, http_host_only_stub):
repo_id = backend.repo.repo_id
repo_name = backend.repo_name
with mock.patch('rhodecode.lib.helpers.is_svn_without_proxy',
return_value=False):
response = self.app.get(
url('summary_home', repo_name=repo_name) + '/',
route_path('repo_summary', repo_name=repo_name) + '/',
status=200)
# clone url...
@ -97,11 +115,10 @@ class TestSummaryController(TestController):
'id="clone_url_id" readonly="readonly"'
' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
def test_index_by_id(self, backend):
self.log_user()
def test_index_by_id(self, autologin_user, backend):
repo_id = backend.repo.repo_id
response = self.app.get(url(
'summary_home', repo_name='_%s' % (repo_id,)))
response = self.app.get(
route_path('repo_summary', repo_name='_%s' % (repo_id,)))
# repo type
response.mustcontain(
@ -112,10 +129,9 @@ class TestSummaryController(TestController):
"""<i class="icon-unlock-alt">"""
)
def test_index_by_repo_having_id_path_in_name_hg(self):
self.log_user()
def test_index_by_repo_having_id_path_in_name_hg(self, autologin_user):
fixture.create_repo(name='repo_1')
response = self.app.get(url('summary_home', repo_name='repo_1'))
response = self.app.get(route_path('repo_summary', repo_name='repo_1'))
try:
response.mustcontain("repo_1")
@ -123,11 +139,11 @@ class TestSummaryController(TestController):
RepoModel().delete(Repository.get_by_repo_name('repo_1'))
Session().commit()
def test_index_with_anonymous_access_disabled(self):
with fixture.anon_access(False):
response = self.app.get(url('summary_home', repo_name=HG_REPO),
status=302)
assert 'login' in response.location
def test_index_with_anonymous_access_disabled(
self, backend, disable_anonymous_user):
response = self.app.get(
route_path('repo_summary', repo_name=backend.repo_name), status=302)
assert 'login' in response.location
def _enable_stats(self, repo):
r = Repository.get_by_repo_name(repo)
@ -174,17 +190,15 @@ class TestSummaryController(TestController):
},
}
def test_repo_stats(self, backend, xhr_header):
self.log_user()
def test_repo_stats(self, autologin_user, backend, xhr_header):
response = self.app.get(
url('repo_stats',
repo_name=backend.repo_name, commit_id='tip'),
route_path(
'repo_stats', repo_name=backend.repo_name, commit_id='tip'),
extra_environ=xhr_header,
status=200)
assert re.match(r'6[\d\.]+ KiB', response.json['size'])
def test_repo_stats_code_stats_enabled(self, backend, xhr_header):
self.log_user()
def test_repo_stats_code_stats_enabled(self, autologin_user, backend, xhr_header):
repo_name = backend.repo_name
# codes stats
@ -192,8 +206,8 @@ class TestSummaryController(TestController):
ScmModel().mark_for_invalidation(repo_name)
response = self.app.get(
url('repo_stats',
repo_name=backend.repo_name, commit_id='tip'),
route_path(
'repo_stats', repo_name=backend.repo_name, commit_id='tip'),
extra_environ=xhr_header,
status=200)
@ -204,7 +218,7 @@ class TestSummaryController(TestController):
def test_repo_refs_data(self, backend):
response = self.app.get(
url('repo_refs_data', repo_name=backend.repo_name),
route_path('repo_refs_data', repo_name=backend.repo_name),
status=200)
# Ensure that there is the correct amount of items in the result
@ -221,72 +235,68 @@ class TestSummaryController(TestController):
Repository, 'scm_instance', side_effect=RepositoryRequirementError)
with scm_patcher:
response = self.app.get(url('summary_home', repo_name=repo_name))
response = self.app.get(route_path('repo_summary', repo_name=repo_name))
assert_response = AssertResponse(response)
assert_response.element_contains(
'.main .alert-warning strong', 'Missing requirements')
assert_response.element_contains(
'.main .alert-warning',
'These commits cannot be displayed, because this repository'
' uses the Mercurial largefiles extension, which was not enabled.')
'Commits cannot be displayed, because this repository '
'uses one or more extensions, which was not enabled.')
def test_missing_requirements_page_does_not_contains_switch_to(
self, backend):
self.log_user()
self, autologin_user, backend):
repo_name = backend.repo_name
scm_patcher = mock.patch.object(
Repository, 'scm_instance', side_effect=RepositoryRequirementError)
with scm_patcher:
response = self.app.get(url('summary_home', repo_name=repo_name))
response = self.app.get(route_path('repo_summary', repo_name=repo_name))
response.mustcontain(no='Switch To')
@pytest.mark.usefixtures('pylonsapp')
class TestSwitcherReferenceData:
@pytest.mark.usefixtures('app')
class TestRepoLocation(object):
def test_creates_reference_urls_based_on_name(self):
references = {
'name': 'commit_id',
}
controller = summary.SummaryController()
is_svn = False
result = controller._switcher_reference_data(
'repo_name', references, is_svn)
expected_url = h.url(
'files_home', repo_name='repo_name', revision='name',
at='name')
assert result[0]['files_url'] == expected_url
@pytest.mark.parametrize("suffix", [u'', u'ąęł'], ids=['', 'non-ascii'])
def test_manual_delete(self, autologin_user, backend, suffix, csrf_token):
repo = backend.create_repo(name_suffix=suffix)
repo_name = repo.repo_name
def test_urls_contain_commit_id_if_slash_in_name(self):
references = {
'name/with/slash': 'commit_id',
}
controller = summary.SummaryController()
is_svn = False
result = controller._switcher_reference_data(
'repo_name', references, is_svn)
expected_url = h.url(
'files_home', repo_name='repo_name', revision='commit_id',
at='name/with/slash')
assert result[0]['files_url'] == expected_url
# delete from file system
RepoModel()._delete_filesystem_repo(repo)
def test_adds_reference_to_path_for_svn(self):
references = {
'name/with/slash': 'commit_id',
}
controller = summary.SummaryController()
is_svn = True
result = controller._switcher_reference_data(
'repo_name', references, is_svn)
expected_url = h.url(
'files_home', repo_name='repo_name', f_path='name/with/slash',
revision='commit_id', at='name/with/slash')
assert result[0]['files_url'] == expected_url
# test if the repo is still in the database
new_repo = RepoModel().get_by_repo_name(repo_name)
assert new_repo.repo_name == repo_name
# check if repo is not in the filesystem
assert not repo_on_filesystem(repo_name)
self.assert_repo_not_found_redirect(repo_name)
def assert_repo_not_found_redirect(self, repo_name):
# run the check page that triggers the other flash message
response = self.app.get(h.url('repo_check_home', repo_name=repo_name))
assert_session_flash(
response, 'The repository at %s cannot be located.' % repo_name)
@pytest.mark.usefixtures('pylonsapp')
class TestCreateReferenceData:
@pytest.fixture()
def summary_view(context_stub, request_stub, user_util):
"""
Bootstrap view to test the view functions
"""
request_stub.matched_route = AttributeDict(name='test_view')
request_stub.user = user_util.create_user().AuthUser
request_stub.db_repo = user_util.create_repo()
view = RepoSummaryView(context=context_stub, request=request_stub)
return view
@pytest.mark.usefixtures('app')
class TestCreateReferenceData(object):
@pytest.fixture
def example_refs(self):
@ -297,14 +307,13 @@ class TestCreateReferenceData:
]
return example_refs
def test_generates_refs_based_on_commit_ids(self, example_refs):
def test_generates_refs_based_on_commit_ids(self, example_refs, summary_view):
repo = mock.Mock()
repo.name = 'test-repo'
repo.alias = 'git'
full_repo_name = 'pytest-repo-group/' + repo.name
controller = summary.SummaryController()
result = controller._create_reference_data(
result = summary_view._create_reference_data(
repo, full_repo_name, example_refs)
expected_files_url = '/{}/files/'.format(full_repo_name)
@ -333,13 +342,13 @@ class TestCreateReferenceData:
}]
assert result == expected_result
def test_generates_refs_with_path_for_svn(self, example_refs):
def test_generates_refs_with_path_for_svn(self, example_refs, summary_view):
repo = mock.Mock()
repo.name = 'test-repo'
repo.alias = 'svn'
full_repo_name = 'pytest-repo-group/' + repo.name
controller = summary.SummaryController()
result = controller._create_reference_data(
result = summary_view._create_reference_data(
repo, full_repo_name, example_refs)
expected_files_url = '/{}/files/'.format(full_repo_name)
@ -373,35 +382,9 @@ class TestCreateReferenceData:
assert result == expected_result
@pytest.mark.usefixtures("app")
class TestRepoLocation:
@pytest.mark.parametrize("suffix", [u'', u'ąęł'], ids=['', 'non-ascii'])
def test_manual_delete(self, autologin_user, backend, suffix, csrf_token):
repo = backend.create_repo(name_suffix=suffix)
repo_name = repo.repo_name
# delete from file system
RepoModel()._delete_filesystem_repo(repo)
# test if the repo is still in the database
new_repo = RepoModel().get_by_repo_name(repo_name)
assert new_repo.repo_name == repo_name
# check if repo is not in the filesystem
assert not repo_on_filesystem(repo_name)
self.assert_repo_not_found_redirect(repo_name)
def assert_repo_not_found_redirect(self, repo_name):
# run the check page that triggers the other flash message
response = self.app.get(url('repo_check_home', repo_name=repo_name))
assert_session_flash(
response, 'The repository at %s cannot be located.' % repo_name)
class TestCreateFilesUrl(object):
def test_creates_non_svn_url(self):
controller = summary.SummaryController()
def test_creates_non_svn_url(self, summary_view):
repo = mock.Mock()
repo.name = 'abcde'
full_repo_name = 'test-repo-group/' + repo.name
@ -409,16 +392,15 @@ class TestCreateFilesUrl(object):
raw_id = 'deadbeef0123456789'
is_svn = False
with mock.patch.object(summary.h, 'url') as url_mock:
result = controller._create_files_url(
with mock.patch('rhodecode.lib.helpers.url') as url_mock:
result = summary_view._create_files_url(
repo, full_repo_name, ref_name, raw_id, is_svn)
url_mock.assert_called_once_with(
'files_home', repo_name=full_repo_name, f_path='',
revision=ref_name, at=ref_name)
assert result == url_mock.return_value
def test_creates_svn_url(self):
controller = summary.SummaryController()
def test_creates_svn_url(self, summary_view):
repo = mock.Mock()
repo.name = 'abcde'
full_repo_name = 'test-repo-group/' + repo.name
@ -426,16 +408,15 @@ class TestCreateFilesUrl(object):
raw_id = 'deadbeef0123456789'
is_svn = True
with mock.patch.object(summary.h, 'url') as url_mock:
result = controller._create_files_url(
with mock.patch('rhodecode.lib.helpers.url') as url_mock:
result = summary_view._create_files_url(
repo, full_repo_name, ref_name, raw_id, is_svn)
url_mock.assert_called_once_with(
'files_home', repo_name=full_repo_name, f_path=ref_name,
revision=raw_id, at=ref_name)
assert result == url_mock.return_value
def test_name_has_slashes(self):
controller = summary.SummaryController()
def test_name_has_slashes(self, summary_view):
repo = mock.Mock()
repo.name = 'abcde'
full_repo_name = 'test-repo-group/' + repo.name
@ -443,8 +424,8 @@ class TestCreateFilesUrl(object):
raw_id = 'deadbeef0123456789'
is_svn = False
with mock.patch.object(summary.h, 'url') as url_mock:
result = controller._create_files_url(
with mock.patch('rhodecode.lib.helpers.url') as url_mock:
result = summary_view._create_files_url(
repo, full_repo_name, ref_name, raw_id, is_svn)
url_mock.assert_called_once_with(
'files_home', repo_name=full_repo_name, f_path='', revision=raw_id,
@ -463,42 +444,39 @@ class TestReferenceItems(object):
def _format_function(name, id_):
return 'format_function_{}_{}'.format(name, id_)
def test_creates_required_amount_of_items(self):
def test_creates_required_amount_of_items(self, summary_view):
amount = 100
refs = {
'ref{}'.format(i): '{0:040d}'.format(i)
for i in range(amount)
}
controller = summary.SummaryController()
url_patcher = mock.patch.object(
controller, '_create_files_url')
svn_patcher = mock.patch.object(
summary.h, 'is_svn', return_value=False)
url_patcher = mock.patch.object(summary_view, '_create_files_url')
svn_patcher = mock.patch('rhodecode.lib.helpers.is_svn',
return_value=False)
with url_patcher as url_mock, svn_patcher:
result = controller._create_reference_items(
result = summary_view._create_reference_items(
self.repo, self.repo_full_name, refs, self.ref_type,
self._format_function)
assert len(result) == amount
assert url_mock.call_count == amount
def test_single_item_details(self):
def test_single_item_details(self, summary_view):
ref_name = 'ref1'
ref_id = 'deadbeef'
refs = {
ref_name: ref_id
}
controller = summary.SummaryController()
svn_patcher = mock.patch('rhodecode.lib.helpers.is_svn',
return_value=False)
url_patcher = mock.patch.object(
controller, '_create_files_url', return_value=self.fake_url)
svn_patcher = mock.patch.object(
summary.h, 'is_svn', return_value=False)
summary_view, '_create_files_url', return_value=self.fake_url)
with url_patcher as url_mock, svn_patcher:
result = controller._create_reference_items(
result = summary_view._create_reference_items(
self.repo, self.repo_full_name, refs, self.ref_type,
self._format_function)

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2010-2017 RhodeCode GmbH
# 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
@ -18,46 +18,51 @@
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
"""
Summary controller for RhodeCode Enterprise
"""
import logging
from string import lower
import string
from pyramid.view import view_config
from pylons import tmpl_context as c, request
from pylons.i18n.translation import _
from beaker.cache import cache_region
from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
from rhodecode.controllers import utils
from rhodecode.controllers.changelog import _load_changelog_summary
from rhodecode.apps._base import RepoAppView
from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
from rhodecode.lib import caches, helpers as h
from rhodecode.lib.utils import jsonify
from rhodecode.lib.utils2 import safe_str
from rhodecode.lib.auth import (
LoginRequired, HasRepoPermissionAnyDecorator, XHRRequired)
from rhodecode.lib.base import BaseRepoController, render
from rhodecode.lib.helpers import RepoPage
from rhodecode.lib.utils2 import safe_str, safe_int
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
from rhodecode.lib.ext_json import json
from rhodecode.lib.vcs.backends.base import EmptyCommit
from rhodecode.lib.vcs.exceptions import CommitError, EmptyRepositoryError
from rhodecode.model.db import Statistics, CacheKey, User
from rhodecode.model.meta import Session
from rhodecode.model.repo import ReadmeFinder
from rhodecode.model.scm import ScmModel
log = logging.getLogger(__name__)
class SummaryController(BaseRepoController):
class RepoSummaryView(RepoAppView):
def __before__(self):
super(SummaryController, self).__before__()
def load_default_context(self):
c = self._get_local_tmpl_context(include_app_defaults=True)
def __get_readme_data(self, db_repo):
# TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
c.repo_info = self.db_repo
c.rhodecode_repo = None
if not c.repository_requirements_missing:
c.rhodecode_repo = self.rhodecode_vcs_repo
self._register_global_c(c)
return c
def _get_readme_data(self, db_repo, default_renderer):
repo_name = db_repo.repo_name
log.debug('Looking for README file')
default_renderer = c.visual.default_renderer
@cache_region('long_term')
def _generate_readme(cache_key):
@ -113,16 +118,58 @@ class SummaryController(BaseRepoController):
log.exception(
"Exception while trying to render the README")
def _load_commits_context(self, c):
p = safe_int(self.request.GET.get('page'), 1)
size = safe_int(self.request.GET.get('size'), 10)
def url_generator(**kw):
query_params = {
'size': size
}
query_params.update(kw)
return h.route_path(
'repo_summary_commits',
repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
pre_load = ['author', 'branch', 'date', 'message']
try:
collection = self.rhodecode_vcs_repo.get_commits(pre_load=pre_load)
except EmptyRepositoryError:
collection = self.rhodecode_vcs_repo
c.repo_commits = RepoPage(
collection, page=p, items_per_page=size, url=url_generator)
page_ids = [x.raw_id for x in c.repo_commits]
c.comments = self.db_repo.get_comments(page_ids)
c.statuses = self.db_repo.statuses(page_ids)
@LoginRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
def index(self, repo_name):
@view_config(
route_name='repo_summary_commits', request_method='GET',
renderer='rhodecode:templates/summary/summary_commits.mako')
def summary_commits(self):
c = self.load_default_context()
self._load_commits_context(c)
return self._get_template_context(c)
@LoginRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@view_config(
route_name='repo_summary', request_method='GET',
renderer='rhodecode:templates/summary/summary.mako')
@view_config(
route_name='repo_summary_slash', request_method='GET',
renderer='rhodecode:templates/summary/summary.mako')
def summary(self):
c = self.load_default_context()
# Prepare the clone URL
username = ''
if c.rhodecode_user.username != User.DEFAULT_USER:
username = safe_str(c.rhodecode_user.username)
if self._rhodecode_user.username != User.DEFAULT_USER:
username = safe_str(self._rhodecode_user.username)
_def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
if '{repo}' in _def_clone_uri:
@ -132,23 +179,23 @@ class SummaryController(BaseRepoController):
_def_clone_uri_by_id = _def_clone_uri.replace(
'_{repoid}', '{repo}')
c.clone_repo_url = c.rhodecode_db_repo.clone_url(
c.clone_repo_url = self.db_repo.clone_url(
user=username, uri_tmpl=_def_clone_uri)
c.clone_repo_url_id = c.rhodecode_db_repo.clone_url(
c.clone_repo_url_id = self.db_repo.clone_url(
user=username, uri_tmpl=_def_clone_uri_by_id)
# If enabled, get statistics data
c.show_stats = bool(c.rhodecode_db_repo.enable_statistics)
c.show_stats = bool(self.db_repo.enable_statistics)
stats = self.sa.query(Statistics)\
.filter(Statistics.repository == c.rhodecode_db_repo)\
stats = Session().query(Statistics) \
.filter(Statistics.repository == self.db_repo) \
.scalar()
c.stats_percentage = 0
if stats and stats.languages:
c.no_data = False is c.rhodecode_db_repo.enable_statistics
c.no_data = False is self.db_repo.enable_statistics
lang_stats_d = json.loads(stats.languages)
# Sort first by decreasing count and second by the file extension,
@ -164,51 +211,59 @@ class SummaryController(BaseRepoController):
c.no_data = True
c.trending_languages = json.dumps({})
c.enable_downloads = c.rhodecode_db_repo.enable_downloads
c.repository_followers = self.scm_model.get_followers(
c.rhodecode_db_repo)
c.repository_forks = self.scm_model.get_forks(c.rhodecode_db_repo)
c.repository_is_user_following = self.scm_model.is_following_repo(
c.repo_name, c.rhodecode_user.user_id)
scm_model = ScmModel()
c.enable_downloads = self.db_repo.enable_downloads
c.repository_followers = scm_model.get_followers(self.db_repo)
c.repository_forks = scm_model.get_forks(self.db_repo)
c.repository_is_user_following = scm_model.is_following_repo(
self.db_repo_name, self._rhodecode_user.user_id)
# first interaction with the VCS instance after here...
if c.repository_requirements_missing:
return render('summary/missing_requirements.mako')
self.request.override_renderer = \
'rhodecode:templates/summary/missing_requirements.mako'
return self._get_template_context(c)
c.readme_data, c.readme_file = \
self.__get_readme_data(c.rhodecode_db_repo)
self._get_readme_data(self.db_repo, c.visual.default_renderer)
_load_changelog_summary()
# loads the summary commits template context
self._load_commits_context(c)
if request.is_xhr:
return render('changelog/changelog_summary_data.mako')
return self._get_template_context(c)
return render('summary/summary.mako')
def get_request_commit_id(self):
return self.request.matchdict['commit_id']
@LoginRequired()
@XHRRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@jsonify
def repo_stats(self, repo_name, commit_id):
@view_config(
route_name='repo_stats', request_method='GET',
renderer='json_ext')
def repo_stats(self):
commit_id = self.get_request_commit_id()
_namespace = caches.get_repo_namespace_key(
caches.SUMMARY_STATS, repo_name)
show_stats = bool(c.rhodecode_db_repo.enable_statistics)
cache_manager = caches.get_cache_manager('repo_cache_long', _namespace)
caches.SUMMARY_STATS, self.db_repo_name)
show_stats = bool(self.db_repo.enable_statistics)
cache_manager = caches.get_cache_manager(
'repo_cache_long', _namespace)
_cache_key = caches.compute_key_from_params(
repo_name, commit_id, show_stats)
self.db_repo_name, commit_id, show_stats)
def compute_stats():
code_stats = {}
size = 0
try:
scm_instance = c.rhodecode_db_repo.scm_instance()
scm_instance = self.db_repo.scm_instance()
commit = scm_instance.get_commit(commit_id)
for node in commit.get_filenodes_generator():
size += node.size
if not show_stats:
continue
ext = lower(node.extension)
ext = string.lower(node.extension)
ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
if ext_info:
if ext in code_stats:
@ -223,44 +278,41 @@ class SummaryController(BaseRepoController):
stats = cache_manager.get(_cache_key, createfunc=compute_stats)
return stats
def _switcher_reference_data(self, repo_name, references, is_svn):
"""Prepare reference data for given `references`"""
items = []
for name, commit_id in references.items():
use_commit_id = '/' in name or is_svn
items.append({
'name': name,
'commit_id': commit_id,
'files_url': h.url(
'files_home',
repo_name=repo_name,
f_path=name if is_svn else '',
revision=commit_id if use_commit_id else name,
at=name)
})
return items
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
'repository.admin')
@jsonify
def repo_refs_data(self, repo_name):
repo = c.rhodecode_repo
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@view_config(
route_name='repo_refs_data', request_method='GET',
renderer='json_ext')
def repo_refs_data(self):
_ = self.request.translate
self.load_default_context()
repo = self.rhodecode_vcs_repo
refs_to_create = [
(_("Branch"), repo.branches, 'branch'),
(_("Tag"), repo.tags, 'tag'),
(_("Bookmark"), repo.bookmarks, 'book'),
]
res = self._create_reference_data(repo, repo_name, refs_to_create)
res = self._create_reference_data(
repo, self.db_repo_name, refs_to_create)
data = {
'more': False,
'results': res
}
return data
@jsonify
def repo_refs_changelog_data(self, repo_name):
repo = c.rhodecode_repo
@LoginRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@view_config(
route_name='repo_refs_changelog_data', request_method='GET',
renderer='json_ext')
def repo_refs_changelog_data(self):
_ = self.request.translate
self.load_default_context()
repo = self.rhodecode_vcs_repo
refs_to_create = [
(_("Branches"), repo.branches, 'branch'),
@ -268,7 +320,8 @@ class SummaryController(BaseRepoController):
# TODO: enable when vcs can handle bookmarks filters
# (_("Bookmarks"), repo.bookmarks, "book"),
]
res = self._create_reference_data(repo, repo_name, refs_to_create)
res = self._create_reference_data(
repo, self.db_repo_name, refs_to_create)
data = {
'more': False,
'results': res
@ -284,7 +337,8 @@ class SummaryController(BaseRepoController):
result.append({
'text': title,
'children': self._create_reference_items(
repo, full_repo_name, refs, ref_type, format_ref_id),
repo, full_repo_name, refs, ref_type,
format_ref_id),
})
return result
@ -304,8 +358,7 @@ class SummaryController(BaseRepoController):
})
return result
def _create_files_url(self, repo, full_repo_name, ref_name, raw_id,
is_svn):
def _create_files_url(self, repo, full_repo_name, ref_name, raw_id, is_svn):
use_commit_id = '/' in ref_name or is_svn
return h.url(
'files_home',

View file

@ -39,11 +39,15 @@ from routes.middleware import RoutesMiddleware
import routes.util
import rhodecode
from rhodecode.model import meta
from rhodecode.config import patches
from rhodecode.config.routing import STATIC_FILE_PREFIX
from rhodecode.config.environment import (
load_environment, load_pyramid_environment)
from rhodecode.lib.vcs import VCSCommunicationError
from rhodecode.lib.exceptions import VCSServerUnavailable
from rhodecode.lib.middleware import csrf
from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
from rhodecode.lib.middleware.error_handling import (
@ -51,7 +55,7 @@ from rhodecode.lib.middleware.error_handling import (
from rhodecode.lib.middleware.https_fixup import HttpsFixup
from rhodecode.lib.middleware.vcs import VCSMiddleware
from rhodecode.lib.plugins.utils import register_rhodecode_plugin
from rhodecode.lib.utils2 import aslist as rhodecode_aslist
from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
from rhodecode.subscribers import (
scan_repositories_if_enabled, write_js_routes_if_enabled,
write_metadata_if_needed)
@ -221,7 +225,6 @@ def add_pylons_compat_data(registry, global_config, settings):
def error_handler(exception, request):
import rhodecode
from rhodecode.lib.utils2 import AttributeDict
from rhodecode.lib import helpers
rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
@ -230,6 +233,8 @@ def error_handler(exception, request):
# prefer original exception for the response since it may have headers set
if isinstance(exception, HTTPException):
base_response = exception
elif isinstance(exception, VCSCommunicationError):
base_response = VCSServerUnavailable()
def is_http_error(response):
# error which should have traceback
@ -257,6 +262,7 @@ def error_handler(exception, request):
if hasattr(base_response, 'causes'):
c.causes = base_response.causes
c.messages = helpers.flash.pop_messages()
response = render_to_response(
'/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
response=base_response)
@ -404,7 +410,6 @@ def wrap_app_in_wsgi_middlewares(pyramid_app, config):
pool = meta.Base.metadata.bind.engine.pool
log.debug('sa pool status: %s', pool.status())
return pyramid_app_with_cleanup

View file

@ -117,8 +117,9 @@ class JSRoutesMapper(Mapper):
def make_map(config):
"""Create, configure and return the routes Mapper"""
rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
always_scan=config['debug'])
rmap = JSRoutesMapper(
directory=config['pylons.paths']['controllers'],
always_scan=config['debug'])
rmap.minimization = False
rmap.explicit = False
@ -609,18 +610,6 @@ def make_map(config):
controller='admin/repos', action='repo_check',
requirements=URL_NAME_REQUIREMENTS)
rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
controller='summary', action='repo_stats',
conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
controller='summary', action='repo_refs_data',
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
controller='summary', action='repo_refs_changelog_data',
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
controller='changeset', revision='tip',
conditions={'function': check_repo},
@ -834,19 +823,10 @@ def make_map(config):
conditions={'function': check_repo, 'method': ['DELETE']},
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
rmap.connect('summary_home_explicit', '/{repo_name}/summary',
controller='summary', conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS)
rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
controller='changelog', conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS)
rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
controller='changelog', action='changelog_summary',
conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS)
rmap.connect('changelog_file_home',
'/{repo_name}/changelog/{revision}/{f_path}',
controller='changelog', f_path=None,
@ -999,19 +979,4 @@ def make_map(config):
conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS)
# catch all, at the end
_connect_with_slash(
rmap, 'summary_home', '/{repo_name}', jsroute=True,
controller='summary', action='index',
conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS)
return rmap
def _connect_with_slash(mapper, name, path, *args, **kwargs):
"""
Connect a route with an optional trailing slash in `path`.
"""
mapper.connect(name + '_slash', path + '/', *args, **kwargs)
mapper.connect(name, path, *args, **kwargs)

View file

@ -274,9 +274,9 @@ class ReposController(BaseRepoController):
h.flash(_('Created repository %s from %s')
% (repo.repo_name, clone_uri), category='success')
else:
repo_url = h.link_to(repo.repo_name,
h.url('summary_home',
repo_name=repo.repo_name))
repo_url = h.link_to(
repo.repo_name,
h.route_path('repo_summary',repo_name=repo.repo_name))
fork = repo.fork
if fork:
fork_name = fork.repo_name
@ -366,7 +366,7 @@ class ReposController(BaseRepoController):
log.exception("Exception during unlocking")
h.flash(_('An error occurred during unlocking'),
category='error')
return redirect(url('summary_home', repo_name=repo_name))
return redirect(h.route_path('repo_summary', repo_name=repo_name))
@HasRepoPermissionAllDecorator('repository.admin')
@auth.CSRFRequired()

View file

@ -46,27 +46,6 @@ log = logging.getLogger(__name__)
DEFAULT_CHANGELOG_SIZE = 20
def _load_changelog_summary():
p = safe_int(request.GET.get('page'), 1)
size = safe_int(request.GET.get('size'), 10)
def url_generator(**kw):
return url('summary_home',
repo_name=c.rhodecode_db_repo.repo_name, size=size, **kw)
pre_load = ['author', 'branch', 'date', 'message']
try:
collection = c.rhodecode_repo.get_commits(pre_load=pre_load)
except EmptyRepositoryError:
collection = c.rhodecode_repo
c.repo_commits = RepoPage(
collection, page=p, items_per_page=size, url=url_generator)
page_ids = [x.raw_id for x in c.repo_commits]
c.comments = c.rhodecode_db_repo.get_comments(page_ids)
c.statuses = c.rhodecode_db_repo.statuses(page_ids)
class ChangelogController(BaseRepoController):
def __before__(self):
@ -211,7 +190,7 @@ class ChangelogController(BaseRepoController):
except EmptyRepositoryError as e:
h.flash(safe_str(e), category='warning')
return redirect(url('summary_home', repo_name=repo_name))
return redirect(h.route_path('repo_summary', repo_name=repo_name))
except (RepositoryError, CommitDoesNotExistError, Exception) as e:
msg = safe_str(e)
log.exception(msg)
@ -279,12 +258,3 @@ class ChangelogController(BaseRepoController):
c.rhodecode_repo, c.pagination,
prev_data=prev_data, next_data=next_data)
return render('changelog/changelog_elements.mako')
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
'repository.admin')
def changelog_summary(self, repo_name):
if request.environ.get('HTTP_X_PJAX'):
_load_changelog_summary()
return render('changelog/changelog_summary_data.mako')
raise HTTPNotFound()

View file

@ -63,14 +63,14 @@ class CompareController(BaseRepoController):
return repo.scm_instance().EMPTY_COMMIT
h.flash(h.literal(_('There are no commits yet')),
category='warning')
redirect(url('summary_home', repo_name=repo.repo_name))
redirect(h.route_path('repo_summary', repo_name=repo.repo_name))
except RepositoryError as e:
msg = safe_str(e)
log.exception(msg)
h.flash(msg, category='warning')
if not partial:
redirect(h.url('summary_home', repo_name=repo.repo_name))
redirect(h.route_path('repo_summary', repo_name=repo.repo_name))
raise HTTPBadRequest()
@LoginRequired()

View file

@ -113,7 +113,7 @@ class FeedController(BaseRepoController):
def _generate_feed(cache_key):
feed = Atom1Feed(
title=self.title % repo_name,
link=url('summary_home', repo_name=repo_name, qualified=True),
link=h.route_url('repo_summary', repo_name=repo_name),
description=self.description % repo_name,
language=self.language,
ttl=self.ttl
@ -150,8 +150,7 @@ class FeedController(BaseRepoController):
def _generate_feed(cache_key):
feed = Rss201rev2Feed(
title=self.title % repo_name,
link=url('summary_home', repo_name=repo_name,
qualified=True),
link=h.route_url('repo_summary', repo_name=repo_name),
description=self.description % repo_name,
language=self.language,
ttl=self.ttl

View file

@ -101,7 +101,7 @@ class FilesController(BaseRepoController):
add_new = ""
h.flash(h.literal(
_('There are no files yet. %s') % add_new), category='warning')
redirect(h.url('summary_home', repo_name=repo_name))
redirect(h.route_path('repo_summary', repo_name=repo_name))
except (CommitDoesNotExistError, LookupError):
msg = _('No such commit exists for this repository')
h.flash(msg, category='error')
@ -669,14 +669,14 @@ class FilesController(BaseRepoController):
# If there's no commit, redirect to repo summary
if type(c.commit) is EmptyCommit:
redirect_url = "summary_home"
redirect_url = h.route_path('repo_summary', repo_name=c.repo_name)
else:
redirect_url = "changeset_home"
redirect_url = url("changeset_home", repo_name=c.repo_name,
revision='tip')
if not filename:
h.flash(_('No filename'), category='warning')
return redirect(url(redirect_url, repo_name=c.repo_name,
revision='tip'))
return redirect(redirect_url)
# extract the location from filename,
# allows using foo/bar.txt syntax to create subdirectories

View file

@ -85,7 +85,7 @@ class PullrequestsController(BaseRepoController):
except EmptyRepositoryError:
h.flash(h.literal(_('There are no commits yet')),
category='warning')
redirect(url('summary_home', repo_name=source_repo.repo_name))
redirect(h.route_path('repo_summary', repo_name=source_repo.repo_name))
commit_id = request.GET.get('commit')
branch_ref = request.GET.get('branch')

View file

@ -161,8 +161,9 @@ class ActionParser(object):
return action_map
def get_fork_name(self):
from rhodecode.lib import helpers as h
repo_name = self.action_params
_url = url('summary_home', repo_name=repo_name)
_url = h.route_path('repo_summary', repo_name=repo_name)
return _('fork name %s') % link_to(self.action_params, _url)
def get_user_name(self):

View file

@ -1342,7 +1342,7 @@ class HasAcceptedRepoType(object):
_('Action not supported for %s.' % rhodecode_repo.alias)),
category='warning')
return redirect(
url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
h.route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
class PermsDecorator(object):

View file

@ -580,7 +580,7 @@ class BaseRepoController(BaseController):
'Requirements are missing for repository %s: %s',
c.repo_name, error.message)
summary_url = url('summary_home', repo_name=c.repo_name)
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

View file

@ -1538,7 +1538,7 @@ def breadcrumb_repo_link(repo):
link_to(group.name, route_path('repo_group_home', repo_group_name=group.group_name))
for group in repo.groups_with_parents
] + [
link_to(repo.just_name, url('summary_home', repo_name=repo.repo_name))
link_to(repo.just_name, route_path('repo_summary', repo_name=repo.repo_name))
]
return literal(' &raquo; '.join(path))

View file

@ -268,8 +268,7 @@ class CommentsModel(BaseModel):
target_repo_url = h.link_to(
repo.repo_name,
h.url('summary_home',
repo_name=repo.repo_name, qualified=True))
h.route_url('repo_summary', repo_name=repo.repo_name))
# commit specifics
kwargs.update({
@ -300,13 +299,11 @@ class CommentsModel(BaseModel):
qualified=True,)
# set some variables for email notification
pr_target_repo_url = h.url(
'summary_home', repo_name=pr_target_repo.repo_name,
qualified=True)
pr_target_repo_url = h.route_url(
'repo_summary', repo_name=pr_target_repo.repo_name)
pr_source_repo_url = h.url(
'summary_home', repo_name=pr_source_repo.repo_name,
qualified=True)
pr_source_repo_url = h.route_url(
'repo_summary', repo_name=pr_source_repo.repo_name)
# pull request specifics
kwargs.update({

View file

@ -1765,6 +1765,7 @@ class Repository(Base, BaseModel):
# TODO: mikhail: Here there is an anti-pattern, we probably need to
# move this methods on models level.
from rhodecode.model.settings import SettingsModel
from rhodecode.model.repo import RepoModel
repo = self
_user_id, _time, _reason = self.locked
@ -1774,7 +1775,7 @@ class Repository(Base, BaseModel):
'repo_name': repo.repo_name,
'repo_type': repo.repo_type,
'clone_uri': repo.clone_uri or '',
'url': repo.home_url(),
'url': RepoModel().get_url(self),
'private': repo.private,
'created_on': repo.created_on,
'description': repo.description,
@ -1935,10 +1936,6 @@ class Repository(Base, BaseModel):
repo_name=self.repo_name,
repo_id=self.repo_id, **override)
def home_url(self):
request = get_current_request()
return request.route_url('repo_summary', repo_name=self.repo_name)
def set_state(self, state):
self.repo_state = state
Session().add(self)

View file

@ -999,15 +999,11 @@ class PullRequestModel(BaseModel):
qualified=True,)
# set some variables for email notification
pr_target_repo_url = h.url(
'summary_home',
repo_name=pr_target_repo.repo_name,
qualified=True)
pr_target_repo_url = h.route_url(
'repo_summary', repo_name=pr_target_repo.repo_name)
pr_source_repo_url = h.url(
'summary_home',
repo_name=pr_source_repo.repo_name,
qualified=True)
pr_source_repo_url = h.route_url(
'repo_summary', repo_name=pr_source_repo.repo_name)
# pull request specifics
pull_request_commits = [

View file

@ -30,6 +30,7 @@ import time
import traceback
from datetime import datetime, timedelta
from pyramid.threadlocal import get_current_request
from zope.cachedescriptors.property import Lazy as LazyProperty
from rhodecode import events
@ -154,9 +155,10 @@ class RepoModel(BaseModel):
repos = Repository.query().filter(Repository.group == root).all()
return repos
def get_url(self, repo):
return h.url('summary_home', repo_name=safe_str(repo.repo_name),
qualified=True)
def get_url(self, repo, request=None):
if not request:
request = get_current_request()
return request.route_url('repo_summary', repo_name=safe_str(repo.repo_name))
@classmethod
def update_repoinfo(cls, repositories=None):

View file

@ -215,6 +215,7 @@
float: left;
display: block;
position: relative;
width: 100%;
// adds some space to make copy and paste easier
.left-label,

View file

@ -62,7 +62,7 @@ function setRCMouseBindings(repoName, repoLandingRev) {
// nav in repo context
Mousetrap.bind(['g s'], function(e) {
window.location = pyroutes.url(
'summary_home', {'repo_name': repoName});
'repo_summary', {'repo_name': repoName});
});
Mousetrap.bind(['g c'], function(e) {
window.location = pyroutes.url(

View file

@ -18,9 +18,6 @@ function registerRCRoutes() {
pyroutes.register('gists', '/_admin/gists', []);
pyroutes.register('new_gist', '/_admin/gists/new', []);
pyroutes.register('toggle_following', '/_admin/toggle_following', []);
pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
@ -46,8 +43,6 @@ function registerRCRoutes() {
pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
pyroutes.register('favicon', '/favicon.ico', []);
pyroutes.register('robots', '/robots.txt', []);
pyroutes.register('auth_home', '/_admin/auth*traverse', []);
@ -99,8 +94,11 @@ 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', '/%(repo_name)s', ['repo_name']);
pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
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']);
@ -122,6 +120,8 @@ function registerRCRoutes() {
pyroutes.register('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('repo_summary', '/%(repo_name)s', ['repo_name']);
pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
pyroutes.register('search', '/_admin/search', []);

View file

@ -45,7 +45,7 @@
</td>
<td class="td-componentname">
%if l.repository is not None:
${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
${h.link_to(l.repository.repo_name, h.route_path('repo_summary',repo_name=l.repository.repo_name))}
%else:
${l.repository_name}
%endif

View file

@ -160,7 +160,7 @@
</td>
<td class="td-scope">
%if integration.repo:
<a href="${h.url('summary_home', repo_name=integration.repo.repo_name)}">
<a href="${h.route_path('repo_summary', repo_name=integration.repo.repo_name)}">
${_('repo')}:${integration.repo.repo_name}
</a>
%elif integration.repo_group:

View file

@ -48,12 +48,12 @@
if (jsonResponse === undefined) {
setTimeout(function () {
// we might have a backend problem, try dashboard again
window.location = "${h.url('summary_home', repo_name = c.repo)}";
window.location = "${h.route_path('repo_summary', repo_name = c.repo)}";
}, 3000);
} else {
if (skipCheck || jsonResponse.result === true) {
// success, means go to dashboard
window.location = "${h.url('summary_home', repo_name = c.repo)}";
window.location = "${h.route_path('repo_summary', repo_name = c.repo)}";
} else {
// Schedule the next request when the current one's complete
setTimeout(worker, 1000);

View file

@ -27,7 +27,7 @@
${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))})}
<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.route_path('repo_summary', repo_name=c.repo_info.fork.repo_name))})}
| <button class="btn btn-link btn-danger" type="submit">Remove fork reference</button></div>
% endif

View file

@ -52,6 +52,6 @@
<script>
$('#check_for_update').click(function(e){
$('#update_notice').show();
$('#update_notice').load("${h.route_path('admin_settings_system_update',version=c.rhodecode_version, platform=c.platform)}");
$('#update_notice').load("${h.route_path('admin_settings_system_update')}");
})
</script>

View file

@ -186,7 +186,7 @@
%if repo_instance.fork:
<p>
<i class="icon-code-fork"></i> ${_('Fork of')}
<a href="${h.url('summary_home',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
<a href="${h.route_path('repo_summary',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
</p>
%endif
@ -225,7 +225,7 @@
<div id="context-bar">
<div class="wrapper">
<ul id="context-pages" class="horizontal-list navigation">
<li class="${is_active('summary')}"><a class="menulink" href="${h.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
<li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
<li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
<li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li>
<li class="${is_active('compare')}">

View file

@ -124,7 +124,7 @@
<tr class="perm_row ${'%s_%s' % (section, section_perm.split('.')[-1])}">
<td class="td-componentname">
%if section == 'repositories':
<a href="${h.url('summary_home',repo_name=k)}">${k}</a>
<a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
%elif section == 'repositories_groups':
<a href="${h.route_path('repo_group_home', repo_group_name=k)}">${k}</a>
%elif section == 'user_groups':

View file

@ -9,7 +9,7 @@
<div class="menu_items_container hidden">
<ul class="menu_items">
<li>
<a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
<a title="${_('Summary')}" href="${h.route_path('repo_summary',repo_name=repo_name)}">
<span>${_('Summary')}</span>
</a>
</li>
@ -42,7 +42,7 @@
%>
<div class="${'repo_state_pending' if rstate == 'repo_state_pending' else ''} truncate">
##NAME
<a href="${h.route_path('edit_repo',repo_name=name) if admin else h.url('summary_home',repo_name=name)}">
<a href="${h.route_path('edit_repo',repo_name=name) if admin else h.route_path('repo_summary',repo_name=name)}">
##TYPE OF REPO
%if h.is_hg(rtype):
@ -64,7 +64,7 @@
${get_name(name)}
</a>
%if fork_of:
<a href="${h.url('summary_home',repo_name=fork_of.repo_name)}"><i class="icon-code-fork"></i></a>
<a href="${h.route_path('repo_summary',repo_name=fork_of.repo_name)}"><i class="icon-code-fork"></i></a>
%endif
%if rstate == 'repo_state_pending':
<i class="icon-cogs" title="${_('Repository creating in progress...')}"></i>
@ -282,7 +282,7 @@
<%def name="pullrequest_target_repo(repo_name)">
<div class="truncate">
${h.link_to(repo_name,h.url('summary_home',repo_name=repo_name))}
${h.link_to(repo_name,h.route_path('repo_summary',repo_name=repo_name))}
</div>
</%def>
<%def name="pullrequest_status(status)">

View file

@ -16,7 +16,7 @@
${base.gravatar_with_user(f.user.email, 16)}
</td>
<td class="td-componentname">
${h.link_to(f.repo_name,h.url('summary_home',repo_name=f.repo_name))}
${h.link_to(f.repo_name,h.route_path('repo_summary',repo_name=f.repo_name))}
</td>
<td class="td-description">
<div class="truncate">${f.description}</div>

View file

@ -20,7 +20,7 @@
<span class="journal_repo_name">
%if entry.repository is not None:
${h.link_to(entry.repository.repo_name,
h.url('summary_home',repo_name=entry.repository.repo_name))}
h.route_path('repo_summary',repo_name=entry.repository.repo_name))}
%else:
${entry.repository_name}
%endif

View file

@ -81,7 +81,7 @@
%endif
</span>
<span class="clone-url">
<a href="${h.url('summary_home', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a>
<a href="${h.route_path('repo_summary', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a>
</span>
<br/>
% if c.ancestor_commit:
@ -113,7 +113,7 @@
%endif
</span>
<span class="clone-url">
<a href="${h.url('summary_home', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a>
<a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a>
</span>
</div>
</div>

View file

@ -27,7 +27,7 @@
%elif h.get_repo_type_by_name(entry.get('repository')) == 'svn':
<i class="icon-svn"></i>
%endif
${h.link_to(entry['repository'], h.url('summary_home',repo_name=entry['repository']))}
${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
</td>
<td class="td-commit">
${h.link_to(h._shorten_commit_id(entry['commit_id']),

View file

@ -49,7 +49,7 @@ ${h.code_highlight(
%elif h.get_repo_type_by_name(entry.get('repository')) == 'svn':
<i class="icon-svn"></i>
%endif
${h.link_to(entry['repository'], h.url('summary_home',repo_name=entry['repository']))}
${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
</h2>
<div class="stats">
${h.link_to(h.literal(entry['f_path']), h.url('files_home',repo_name=entry['repository'],revision=entry.get('commit_id', 'tip'),f_path=entry['f_path']))}

View file

@ -16,7 +16,7 @@
%elif h.get_repo_type_by_name(entry.get('repository')) == 'svn':
<i class="icon-svn"></i>
%endif
${h.link_to(entry['repository'], h.url('summary_home',repo_name=entry['repository']))}
${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
</td>
<td class="td-componentname">
${h.link_to(h.literal(entry['f_path']),

View file

@ -1,28 +1,28 @@
<%def name="refs_counters(branches, closed_branches, tags, bookmarks)">
<span class="branchtag tag">
<a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs">
<i class="icon-branch"></i>${ungettext(
<i class="icon-branch"></i>${_ungettext(
'%(num)s Branch','%(num)s Branches', len(branches)) % {'num': len(branches)}}</a>
</span>
%if closed_branches:
<span class="branchtag tag">
<a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs">
<i class="icon-branch"></i>${ungettext(
<i class="icon-branch"></i>${_ungettext(
'%(num)s Closed Branch', '%(num)s Closed Branches', len(closed_branches)) % {'num': len(closed_branches)}}</a>
</span>
%endif
<span class="tagtag tag">
<a href="${h.route_path('tags_home',repo_name=c.repo_name)}" class="childs">
<i class="icon-tag"></i>${ungettext(
<i class="icon-tag"></i>${_ungettext(
'%(num)s Tag', '%(num)s Tags', len(tags)) % {'num': len(tags)}}</a>
</span>
%if bookmarks:
<span class="booktag tag">
<a href="${h.route_path('bookmarks_home',repo_name=c.repo_name)}" class="childs">
<i class="icon-bookmark"></i>${ungettext(
<i class="icon-bookmark"></i>${_ungettext(
'%(num)s Bookmark', '%(num)s Bookmarks', len(bookmarks)) % {'num': len(bookmarks)}}</a>
</span>
%endif
@ -92,15 +92,15 @@
## commits
% if commit_rev == -1:
${ungettext('%(num)s Commit', '%(num)s Commits', 0) % {'num': 0}},
${_ungettext('%(num)s Commit', '%(num)s Commits', 0) % {'num': 0}},
% else:
<a href="${h.url('changelog_home', repo_name=c.repo_name)}">
${ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}}</a>,
${_ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}}</a>,
% endif
## forks
<a title="${_('Number of Repository Forks')}" href="${h.url('repo_forks_home', repo_name=c.repo_name)}">
${c.repository_forks} ${ungettext('Fork', 'Forks', c.repository_forks)}</a>,
${c.repository_forks} ${_ungettext('Fork', 'Forks', c.repository_forks)}</a>,
## repo size
% if commit_rev == -1:

View file

@ -14,8 +14,14 @@
<div class="alert alert-dismissable alert-warning">
<strong>Missing requirements</strong>
These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.
Please <a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">enable this extension in settings</a>, or contact the repository owner for help.
Commits cannot be displayed, because this repository uses one or more extensions, which was not enabled. <br/>
Please <a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">enable extension in settings</a>, or contact the repository owner for help.
Missing extensions could be:
<pre>
- Mercurial largefiles
- Git LFS
</pre>
</div>
</%def>

View file

@ -36,7 +36,7 @@
%endif
<div class="table">
<div id="shortlog_data">
<%include file='../changelog/changelog_summary_data.mako'/>
<%include file='summary_commits.mako'/>
</div>
</div>
</div>
@ -110,8 +110,7 @@ $(document).ready(function(){
var callback = function (data) {
% if c.show_stats:
showRepoStats(
'lang_stats', data);
showRepoStats('lang_stats', data);
% endif
};

View file

@ -56,7 +56,7 @@ def scm_extras(user_regular, repo_stub):
RepoPreCreateEvent, RepoCreateEvent,
RepoPreDeleteEvent, RepoDeleteEvent,
])
def test_repo_events_serialized(repo_stub, EventClass):
def test_repo_events_serialized(config_stub, repo_stub, EventClass):
event = EventClass(repo_stub)
data = event.as_dict()
assert data['name'] == EventClass.name
@ -67,7 +67,7 @@ def test_repo_events_serialized(repo_stub, EventClass):
@pytest.mark.parametrize('EventClass', [
RepoPrePullEvent, RepoPullEvent, RepoPrePushEvent
])
def test_vcs_repo_events_serialize(repo_stub, scm_extras, EventClass):
def test_vcs_repo_events_serialize(config_stub, repo_stub, scm_extras, EventClass):
event = EventClass(repo_name=repo_stub.repo_name, extras=scm_extras)
data = event.as_dict()
assert data['name'] == EventClass.name
@ -76,7 +76,7 @@ def test_vcs_repo_events_serialize(repo_stub, scm_extras, EventClass):
@pytest.mark.parametrize('EventClass', [RepoPushEvent])
def test_vcs_repo_push_event_serialize(repo_stub, scm_extras, EventClass):
def test_vcs_repo_push_event_serialize(config_stub, repo_stub, scm_extras, EventClass):
event = EventClass(repo_name=repo_stub.repo_name,
pushed_commit_ids=scm_extras['commit_ids'],
extras=scm_extras)

View file

@ -24,10 +24,10 @@ import mock
import pytest
from rhodecode.lib import auth
from rhodecode.lib.utils2 import safe_str, str2bool, safe_unicode
from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
from rhodecode.model.db import Repository, RepoGroup, UserRepoToPerm, User,\
Permission
from rhodecode.lib.utils2 import safe_str, str2bool
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
@ -475,7 +475,7 @@ class TestAdminRepos(object):
assert new_repo.description == description
# test if the repository is visible in the list ?
response = self.app.get(url('summary_home', repo_name=repo_name))
response = self.app.get(h.route_path('repo_summary', repo_name=repo_name))
response.mustcontain(repo_name)
response.mustcontain(backend.alias)

View file

@ -796,11 +796,12 @@ class TestChangingFiles:
# Not allowed, redirect to the summary
redirected = response.follow()
summary_url = url('summary_home', repo_name=repo.repo_name)
summary_url = h.route_path('repo_summary', repo_name=repo.repo_name)
# As there are no commits, displays the summary page with the error of
# creating a file with no filename
assert redirected.req.path == summary_url
assert redirected.request.path == summary_url
@pytest.mark.parametrize("location, filename", [
('/abs', 'foo'),

View file

@ -22,6 +22,7 @@ import pytest
from rhodecode.tests import *
from rhodecode.tests.fixture import Fixture
from rhodecode.lib import helpers as h
from rhodecode.model.db import Repository
from rhodecode.model.repo import RepoModel
@ -147,7 +148,7 @@ class _BaseTest(TestController):
assert fork_repo.fork.repo_name == repo_name
# test if the repository is visible in the list ?
response = self.app.get(url('summary_home', repo_name=fork_name_full))
response = self.app.get(h.route_path('repo_summary', repo_name=fork_name_full))
response.mustcontain(fork_name_full)
response.mustcontain(self.REPO_TYPE)
@ -193,7 +194,7 @@ class _BaseTest(TestController):
assert fork_repo.fork.repo_name == repo_name
# test if the repository is visible in the list ?
response = self.app.get(url('summary_home', repo_name=fork_name))
response = self.app.get(h.route_path('repo_summary', repo_name=fork_name))
response.mustcontain(fork_name)
response.mustcontain(self.REPO_TYPE)
response.mustcontain('Fork of')
@ -254,7 +255,7 @@ class TestHG(_BaseTest):
@pytest.mark.usefixtures('app', 'autologin_user')
@pytest.mark.skip_backends('git','hg')
class TestSVNFork:
class TestSVNFork(object):
def test_fork_redirects(self, backend):
denied_actions = ['fork','fork_create']
@ -266,7 +267,7 @@ class TestSVNFork:
# Not allowed, redirect to the summary
redirected = response.follow()
summary_url = url('summary_home', repo_name=backend.repo_name)
summary_url = h.route_path('repo_summary', repo_name=backend.repo_name)
# URL adds leading slash and path doesn't have it
assert redirected.req.path == summary_url
assert redirected.request.path == summary_url

View file

@ -29,6 +29,7 @@ from rhodecode.tests import (
no_newline_id_generator)
from rhodecode.tests.fixture import Fixture
from rhodecode.lib.auth import check_password
from rhodecode.lib import helpers as h
from rhodecode.model.auth_token import AuthTokenModel
from rhodecode.model import validators
from rhodecode.model.db import User, Notification, UserApiKeys
@ -105,8 +106,9 @@ class TestLoginController(object):
with fixture.anon_access(False):
kwargs = {'branch': 'stable'}
response = self.app.get(
url('summary_home', repo_name=HG_REPO, **kwargs))
h.route_path('repo_summary', repo_name=HG_REPO, _query=kwargs))
assert response.status == '302 Found'
response_query = urlparse.parse_qsl(response.location)
assert 'branch=stable' in response_query[0][1]

View file

@ -24,13 +24,13 @@ from webob.exc import HTTPNotFound
import rhodecode
from rhodecode.lib.vcs.nodes import FileNode
from rhodecode.lib import helpers as h
from rhodecode.model.changeset_status import ChangesetStatusModel
from rhodecode.model.db import (
PullRequest, ChangesetStatus, UserLog, Notification)
from rhodecode.model.meta import Session
from rhodecode.model.pull_request import PullRequestModel
from rhodecode.model.user import UserModel
from rhodecode.model.repo import RepoModel
from rhodecode.tests import (
assert_session_flash, url, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN)
from rhodecode.tests.utils import AssertResponse
@ -38,7 +38,7 @@ from rhodecode.tests.utils import AssertResponse
@pytest.mark.usefixtures('app', 'autologin_user')
@pytest.mark.backends("git", "hg")
class TestPullrequestsController:
class TestPullrequestsController(object):
def test_index(self, backend):
self.app.get(url(
@ -47,7 +47,7 @@ class TestPullrequestsController:
def test_option_menu_create_pull_request_exists(self, backend):
repo_name = backend.repo_name
response = self.app.get(url('summary_home', repo_name=repo_name))
response = self.app.get(h.route_path('repo_summary', repo_name=repo_name))
create_pr_link = '<a href="%s">Create Pull Request</a>' % url(
'pullrequest', repo_name=repo_name)
@ -1074,10 +1074,10 @@ def test_redirects_to_repo_summary_for_svn_repositories(backend_svn, app, action
# Not allowed, redirect to the summary
redirected = response.follow()
summary_url = url('summary_home', repo_name=backend_svn.repo_name)
summary_url = h.route_path('repo_summary', repo_name=backend_svn.repo_name)
# URL adds leading slash and path doesn't have it
assert redirected.req.path == summary_url
assert redirected.request.path == summary_url
def test_delete_comment_returns_404_if_comment_does_not_exist(pylonsapp):

View file

@ -20,10 +20,10 @@
import pytest
from mock import Mock, patch
from pylons import url
from rhodecode.lib import base
from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
from rhodecode.lib import helpers as h
from rhodecode.model import db
@ -165,7 +165,7 @@ class TestBaseRepoControllerHandleMissingRequirements(object):
context_mock.repo_name = repo_name
controller._handle_missing_requirements(error)
expected_url = url('summary_home', repo_name=repo_name)
expected_url = h.route_path('repo_summary', repo_name=repo_name)
if should_redirect:
redirect_mock.assert_called_once_with(expected_url)
else:

View file

@ -1682,6 +1682,15 @@ def request_stub():
return request
@pytest.fixture
def context_stub():
"""
Stub context object.
"""
context = pyramid.testing.DummyResource()
return context
@pytest.fixture
def config_stub(request, request_stub):
"""

View file

@ -123,6 +123,7 @@ def set_anonymous_access(enabled):
user.active = enabled
Session().add(user)
Session().commit()
time.sleep(1.5) # must sleep for cache (1s to expire)
log.info('anonymous access is now: %s', enabled)
assert enabled == User.get_default_user().active, (
'Cannot set anonymous access')