diff --git a/rhodecode/apps/_base/__init__.py b/rhodecode/apps/_base/__init__.py
--- a/rhodecode/apps/_base/__init__.py
+++ b/rhodecode/apps/_base/__init__.py
@@ -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
diff --git a/rhodecode/apps/home/views.py b/rhodecode/apps/home/views.py
--- a/rhodecode/apps/home/views.py
+++ b/rhodecode/apps/home/views.py
@@ -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]
diff --git a/rhodecode/apps/repository/__init__.py b/rhodecode/apps/repository/__init__.py
--- a/rhodecode/apps/repository/__init__.py
+++ b/rhodecode/apps/repository/__init__.py
@@ -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()
diff --git a/rhodecode/tests/functional/test_summary.py b/rhodecode/apps/repository/tests/test_repo_summary.py
rename from rhodecode/tests/functional/test_summary.py
rename to rhodecode/apps/repository/tests/test_repo_summary.py
--- a/rhodecode/tests/functional/test_summary.py
+++ b/rhodecode/apps/repository/tests/test_repo_summary.py
@@ -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 Assert
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(TestControll
'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(TestControll
'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(TestControll
'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(TestControll
""""""
)
- 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(TestControll
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(TestControll
},
}
- 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(TestControll
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(TestControll
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(TestControll
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
+
+ # delete from file system
+ RepoModel()._delete_filesystem_repo(repo)
- 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
+ # 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
- 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
+ # 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
+class TestCreateFilesUrl(object):
- # 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)
diff --git a/rhodecode/apps/repository/views/repo_summary.py b/rhodecode/apps/repository/views/repo_summary.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/repository/views/repo_summary.py
@@ -0,0 +1,368 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2011-2017 RhodeCode GmbH
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License, version 3
+# (only), as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+# This program is dual-licensed. If you wish to learn more about the
+# RhodeCode Enterprise Edition, including its added features, Support services,
+# and proprietary license terms, please see https://rhodecode.com/licenses/
+
+import logging
+import string
+
+from pyramid.view import view_config
+
+from beaker.cache import cache_region
+
+
+from rhodecode.controllers import utils
+
+from rhodecode.apps._base import RepoAppView
+from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
+from rhodecode.lib import caches, helpers as h
+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 RepoSummaryView(RepoAppView):
+
+ def load_default_context(self):
+ c = self._get_local_tmpl_context(include_app_defaults=True)
+
+ # 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')
+
+ @cache_region('long_term')
+ def _generate_readme(cache_key):
+ readme_data = None
+ readme_node = None
+ readme_filename = None
+ commit = self._get_landing_commit_or_none(db_repo)
+ if commit:
+ log.debug("Searching for a README file.")
+ readme_node = ReadmeFinder(default_renderer).search(commit)
+ if readme_node:
+ relative_url = h.url('files_raw_home',
+ repo_name=repo_name,
+ revision=commit.raw_id,
+ f_path=readme_node.path)
+ readme_data = self._render_readme_or_none(
+ commit, readme_node, relative_url)
+ readme_filename = readme_node.path
+ return readme_data, readme_filename
+
+ invalidator_context = CacheKey.repo_context_cache(
+ _generate_readme, repo_name, CacheKey.CACHE_TYPE_README)
+
+ with invalidator_context as context:
+ context.invalidate()
+ computed = context.compute()
+
+ return computed
+
+ def _get_landing_commit_or_none(self, db_repo):
+ log.debug("Getting the landing commit.")
+ try:
+ commit = db_repo.get_landing_commit()
+ if not isinstance(commit, EmptyCommit):
+ return commit
+ else:
+ log.debug("Repository is empty, no README to render.")
+ except CommitError:
+ log.exception(
+ "Problem getting commit when trying to render the README.")
+
+ def _render_readme_or_none(self, commit, readme_node, relative_url):
+ log.debug(
+ 'Found README file `%s` rendering...', readme_node.path)
+ renderer = MarkupRenderer()
+ try:
+ html_source = renderer.render(
+ readme_node.content, filename=readme_node.path)
+ if relative_url:
+ return relative_links(html_source, relative_url)
+ return html_source
+ except Exception:
+ 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')
+ @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 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:
+ _def_clone_uri_by_id = _def_clone_uri.replace(
+ '{repo}', '_{repoid}')
+ elif '{repoid}' in _def_clone_uri:
+ _def_clone_uri_by_id = _def_clone_uri.replace(
+ '_{repoid}', '{repo}')
+
+ c.clone_repo_url = self.db_repo.clone_url(
+ user=username, uri_tmpl=_def_clone_uri)
+ 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(self.db_repo.enable_statistics)
+
+ 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 self.db_repo.enable_statistics
+ lang_stats_d = json.loads(stats.languages)
+
+ # Sort first by decreasing count and second by the file extension,
+ # so we have a consistent output.
+ lang_stats_items = sorted(lang_stats_d.iteritems(),
+ key=lambda k: (-k[1], k[0]))[:10]
+ lang_stats = [(x, {"count": y,
+ "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
+ for x, y in lang_stats_items]
+
+ c.trending_languages = json.dumps(lang_stats)
+ else:
+ c.no_data = True
+ c.trending_languages = json.dumps({})
+
+ 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:
+ 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(self.db_repo, c.visual.default_renderer)
+
+ # loads the summary commits template context
+ self._load_commits_context(c)
+
+ return self._get_template_context(c)
+
+ def get_request_commit_id(self):
+ return self.request.matchdict['commit_id']
+
+ @LoginRequired()
+ @HasRepoPermissionAnyDecorator(
+ 'repository.read', 'repository.write', 'repository.admin')
+ @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, 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(
+ self.db_repo_name, commit_id, show_stats)
+
+ def compute_stats():
+ code_stats = {}
+ size = 0
+ try:
+ 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 = string.lower(node.extension)
+ ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
+ if ext_info:
+ if ext in code_stats:
+ code_stats[ext]['count'] += 1
+ else:
+ code_stats[ext] = {"count": 1, "desc": ext_info}
+ except EmptyRepositoryError:
+ pass
+ return {'size': h.format_byte_size_binary(size),
+ 'code_stats': code_stats}
+
+ stats = cache_manager.get(_cache_key, createfunc=compute_stats)
+ return stats
+
+ @LoginRequired()
+ @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, self.db_repo_name, refs_to_create)
+ data = {
+ 'more': False,
+ 'results': res
+ }
+ return data
+
+ @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'),
+ (_("Closed branches"), repo.branches_closed, 'branch_closed'),
+ # TODO: enable when vcs can handle bookmarks filters
+ # (_("Bookmarks"), repo.bookmarks, "book"),
+ ]
+ res = self._create_reference_data(
+ repo, self.db_repo_name, refs_to_create)
+ data = {
+ 'more': False,
+ 'results': res
+ }
+ return data
+
+ def _create_reference_data(self, repo, full_repo_name, refs_to_create):
+ format_ref_id = utils.get_format_ref_id(repo)
+
+ result = []
+ for title, refs, ref_type in refs_to_create:
+ if refs:
+ result.append({
+ 'text': title,
+ 'children': self._create_reference_items(
+ repo, full_repo_name, refs, ref_type,
+ format_ref_id),
+ })
+ return result
+
+ def _create_reference_items(self, repo, full_repo_name, refs, ref_type,
+ format_ref_id):
+ result = []
+ is_svn = h.is_svn(repo)
+ for ref_name, raw_id in refs.iteritems():
+ files_url = self._create_files_url(
+ repo, full_repo_name, ref_name, raw_id, is_svn)
+ result.append({
+ 'text': ref_name,
+ 'id': format_ref_id(ref_name, raw_id),
+ 'raw_id': raw_id,
+ 'type': ref_type,
+ 'files_url': files_url,
+ })
+ return result
+
+ 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',
+ repo_name=full_repo_name,
+ f_path=ref_name if is_svn else '',
+ revision=raw_id if use_commit_id else ref_name,
+ at=ref_name)
diff --git a/rhodecode/config/middleware.py b/rhodecode/config/middleware.py
--- a/rhodecode/config/middleware.py
+++ b/rhodecode/config/middleware.py
@@ -39,11 +39,15 @@ from routes.middleware import RoutesMidd
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_hand
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, glo
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
pool = meta.Base.metadata.bind.engine.pool
log.debug('sa pool status: %s', pool.status())
-
return pyramid_app_with_cleanup
diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py
--- a/rhodecode/config/routing.py
+++ b/rhodecode/config/routing.py
@@ -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)
diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py
--- a/rhodecode/controllers/admin/repos.py
+++ b/rhodecode/controllers/admin/repos.py
@@ -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()
diff --git a/rhodecode/controllers/changelog.py b/rhodecode/controllers/changelog.py
--- a/rhodecode/controllers/changelog.py
+++ b/rhodecode/controllers/changelog.py
@@ -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(BaseRepoContro
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(BaseRepoContro
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()
diff --git a/rhodecode/controllers/compare.py b/rhodecode/controllers/compare.py
--- a/rhodecode/controllers/compare.py
+++ b/rhodecode/controllers/compare.py
@@ -63,14 +63,14 @@ class CompareController(BaseRepoControll
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()
diff --git a/rhodecode/controllers/feed.py b/rhodecode/controllers/feed.py
--- a/rhodecode/controllers/feed.py
+++ b/rhodecode/controllers/feed.py
@@ -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
diff --git a/rhodecode/controllers/files.py b/rhodecode/controllers/files.py
--- a/rhodecode/controllers/files.py
+++ b/rhodecode/controllers/files.py
@@ -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
diff --git a/rhodecode/controllers/pullrequests.py b/rhodecode/controllers/pullrequests.py
--- a/rhodecode/controllers/pullrequests.py
+++ b/rhodecode/controllers/pullrequests.py
@@ -85,7 +85,7 @@ class PullrequestsController(BaseRepoCon
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')
diff --git a/rhodecode/controllers/summary.py b/rhodecode/controllers/summary.py
deleted file mode 100644
--- a/rhodecode/controllers/summary.py
+++ /dev/null
@@ -1,315 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (C) 2010-2017 RhodeCode GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License, version 3
-# (only), as published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-# 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/
-
-"""
-Summary controller for RhodeCode Enterprise
-"""
-
-import logging
-from string import lower
-
-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.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.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.repo import ReadmeFinder
-
-
-log = logging.getLogger(__name__)
-
-
-class SummaryController(BaseRepoController):
-
- def __before__(self):
- super(SummaryController, self).__before__()
-
- def __get_readme_data(self, db_repo):
- 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):
- readme_data = None
- readme_node = None
- readme_filename = None
- commit = self._get_landing_commit_or_none(db_repo)
- if commit:
- log.debug("Searching for a README file.")
- readme_node = ReadmeFinder(default_renderer).search(commit)
- if readme_node:
- relative_url = h.url('files_raw_home',
- repo_name=repo_name,
- revision=commit.raw_id,
- f_path=readme_node.path)
- readme_data = self._render_readme_or_none(
- commit, readme_node, relative_url)
- readme_filename = readme_node.path
- return readme_data, readme_filename
-
- invalidator_context = CacheKey.repo_context_cache(
- _generate_readme, repo_name, CacheKey.CACHE_TYPE_README)
-
- with invalidator_context as context:
- context.invalidate()
- computed = context.compute()
-
- return computed
-
- def _get_landing_commit_or_none(self, db_repo):
- log.debug("Getting the landing commit.")
- try:
- commit = db_repo.get_landing_commit()
- if not isinstance(commit, EmptyCommit):
- return commit
- else:
- log.debug("Repository is empty, no README to render.")
- except CommitError:
- log.exception(
- "Problem getting commit when trying to render the README.")
-
- def _render_readme_or_none(self, commit, readme_node, relative_url):
- log.debug(
- 'Found README file `%s` rendering...', readme_node.path)
- renderer = MarkupRenderer()
- try:
- html_source = renderer.render(
- readme_node.content, filename=readme_node.path)
- if relative_url:
- return relative_links(html_source, relative_url)
- return html_source
- except Exception:
- log.exception(
- "Exception while trying to render the README")
-
- @LoginRequired()
- @HasRepoPermissionAnyDecorator(
- 'repository.read', 'repository.write', 'repository.admin')
- def index(self, repo_name):
-
- # Prepare the clone URL
-
- username = ''
- if c.rhodecode_user.username != User.DEFAULT_USER:
- username = safe_str(c.rhodecode_user.username)
-
- _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
- if '{repo}' in _def_clone_uri:
- _def_clone_uri_by_id = _def_clone_uri.replace(
- '{repo}', '_{repoid}')
- elif '{repoid}' in _def_clone_uri:
- _def_clone_uri_by_id = _def_clone_uri.replace(
- '_{repoid}', '{repo}')
-
- c.clone_repo_url = c.rhodecode_db_repo.clone_url(
- user=username, uri_tmpl=_def_clone_uri)
- c.clone_repo_url_id = c.rhodecode_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)
-
- stats = self.sa.query(Statistics)\
- .filter(Statistics.repository == c.rhodecode_db_repo)\
- .scalar()
-
- c.stats_percentage = 0
-
- if stats and stats.languages:
- c.no_data = False is c.rhodecode_db_repo.enable_statistics
- lang_stats_d = json.loads(stats.languages)
-
- # Sort first by decreasing count and second by the file extension,
- # so we have a consistent output.
- lang_stats_items = sorted(lang_stats_d.iteritems(),
- key=lambda k: (-k[1], k[0]))[:10]
- lang_stats = [(x, {"count": y,
- "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
- for x, y in lang_stats_items]
-
- c.trending_languages = json.dumps(lang_stats)
- else:
- 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)
-
- if c.repository_requirements_missing:
- return render('summary/missing_requirements.mako')
-
- c.readme_data, c.readme_file = \
- self.__get_readme_data(c.rhodecode_db_repo)
-
- _load_changelog_summary()
-
- if request.is_xhr:
- return render('changelog/changelog_summary_data.mako')
-
- return render('summary/summary.mako')
-
- @LoginRequired()
- @XHRRequired()
- @HasRepoPermissionAnyDecorator(
- 'repository.read', 'repository.write', 'repository.admin')
- @jsonify
- def repo_stats(self, repo_name, 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)
- _cache_key = caches.compute_key_from_params(
- repo_name, commit_id, show_stats)
-
- def compute_stats():
- code_stats = {}
- size = 0
- try:
- scm_instance = c.rhodecode_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_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
- if ext_info:
- if ext in code_stats:
- code_stats[ext]['count'] += 1
- else:
- code_stats[ext] = {"count": 1, "desc": ext_info}
- except EmptyRepositoryError:
- pass
- return {'size': h.format_byte_size_binary(size),
- 'code_stats': code_stats}
-
- 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
- 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)
- data = {
- 'more': False,
- 'results': res
- }
- return data
-
- @jsonify
- def repo_refs_changelog_data(self, repo_name):
- repo = c.rhodecode_repo
-
- refs_to_create = [
- (_("Branches"), repo.branches, 'branch'),
- (_("Closed branches"), repo.branches_closed, 'branch_closed'),
- # TODO: enable when vcs can handle bookmarks filters
- # (_("Bookmarks"), repo.bookmarks, "book"),
- ]
- res = self._create_reference_data(repo, repo_name, refs_to_create)
- data = {
- 'more': False,
- 'results': res
- }
- return data
-
- def _create_reference_data(self, repo, full_repo_name, refs_to_create):
- format_ref_id = utils.get_format_ref_id(repo)
-
- result = []
- for title, refs, ref_type in refs_to_create:
- if refs:
- result.append({
- 'text': title,
- 'children': self._create_reference_items(
- repo, full_repo_name, refs, ref_type, format_ref_id),
- })
- return result
-
- def _create_reference_items(self, repo, full_repo_name, refs, ref_type,
- format_ref_id):
- result = []
- is_svn = h.is_svn(repo)
- for ref_name, raw_id in refs.iteritems():
- files_url = self._create_files_url(
- repo, full_repo_name, ref_name, raw_id, is_svn)
- result.append({
- 'text': ref_name,
- 'id': format_ref_id(ref_name, raw_id),
- 'raw_id': raw_id,
- 'type': ref_type,
- 'files_url': files_url,
- })
- return result
-
- 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',
- repo_name=full_repo_name,
- f_path=ref_name if is_svn else '',
- revision=raw_id if use_commit_id else ref_name,
- at=ref_name)
diff --git a/rhodecode/lib/action_parser.py b/rhodecode/lib/action_parser.py
--- a/rhodecode/lib/action_parser.py
+++ b/rhodecode/lib/action_parser.py
@@ -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):
diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py
--- a/rhodecode/lib/auth.py
+++ b/rhodecode/lib/auth.py
@@ -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):
diff --git a/rhodecode/lib/base.py b/rhodecode/lib/base.py
--- a/rhodecode/lib/base.py
+++ b/rhodecode/lib/base.py
@@ -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
diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py
--- a/rhodecode/lib/helpers.py
+++ b/rhodecode/lib/helpers.py
@@ -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(' » '.join(path))
diff --git a/rhodecode/model/comment.py b/rhodecode/model/comment.py
--- a/rhodecode/model/comment.py
+++ b/rhodecode/model/comment.py
@@ -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({
diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py
--- a/rhodecode/model/db.py
+++ b/rhodecode/model/db.py
@@ -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)
diff --git a/rhodecode/model/pull_request.py b/rhodecode/model/pull_request.py
--- a/rhodecode/model/pull_request.py
+++ b/rhodecode/model/pull_request.py
@@ -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 = [
diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py
--- a/rhodecode/model/repo.py
+++ b/rhodecode/model/repo.py
@@ -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):
diff --git a/rhodecode/public/css/summary.less b/rhodecode/public/css/summary.less
--- a/rhodecode/public/css/summary.less
+++ b/rhodecode/public/css/summary.less
@@ -215,6 +215,7 @@
float: left;
display: block;
position: relative;
+ width: 100%;
// adds some space to make copy and paste easier
.left-label,
diff --git a/rhodecode/public/js/rhodecode/base/keyboard-bindings.js b/rhodecode/public/js/rhodecode/base/keyboard-bindings.js
--- a/rhodecode/public/js/rhodecode/base/keyboard-bindings.js
+++ b/rhodecode/public/js/rhodecode/base/keyboard-bindings.js
@@ -62,7 +62,7 @@ function setRCMouseBindings(repoName, re
// 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(
diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js
--- a/rhodecode/public/js/rhodecode/routes.js
+++ b/rhodecode/public/js/rhodecode/routes.js
@@ -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', []);
diff --git a/rhodecode/templates/admin/admin_log_base.mako b/rhodecode/templates/admin/admin_log_base.mako
--- a/rhodecode/templates/admin/admin_log_base.mako
+++ b/rhodecode/templates/admin/admin_log_base.mako
@@ -45,7 +45,7 @@
%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
diff --git a/rhodecode/templates/admin/integrations/list.mako b/rhodecode/templates/admin/integrations/list.mako
--- a/rhodecode/templates/admin/integrations/list.mako
+++ b/rhodecode/templates/admin/integrations/list.mako
@@ -160,7 +160,7 @@
%if integration.repo:
-
+
${_('repo')}:${integration.repo.repo_name}
%elif integration.repo_group:
diff --git a/rhodecode/templates/admin/repos/repo_creating.mako b/rhodecode/templates/admin/repos/repo_creating.mako
--- a/rhodecode/templates/admin/repos/repo_creating.mako
+++ b/rhodecode/templates/admin/repos/repo_creating.mako
@@ -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);
diff --git a/rhodecode/templates/admin/repos/repo_edit_advanced.mako b/rhodecode/templates/admin/repos/repo_edit_advanced.mako
--- a/rhodecode/templates/admin/repos/repo_edit_advanced.mako
+++ b/rhodecode/templates/admin/repos/repo_edit_advanced.mako
@@ -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:
- ${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))})}
+
${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))})}
| Remove fork reference
% endif
diff --git a/rhodecode/templates/admin/settings/settings_system.mako b/rhodecode/templates/admin/settings/settings_system.mako
--- a/rhodecode/templates/admin/settings/settings_system.mako
+++ b/rhodecode/templates/admin/settings/settings_system.mako
@@ -52,6 +52,6 @@
diff --git a/rhodecode/templates/base/base.mako b/rhodecode/templates/base/base.mako
--- a/rhodecode/templates/base/base.mako
+++ b/rhodecode/templates/base/base.mako
@@ -186,7 +186,7 @@
%if repo_instance.fork:
${_('Fork of')}
- ${repo_instance.fork.repo_name}
+ ${repo_instance.fork.repo_name}
%endif
@@ -225,7 +225,7 @@
-
+
diff --git a/rhodecode/templates/base/perms_summary.mako b/rhodecode/templates/base/perms_summary.mako
--- a/rhodecode/templates/base/perms_summary.mako
+++ b/rhodecode/templates/base/perms_summary.mako
@@ -124,7 +124,7 @@
%if section == 'repositories':
- ${k}
+ ${k}
%elif section == 'repositories_groups':
${k}
%elif section == 'user_groups':
diff --git a/rhodecode/templates/changelog/changelog_summary_data.mako b/rhodecode/templates/changelog/changelog_summary_data.mako
deleted file mode 100644
--- a/rhodecode/templates/changelog/changelog_summary_data.mako
+++ /dev/null
@@ -1,136 +0,0 @@
-## -*- coding: utf-8 -*-
-<%namespace name="base" file="/base/base.mako"/>
-%if c.repo_commits:
-
-
-
-
- ${_('Commit')}
- ${_('Commit message')}
- ${_('Age')}
- ${_('Author')}
- ${_('Refs')}
-
-%for cnt,cs in enumerate(c.repo_commits):
-
-
-
- %if c.statuses.get(cs.raw_id):
-
- %if c.statuses.get(cs.raw_id)[2]:
-
-
-
- %else:
-
-
-
- %endif
-
- %else:
-
- %endif
-
-
-
- ${h.show_id(cs)}
-
-
-
-
-
${h.urlify_commit_message(cs.message, c.repo_name)}
-
-
-
-
- ${h.age_component(cs.date)}
-
-
- ${base.gravatar_with_user(cs.author)}
-
-
-
-
-
-
-%endfor
-
-
-
-
-
-
-%else:
-
-%if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
-
-
-
${_('Add or upload files directly via RhodeCode:')}
-
- %endif
-
-
- %if not h.is_svn(c.rhodecode_repo):
-
-
${_('Push new repo:')}
-
-
-${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
-${c.rhodecode_repo.alias} add README # add first file
-${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
-${c.rhodecode_repo.alias} push ${'origin master' if h.is_git(c.rhodecode_repo) else ''} # push changes back
-
-
-
-
-
${_('Existing repository?')}
-
-
- %if h.is_git(c.rhodecode_repo):
-git remote add origin ${c.clone_repo_url}
-git push -u origin master
- %else:
-hg push ${c.clone_repo_url}
- %endif
-
-
-
- %endif
-
-%endif
diff --git a/rhodecode/templates/data_table/_dt_elements.mako b/rhodecode/templates/data_table/_dt_elements.mako
--- a/rhodecode/templates/data_table/_dt_elements.mako
+++ b/rhodecode/templates/data_table/_dt_elements.mako
@@ -9,7 +9,7 @@
- ${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))}
${f.description}
diff --git a/rhodecode/templates/journal/journal_data.mako b/rhodecode/templates/journal/journal_data.mako
--- a/rhodecode/templates/journal/journal_data.mako
+++ b/rhodecode/templates/journal/journal_data.mako
@@ -20,7 +20,7 @@
%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
diff --git a/rhodecode/templates/pullrequests/pullrequest_show.mako b/rhodecode/templates/pullrequests/pullrequest_show.mako
--- a/rhodecode/templates/pullrequests/pullrequest_show.mako
+++ b/rhodecode/templates/pullrequests/pullrequest_show.mako
@@ -81,7 +81,7 @@
%endif
- ${c.pull_request.source_repo.clone_url()}
+ ${c.pull_request.source_repo.clone_url()}
% if c.ancestor_commit:
@@ -113,7 +113,7 @@
%endif
- ${c.pull_request.target_repo.clone_url()}
+ ${c.pull_request.target_repo.clone_url()}
diff --git a/rhodecode/templates/search/search_commit.mako b/rhodecode/templates/search/search_commit.mako
--- a/rhodecode/templates/search/search_commit.mako
+++ b/rhodecode/templates/search/search_commit.mako
@@ -27,7 +27,7 @@
%elif h.get_repo_type_by_name(entry.get('repository')) == 'svn':
%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']))}
${h.link_to(h._shorten_commit_id(entry['commit_id']),
diff --git a/rhodecode/templates/search/search_content.mako b/rhodecode/templates/search/search_content.mako
--- a/rhodecode/templates/search/search_content.mako
+++ b/rhodecode/templates/search/search_content.mako
@@ -49,7 +49,7 @@ for line_number in matching_lines:
%elif h.get_repo_type_by_name(entry.get('repository')) == 'svn':
%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']))}
${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']))}
diff --git a/rhodecode/templates/search/search_path.mako b/rhodecode/templates/search/search_path.mako
--- a/rhodecode/templates/search/search_path.mako
+++ b/rhodecode/templates/search/search_path.mako
@@ -16,7 +16,7 @@
%elif h.get_repo_type_by_name(entry.get('repository')) == 'svn':
%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']))}
${h.link_to(h.literal(entry['f_path']),
diff --git a/rhodecode/templates/summary/components.mako b/rhodecode/templates/summary/components.mako
--- a/rhodecode/templates/summary/components.mako
+++ b/rhodecode/templates/summary/components.mako
@@ -1,28 +1,28 @@
<%def name="refs_counters(branches, closed_branches, tags, bookmarks)">
- ${ungettext(
+ ${_ungettext(
'%(num)s Branch','%(num)s Branches', len(branches)) % {'num': len(branches)}}
%if closed_branches:
- ${ungettext(
+ ${_ungettext(
'%(num)s Closed Branch', '%(num)s Closed Branches', len(closed_branches)) % {'num': len(closed_branches)}}
%endif
- ${ungettext(
+ ${_ungettext(
'%(num)s Tag', '%(num)s Tags', len(tags)) % {'num': len(tags)}}
%if bookmarks:
- ${ungettext(
+ ${_ungettext(
'%(num)s Bookmark', '%(num)s Bookmarks', len(bookmarks)) % {'num': len(bookmarks)}}
%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:
- ${ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}} ,
+ ${_ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}},
% endif
## forks
- ${c.repository_forks} ${ungettext('Fork', 'Forks', c.repository_forks)} ,
+ ${c.repository_forks} ${_ungettext('Fork', 'Forks', c.repository_forks)},
## repo size
% if commit_rev == -1:
diff --git a/rhodecode/templates/summary/missing_requirements.mako b/rhodecode/templates/summary/missing_requirements.mako
--- a/rhodecode/templates/summary/missing_requirements.mako
+++ b/rhodecode/templates/summary/missing_requirements.mako
@@ -14,8 +14,14 @@
Missing requirements
- These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.
- Please
enable this extension in settings , or contact the repository owner for help.
+ Commits cannot be displayed, because this repository uses one or more extensions, which was not enabled.
+ Please
enable extension in settings , or contact the repository owner for help.
+ Missing extensions could be:
+
+
+- Mercurial largefiles
+- Git LFS
+
%def>
diff --git a/rhodecode/templates/summary/summary.mako b/rhodecode/templates/summary/summary.mako
--- a/rhodecode/templates/summary/summary.mako
+++ b/rhodecode/templates/summary/summary.mako
@@ -36,7 +36,7 @@
%endif
- <%include file='../changelog/changelog_summary_data.mako'/>
+ <%include file='summary_commits.mako'/>
@@ -110,8 +110,7 @@
var callback = function (data) {
% if c.show_stats:
- showRepoStats(
- 'lang_stats', data);
+ showRepoStats('lang_stats', data);
% endif
};
diff --git a/rhodecode/templates/summary/summary_commits.mako b/rhodecode/templates/summary/summary_commits.mako
new file mode 100644
--- /dev/null
+++ b/rhodecode/templates/summary/summary_commits.mako
@@ -0,0 +1,136 @@
+## -*- coding: utf-8 -*-
+<%namespace name="base" file="/base/base.mako"/>
+%if c.repo_commits:
+
+
+
+
+ ${_('Commit')}
+ ${_('Commit message')}
+ ${_('Age')}
+ ${_('Author')}
+ ${_('Refs')}
+
+%for cnt,cs in enumerate(c.repo_commits):
+
+
+
+ %if c.statuses.get(cs.raw_id):
+
+ %if c.statuses.get(cs.raw_id)[2]:
+
+
+
+ %else:
+
+
+
+ %endif
+
+ %else:
+
+ %endif
+
+
+
+ ${h.show_id(cs)}
+
+
+
+
+
${h.urlify_commit_message(cs.message, c.repo_name)}
+
+
+
+
+ ${h.age_component(cs.date)}
+
+
+ ${base.gravatar_with_user(cs.author)}
+
+
+
+
+
+
+%endfor
+
+
+
+
+
+
+%else:
+
+%if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
+
+
+
${_('Add or upload files directly via RhodeCode:')}
+
+ %endif
+
+
+ %if not h.is_svn(c.rhodecode_repo):
+
+
${_('Push new repo:')}
+
+
+${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
+${c.rhodecode_repo.alias} add README # add first file
+${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
+${c.rhodecode_repo.alias} push ${'origin master' if h.is_git(c.rhodecode_repo) else ''} # push changes back
+
+
+
+
+
${_('Existing repository?')}
+
+
+ %if h.is_git(c.rhodecode_repo):
+git remote add origin ${c.clone_repo_url}
+git push -u origin master
+ %else:
+hg push ${c.clone_repo_url}
+ %endif
+
+
+
+ %endif
+
+%endif
diff --git a/rhodecode/tests/events/test_repo.py b/rhodecode/tests/events/test_repo.py
--- a/rhodecode/tests/events/test_repo.py
+++ b/rhodecode/tests/events/test_repo.py
@@ -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_stu
@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_
@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)
diff --git a/rhodecode/tests/functional/test_admin_repos.py b/rhodecode/tests/functional/test_admin_repos.py
--- a/rhodecode/tests/functional/test_admin_repos.py
+++ b/rhodecode/tests/functional/test_admin_repos.py
@@ -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)
diff --git a/rhodecode/tests/functional/test_files.py b/rhodecode/tests/functional/test_files.py
--- a/rhodecode/tests/functional/test_files.py
+++ b/rhodecode/tests/functional/test_files.py
@@ -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'),
diff --git a/rhodecode/tests/functional/test_forks.py b/rhodecode/tests/functional/test_forks.py
--- a/rhodecode/tests/functional/test_forks.py
+++ b/rhodecode/tests/functional/test_forks.py
@@ -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
diff --git a/rhodecode/tests/functional/test_login.py b/rhodecode/tests/functional/test_login.py
--- a/rhodecode/tests/functional/test_login.py
+++ b/rhodecode/tests/functional/test_login.py
@@ -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]
diff --git a/rhodecode/tests/functional/test_pullrequests.py b/rhodecode/tests/functional/test_pullrequests.py
--- a/rhodecode/tests/functional/test_pullrequests.py
+++ b/rhodecode/tests/functional/test_pullrequests.py
@@ -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 Assert
@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 = 'Create Pull Request ' % url(
'pullrequest', repo_name=repo_name)
@@ -1074,10 +1074,10 @@ def test_redirects_to_repo_summary_for_s
# 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):
diff --git a/rhodecode/tests/lib/test_base.py b/rhodecode/tests/lib/test_base.py
--- a/rhodecode/tests/lib/test_base.py
+++ b/rhodecode/tests/lib/test_base.py
@@ -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 TestBaseRepoControllerHandleMissin
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:
diff --git a/rhodecode/tests/plugin.py b/rhodecode/tests/plugin.py
--- a/rhodecode/tests/plugin.py
+++ b/rhodecode/tests/plugin.py
@@ -1683,6 +1683,15 @@ def request_stub():
@pytest.fixture
+def context_stub():
+ """
+ Stub context object.
+ """
+ context = pyramid.testing.DummyResource()
+ return context
+
+
+@pytest.fixture
def config_stub(request, request_stub):
"""
Set up pyramid.testing and return the Configurator.
diff --git a/rhodecode/tests/utils.py b/rhodecode/tests/utils.py
--- a/rhodecode/tests/utils.py
+++ b/rhodecode/tests/utils.py
@@ -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')