Show More
@@ -0,0 +1,50 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2011-2017 RhodeCode GmbH | |
|
4 | # | |
|
5 | # This program is free software: you can redistribute it and/or modify | |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
|
7 | # (only), as published by the Free Software Foundation. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
|
16 | # | |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
|
20 | import logging | |
|
21 | ||
|
22 | from pyramid.httpexceptions import HTTPNotFound | |
|
23 | from pyramid.view import view_config | |
|
24 | ||
|
25 | from rhodecode.apps._base import BaseReferencesView | |
|
26 | from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator) | |
|
27 | from rhodecode.lib import helpers as h | |
|
28 | ||
|
29 | log = logging.getLogger(__name__) | |
|
30 | ||
|
31 | ||
|
32 | class RepoBookmarksView(BaseReferencesView): | |
|
33 | ||
|
34 | @LoginRequired() | |
|
35 | @HasRepoPermissionAnyDecorator( | |
|
36 | 'repository.read', 'repository.write', 'repository.admin') | |
|
37 | @view_config( | |
|
38 | route_name='bookmarks_home', request_method='GET', | |
|
39 | renderer='rhodecode:templates/bookmarks/bookmarks.mako') | |
|
40 | def bookmarks(self): | |
|
41 | c = self.load_default_context() | |
|
42 | ||
|
43 | if not h.is_hg(self.db_repo): | |
|
44 | raise HTTPNotFound() | |
|
45 | ||
|
46 | ref_items = self.rhodecode_vcs_repo.bookmarks.items() | |
|
47 | self.load_refs_context( | |
|
48 | ref_items=ref_items, partials_template='bookmarks/bookmarks_data.mako') | |
|
49 | ||
|
50 | return self._get_template_context(c) |
@@ -0,0 +1,51 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2011-2017 RhodeCode GmbH | |
|
4 | # | |
|
5 | # This program is free software: you can redistribute it and/or modify | |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
|
7 | # (only), as published by the Free Software Foundation. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
|
16 | # | |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
|
20 | ||
|
21 | import logging | |
|
22 | from pyramid.view import view_config | |
|
23 | ||
|
24 | from rhodecode.apps._base import BaseReferencesView | |
|
25 | from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator) | |
|
26 | ||
|
27 | ||
|
28 | log = logging.getLogger(__name__) | |
|
29 | ||
|
30 | ||
|
31 | class RepoBranchesView(BaseReferencesView): | |
|
32 | ||
|
33 | @LoginRequired() | |
|
34 | @HasRepoPermissionAnyDecorator( | |
|
35 | 'repository.read', 'repository.write', 'repository.admin') | |
|
36 | @view_config( | |
|
37 | route_name='branches_home', request_method='GET', | |
|
38 | renderer='rhodecode:templates/branches/branches.mako') | |
|
39 | def branches(self): | |
|
40 | c = self.load_default_context() | |
|
41 | c.closed_branches = self.rhodecode_vcs_repo.branches_closed | |
|
42 | # NOTE(marcink): | |
|
43 | # we need this trick because of PartialRenderer still uses the | |
|
44 | # global 'c', we might not need this after full pylons migration | |
|
45 | self._register_global_c(c) | |
|
46 | ||
|
47 | ref_items = self.rhodecode_vcs_repo.branches_all.items() | |
|
48 | self.load_refs_context( | |
|
49 | ref_items=ref_items, partials_template='branches/branches_data.mako') | |
|
50 | ||
|
51 | return self._get_template_context(c) |
@@ -0,0 +1,45 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2011-2017 RhodeCode GmbH | |
|
4 | # | |
|
5 | # This program is free software: you can redistribute it and/or modify | |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
|
7 | # (only), as published by the Free Software Foundation. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
|
16 | # | |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
|
20 | ||
|
21 | import logging | |
|
22 | from pyramid.view import view_config | |
|
23 | ||
|
24 | from rhodecode.apps._base import BaseReferencesView | |
|
25 | from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator) | |
|
26 | ||
|
27 | log = logging.getLogger(__name__) | |
|
28 | ||
|
29 | ||
|
30 | class RepoTagsView(BaseReferencesView): | |
|
31 | ||
|
32 | @LoginRequired() | |
|
33 | @HasRepoPermissionAnyDecorator( | |
|
34 | 'repository.read', 'repository.write', 'repository.admin') | |
|
35 | @view_config( | |
|
36 | route_name='tags_home', request_method='GET', | |
|
37 | renderer='rhodecode:templates/tags/tags.mako') | |
|
38 | def tags(self): | |
|
39 | c = self.load_default_context() | |
|
40 | ||
|
41 | ref_items = self.rhodecode_vcs_repo.tags.items() | |
|
42 | self.load_refs_context( | |
|
43 | ref_items=ref_items, partials_template='tags/tags_data.mako') | |
|
44 | ||
|
45 | return self._get_template_context(c) |
@@ -24,8 +24,10 b' from pylons import tmpl_context as c' | |||
|
24 | 24 | from pyramid.httpexceptions import HTTPFound |
|
25 | 25 | |
|
26 | 26 | from rhodecode.lib import helpers as h |
|
27 |
from rhodecode.lib.utils |
|
|
27 | from rhodecode.lib.utils import PartialRenderer | |
|
28 | from rhodecode.lib.utils2 import StrictAttributeDict, safe_int, datetime_to_time | |
|
28 | 29 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError |
|
30 | from rhodecode.lib.ext_json import json | |
|
29 | 31 | from rhodecode.model import repo |
|
30 | 32 | from rhodecode.model.db import User |
|
31 | 33 | from rhodecode.model.scm import ScmModel |
@@ -37,6 +39,24 b" ADMIN_PREFIX = '/_admin'" | |||
|
37 | 39 | STATIC_FILE_PREFIX = '/_static' |
|
38 | 40 | |
|
39 | 41 | |
|
42 | def get_format_ref_id(repo): | |
|
43 | """Returns a `repo` specific reference formatter function""" | |
|
44 | if h.is_svn(repo): | |
|
45 | return _format_ref_id_svn | |
|
46 | else: | |
|
47 | return _format_ref_id | |
|
48 | ||
|
49 | ||
|
50 | def _format_ref_id(name, raw_id): | |
|
51 | """Default formatting of a given reference `name`""" | |
|
52 | return name | |
|
53 | ||
|
54 | ||
|
55 | def _format_ref_id_svn(name, raw_id): | |
|
56 | """Special way of formatting a reference for Subversion including path""" | |
|
57 | return '%s@%s' % (name, raw_id) | |
|
58 | ||
|
59 | ||
|
40 | 60 | class TemplateArgs(StrictAttributeDict): |
|
41 | 61 | pass |
|
42 | 62 | |
@@ -170,6 +190,56 b' class DataGridAppView(object):' | |||
|
170 | 190 | return draw, start, length |
|
171 | 191 | |
|
172 | 192 | |
|
193 | class BaseReferencesView(RepoAppView): | |
|
194 | """ | |
|
195 | Base for reference view for branches, tags and bookmarks. | |
|
196 | """ | |
|
197 | def load_default_context(self): | |
|
198 | c = self._get_local_tmpl_context() | |
|
199 | ||
|
200 | # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead | |
|
201 | c.repo_info = self.db_repo | |
|
202 | ||
|
203 | self._register_global_c(c) | |
|
204 | return c | |
|
205 | ||
|
206 | def load_refs_context(self, ref_items, partials_template): | |
|
207 | _render = PartialRenderer(partials_template) | |
|
208 | _data = [] | |
|
209 | pre_load = ["author", "date", "message"] | |
|
210 | ||
|
211 | is_svn = h.is_svn(self.rhodecode_vcs_repo) | |
|
212 | format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo) | |
|
213 | ||
|
214 | for ref_name, commit_id in ref_items: | |
|
215 | commit = self.rhodecode_vcs_repo.get_commit( | |
|
216 | commit_id=commit_id, pre_load=pre_load) | |
|
217 | ||
|
218 | # TODO: johbo: Unify generation of reference links | |
|
219 | use_commit_id = '/' in ref_name or is_svn | |
|
220 | files_url = h.url( | |
|
221 | 'files_home', | |
|
222 | repo_name=c.repo_name, | |
|
223 | f_path=ref_name if is_svn else '', | |
|
224 | revision=commit_id if use_commit_id else ref_name, | |
|
225 | at=ref_name) | |
|
226 | ||
|
227 | _data.append({ | |
|
228 | "name": _render('name', ref_name, files_url), | |
|
229 | "name_raw": ref_name, | |
|
230 | "date": _render('date', commit.date), | |
|
231 | "date_raw": datetime_to_time(commit.date), | |
|
232 | "author": _render('author', commit.author), | |
|
233 | "commit": _render( | |
|
234 | 'commit', commit.message, commit.raw_id, commit.idx), | |
|
235 | "commit_raw": commit.idx, | |
|
236 | "compare": _render( | |
|
237 | 'compare', format_ref_id(ref_name, commit.raw_id)), | |
|
238 | }) | |
|
239 | c.has_references = bool(_data) | |
|
240 | c.data = json.dumps(_data) | |
|
241 | ||
|
242 | ||
|
173 | 243 | class RepoRoutePredicate(object): |
|
174 | 244 | def __init__(self, val, config): |
|
175 | 245 | self.val = val |
@@ -21,6 +21,21 b'' | |||
|
21 | 21 | |
|
22 | 22 | def includeme(config): |
|
23 | 23 | |
|
24 | # Tags | |
|
25 | config.add_route( | |
|
26 | name='tags_home', | |
|
27 | pattern='/{repo_name:.*?[^/]}/tags', repo_route=True) | |
|
28 | ||
|
29 | # Branches | |
|
30 | config.add_route( | |
|
31 | name='branches_home', | |
|
32 | pattern='/{repo_name:.*?[^/]}/branches', repo_route=True) | |
|
33 | ||
|
34 | # Bookmarks | |
|
35 | config.add_route( | |
|
36 | name='bookmarks_home', | |
|
37 | pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True) | |
|
38 | ||
|
24 | 39 | # Settings |
|
25 | 40 | config.add_route( |
|
26 | 41 | name='edit_repo', |
@@ -18,24 +18,35 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | import pytest | |
|
21 | 22 | from rhodecode.model.db import Repository |
|
22 | from rhodecode.tests import * | |
|
23 | 23 | |
|
24 | 24 | |
|
25 | class TestBookmarksController(TestController): | |
|
25 | def route_path(name, params=None, **kwargs): | |
|
26 | import urllib | |
|
27 | ||
|
28 | base_url = { | |
|
29 | 'bookmarks_home': '/{repo_name}/bookmarks', | |
|
30 | }[name].format(**kwargs) | |
|
31 | ||
|
32 | if params: | |
|
33 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |
|
34 | return base_url | |
|
35 | ||
|
36 | ||
|
37 | @pytest.mark.usefixtures('autologin_user', 'app') | |
|
38 | class TestBookmarks(object): | |
|
26 | 39 | |
|
27 | 40 | def test_index(self, backend): |
|
28 | self.log_user() | |
|
29 | 41 | if backend.alias == 'hg': |
|
30 |
response = self.app.get( |
|
|
31 | action='index', | |
|
32 | repo_name=backend.repo_name)) | |
|
42 | response = self.app.get( | |
|
43 | route_path('bookmarks_home', repo_name=backend.repo_name)) | |
|
33 | 44 | |
|
34 | 45 | repo = Repository.get_by_repo_name(backend.repo_name) |
|
35 | 46 | for commit_id, obj_name in repo.scm_instance().bookmarks.items(): |
|
36 | 47 | assert commit_id in response |
|
37 | 48 | assert obj_name in response |
|
38 | 49 | else: |
|
39 |
self.app.get( |
|
|
40 | action='index', | |
|
41 | repo_name=backend.repo_name), status=404) No newline at end of file | |
|
50 | self.app.get( | |
|
51 | route_path('bookmarks_home', repo_name=backend.repo_name), | |
|
52 | status=404) |
@@ -18,17 +18,28 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | import pytest | |
|
21 | 22 | from rhodecode.model.db import Repository |
|
22 | from rhodecode.tests import * | |
|
23 | 23 | |
|
24 | 24 | |
|
25 | class TestBranchesController(TestController): | |
|
25 | def route_path(name, params=None, **kwargs): | |
|
26 | import urllib | |
|
27 | ||
|
28 | base_url = { | |
|
29 | 'branches_home': '/{repo_name}/branches', | |
|
30 | }[name].format(**kwargs) | |
|
31 | ||
|
32 | if params: | |
|
33 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |
|
34 | return base_url | |
|
35 | ||
|
36 | ||
|
37 | @pytest.mark.usefixtures('autologin_user', 'app') | |
|
38 | class TestBranchesController(object): | |
|
26 | 39 | |
|
27 | 40 | def test_index(self, backend): |
|
28 | self.log_user() | |
|
29 | response = self.app.get(url(controller='branches', | |
|
30 | action='index', | |
|
31 | repo_name=backend.repo_name)) | |
|
41 | response = self.app.get( | |
|
42 | route_path('branches_home', repo_name=backend.repo_name)) | |
|
32 | 43 | |
|
33 | 44 | repo = Repository.get_by_repo_name(backend.repo_name) |
|
34 | 45 |
@@ -18,16 +18,27 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | import pytest | |
|
21 | 22 | from rhodecode.model.db import Repository |
|
22 | from rhodecode.tests import * | |
|
23 | 23 | |
|
24 | 24 | |
|
25 | class TestTagsController(TestController): | |
|
25 | def route_path(name, params=None, **kwargs): | |
|
26 | import urllib | |
|
27 | ||
|
28 | base_url = { | |
|
29 | 'tags_home': '/{repo_name}/tags', | |
|
30 | }[name].format(**kwargs) | |
|
31 | ||
|
32 | if params: | |
|
33 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |
|
34 | return base_url | |
|
35 | ||
|
36 | ||
|
37 | @pytest.mark.usefixtures('autologin_user', 'app') | |
|
38 | class TestTagsController(object): | |
|
26 | 39 | def test_index(self, backend): |
|
27 | self.log_user() | |
|
28 | response = self.app.get(url(controller='tags', | |
|
29 | action='index', | |
|
30 | repo_name=backend.repo_name)) | |
|
40 | response = self.app.get( | |
|
41 | route_path('tags_home', repo_name=backend.repo_name)) | |
|
31 | 42 | |
|
32 | 43 | repo = Repository.get_by_repo_name(backend.repo_name) |
|
33 | 44 |
@@ -890,18 +890,6 b' def make_map(config):' | |||
|
890 | 890 | controller='summary', conditions={'function': check_repo}, |
|
891 | 891 | requirements=URL_NAME_REQUIREMENTS) |
|
892 | 892 | |
|
893 | rmap.connect('branches_home', '/{repo_name}/branches', | |
|
894 | controller='branches', conditions={'function': check_repo}, | |
|
895 | requirements=URL_NAME_REQUIREMENTS) | |
|
896 | ||
|
897 | rmap.connect('tags_home', '/{repo_name}/tags', | |
|
898 | controller='tags', conditions={'function': check_repo}, | |
|
899 | requirements=URL_NAME_REQUIREMENTS) | |
|
900 | ||
|
901 | rmap.connect('bookmarks_home', '/{repo_name}/bookmarks', | |
|
902 | controller='bookmarks', conditions={'function': check_repo}, | |
|
903 | requirements=URL_NAME_REQUIREMENTS) | |
|
904 | ||
|
905 | 893 | rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True, |
|
906 | 894 | controller='changelog', conditions={'function': check_repo}, |
|
907 | 895 | requirements=URL_NAME_REQUIREMENTS) |
@@ -96,6 +96,9 b' function registerRCRoutes() {' | |||
|
96 | 96 | pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); |
|
97 | 97 | pyroutes.register('repo_list_data', '/_repos', []); |
|
98 | 98 | pyroutes.register('goto_switcher_data', '/_goto_data', []); |
|
99 | pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']); | |
|
100 | pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']); | |
|
101 | pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']); | |
|
99 | 102 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); |
|
100 | 103 | pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); |
|
101 | 104 | pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); |
@@ -1,27 +1,27 b'' | |||
|
1 | 1 | <%def name="refs_counters(branches, closed_branches, tags, bookmarks)"> |
|
2 | 2 | <span class="branchtag tag"> |
|
3 |
<a href="${h. |
|
|
3 | <a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs"> | |
|
4 | 4 | <i class="icon-branch"></i>${ungettext( |
|
5 | 5 | '%(num)s Branch','%(num)s Branches', len(branches)) % {'num': len(branches)}}</a> |
|
6 | 6 | </span> |
|
7 | 7 | |
|
8 | 8 | %if closed_branches: |
|
9 | 9 | <span class="branchtag tag"> |
|
10 |
<a href="${h. |
|
|
10 | <a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs"> | |
|
11 | 11 | <i class="icon-branch"></i>${ungettext( |
|
12 | 12 | '%(num)s Closed Branch', '%(num)s Closed Branches', len(closed_branches)) % {'num': len(closed_branches)}}</a> |
|
13 | 13 | </span> |
|
14 | 14 | %endif |
|
15 | 15 | |
|
16 | 16 | <span class="tagtag tag"> |
|
17 |
<a href="${h. |
|
|
17 | <a href="${h.route_path('tags_home',repo_name=c.repo_name)}" class="childs"> | |
|
18 | 18 | <i class="icon-tag"></i>${ungettext( |
|
19 | 19 | '%(num)s Tag', '%(num)s Tags', len(tags)) % {'num': len(tags)}}</a> |
|
20 | 20 | </span> |
|
21 | 21 | |
|
22 | 22 | %if bookmarks: |
|
23 | 23 | <span class="booktag tag"> |
|
24 |
<a href="${h. |
|
|
24 | <a href="${h.route_path('bookmarks_home',repo_name=c.repo_name)}" class="childs"> | |
|
25 | 25 | <i class="icon-bookmark"></i>${ungettext( |
|
26 | 26 | '%(num)s Bookmark', '%(num)s Bookmarks', len(bookmarks)) % {'num': len(bookmarks)}}</a> |
|
27 | 27 | </span> |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now