##// END OF EJS Templates
tags/branches/bookmarks: moved views into pyramid.
marcink -
r1746:198df317 default
parent child Browse files
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)
@@ -1,203 +1,273 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 import time
22 22 import logging
23 23 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.utils2 import StrictAttributeDict, safe_int
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
32 34
33 35 log = logging.getLogger(__name__)
34 36
35 37
36 38 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
43 63
44 64 class BaseAppView(object):
45 65
46 66 def __init__(self, context, request):
47 67 self.request = request
48 68 self.context = context
49 69 self.session = request.session
50 70 self._rhodecode_user = request.user # auth user
51 71 self._rhodecode_db_user = self._rhodecode_user.get_instance()
52 72 self._maybe_needs_password_change(
53 73 request.matched_route.name, self._rhodecode_db_user)
54 74
55 75 def _maybe_needs_password_change(self, view_name, user_obj):
56 76 log.debug('Checking if user %s needs password change on view %s',
57 77 user_obj, view_name)
58 78 skip_user_views = [
59 79 'logout', 'login',
60 80 'my_account_password', 'my_account_password_update'
61 81 ]
62 82
63 83 if not user_obj:
64 84 return
65 85
66 86 if user_obj.username == User.DEFAULT_USER:
67 87 return
68 88
69 89 now = time.time()
70 90 should_change = user_obj.user_data.get('force_password_change')
71 91 change_after = safe_int(should_change) or 0
72 92 if should_change and now > change_after:
73 93 log.debug('User %s requires password change', user_obj)
74 94 h.flash('You are required to change your password', 'warning',
75 95 ignore_duplicate=True)
76 96
77 97 if view_name not in skip_user_views:
78 98 raise HTTPFound(
79 99 self.request.route_path('my_account_password'))
80 100
81 101 def _get_local_tmpl_context(self):
82 102 c = TemplateArgs()
83 103 c.auth_user = self.request.user
84 104 return c
85 105
86 106 def _register_global_c(self, tmpl_args):
87 107 """
88 108 Registers attributes to pylons global `c`
89 109 """
90 110 # TODO(marcink): remove once pyramid migration is finished
91 111 for k, v in tmpl_args.items():
92 112 setattr(c, k, v)
93 113
94 114 def _get_template_context(self, tmpl_args):
95 115 self._register_global_c(tmpl_args)
96 116
97 117 local_tmpl_args = {
98 118 'defaults': {},
99 119 'errors': {},
100 120 }
101 121 local_tmpl_args.update(tmpl_args)
102 122 return local_tmpl_args
103 123
104 124 def load_default_context(self):
105 125 """
106 126 example:
107 127
108 128 def load_default_context(self):
109 129 c = self._get_local_tmpl_context()
110 130 c.custom_var = 'foobar'
111 131 self._register_global_c(c)
112 132 return c
113 133 """
114 134 raise NotImplementedError('Needs implementation in view class')
115 135
116 136
117 137 class RepoAppView(BaseAppView):
118 138
119 139 def __init__(self, context, request):
120 140 super(RepoAppView, self).__init__(context, request)
121 141 self.db_repo = request.db_repo
122 142 self.db_repo_name = self.db_repo.repo_name
123 143 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
124 144
125 145 def _handle_missing_requirements(self, error):
126 146 log.error(
127 147 'Requirements are missing for repository %s: %s',
128 148 self.db_repo_name, error.message)
129 149
130 150 def _get_local_tmpl_context(self):
131 151 c = super(RepoAppView, self)._get_local_tmpl_context()
132 152 # register common vars for this type of view
133 153 c.rhodecode_db_repo = self.db_repo
134 154 c.repo_name = self.db_repo_name
135 155 c.repository_pull_requests = self.db_repo_pull_requests
136 156
137 157 c.repository_requirements_missing = False
138 158 try:
139 159 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
140 160 except RepositoryRequirementError as e:
141 161 c.repository_requirements_missing = True
142 162 self._handle_missing_requirements(e)
143 163
144 164 return c
145 165
146 166
147 167 class DataGridAppView(object):
148 168 """
149 169 Common class to have re-usable grid rendering components
150 170 """
151 171
152 172 def _extract_ordering(self, request, column_map=None):
153 173 column_map = column_map or {}
154 174 column_index = safe_int(request.GET.get('order[0][column]'))
155 175 order_dir = request.GET.get(
156 176 'order[0][dir]', 'desc')
157 177 order_by = request.GET.get(
158 178 'columns[%s][data][sort]' % column_index, 'name_raw')
159 179
160 180 # translate datatable to DB columns
161 181 order_by = column_map.get(order_by) or order_by
162 182
163 183 search_q = request.GET.get('search[value]')
164 184 return search_q, order_by, order_dir
165 185
166 186 def _extract_chunk(self, request):
167 187 start = safe_int(request.GET.get('start'), 0)
168 188 length = safe_int(request.GET.get('length'), 25)
169 189 draw = safe_int(request.GET.get('draw'))
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
176 246
177 247 def text(self):
178 248 return 'repo_route = %s' % self.val
179 249
180 250 phash = text
181 251
182 252 def __call__(self, info, request):
183 253 repo_name = info['match']['repo_name']
184 254 repo_model = repo.RepoModel()
185 255 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
186 256 # if we match quickly from database, short circuit the operation,
187 257 # and validate repo based on the type.
188 258 if by_name_match:
189 259 # register this as request object we can re-use later
190 260 request.db_repo = by_name_match
191 261 return True
192 262
193 263 by_id_match = repo_model.get_repo_by_id(repo_name)
194 264 if by_id_match:
195 265 request.db_repo = by_id_match
196 266 return True
197 267
198 268 return False
199 269
200 270
201 271 def includeme(config):
202 272 config.add_route_predicate(
203 273 'repo_route', RepoRoutePredicate)
@@ -1,66 +1,81 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 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',
27 42 pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
28 43
29 44 # Caches
30 45 config.add_route(
31 46 name='edit_repo_caches',
32 47 pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True)
33 48
34 49 # Permissions
35 50 config.add_route(
36 51 name='edit_repo_perms',
37 52 pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
38 53
39 54 # Repo Review Rules
40 55 config.add_route(
41 56 name='repo_reviewers',
42 57 pattern='/{repo_name:.*?[^/]}/settings/review/rules', repo_route=True)
43 58
44 59 # Maintenance
45 60 config.add_route(
46 61 name='repo_maintenance',
47 62 pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True)
48 63
49 64 config.add_route(
50 65 name='repo_maintenance_execute',
51 66 pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True)
52 67
53 68 # Strip
54 69 config.add_route(
55 70 name='strip',
56 71 pattern='/{repo_name:.*?[^/]}/settings/strip', repo_route=True)
57 72
58 73 config.add_route(
59 74 name='strip_check',
60 75 pattern='/{repo_name:.*?[^/]}/settings/strip_check', repo_route=True)
61 76
62 77 config.add_route(
63 78 name='strip_execute',
64 79 pattern='/{repo_name:.*?[^/]}/settings/strip_execute', repo_route=True)
65 80 # Scan module for configuration decorators.
66 81 config.scan()
@@ -1,41 +1,52 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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(url(controller='bookmarks',
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(url(controller='bookmarks',
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)
@@ -1,37 +1,48 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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
35 46 for commit_id, obj_name in repo.scm_instance().branches.items():
36 47 assert commit_id in response
37 48 assert obj_name in response
@@ -1,36 +1,47 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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
34 45 for commit_id, obj_name in repo.scm_instance().tags.items():
35 46 assert commit_id in response
36 47 assert obj_name in response
@@ -1,1088 +1,1076 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 """
22 22 Routes configuration
23 23
24 24 The more specific and detailed routes should be defined first so they
25 25 may take precedent over the more generic routes. For more information
26 26 refer to the routes manual at http://routes.groovie.org/docs/
27 27
28 28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 29 and _route_name variable which uses some of stored naming here to do redirects.
30 30 """
31 31 import os
32 32 import re
33 33 from routes import Mapper
34 34
35 35 # prefix for non repository related links needs to be prefixed with `/`
36 36 ADMIN_PREFIX = '/_admin'
37 37 STATIC_FILE_PREFIX = '/_static'
38 38
39 39 # Default requirements for URL parts
40 40 URL_NAME_REQUIREMENTS = {
41 41 # group name can have a slash in them, but they must not end with a slash
42 42 'group_name': r'.*?[^/]',
43 43 'repo_group_name': r'.*?[^/]',
44 44 # repo names can have a slash in them, but they must not end with a slash
45 45 'repo_name': r'.*?[^/]',
46 46 # file path eats up everything at the end
47 47 'f_path': r'.*',
48 48 # reference types
49 49 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
50 50 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
51 51 }
52 52
53 53
54 54 def add_route_requirements(route_path, requirements):
55 55 """
56 56 Adds regex requirements to pyramid routes using a mapping dict
57 57
58 58 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
59 59 '/{action}/{id:\d+}'
60 60
61 61 """
62 62 for key, regex in requirements.items():
63 63 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
64 64 return route_path
65 65
66 66
67 67 class JSRoutesMapper(Mapper):
68 68 """
69 69 Wrapper for routes.Mapper to make pyroutes compatible url definitions
70 70 """
71 71 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
72 72 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
73 73 def __init__(self, *args, **kw):
74 74 super(JSRoutesMapper, self).__init__(*args, **kw)
75 75 self._jsroutes = []
76 76
77 77 def connect(self, *args, **kw):
78 78 """
79 79 Wrapper for connect to take an extra argument jsroute=True
80 80
81 81 :param jsroute: boolean, if True will add the route to the pyroutes list
82 82 """
83 83 if kw.pop('jsroute', False):
84 84 if not self._named_route_regex.match(args[0]):
85 85 raise Exception('only named routes can be added to pyroutes')
86 86 self._jsroutes.append(args[0])
87 87
88 88 super(JSRoutesMapper, self).connect(*args, **kw)
89 89
90 90 def _extract_route_information(self, route):
91 91 """
92 92 Convert a route into tuple(name, path, args), eg:
93 93 ('show_user', '/profile/%(username)s', ['username'])
94 94 """
95 95 routepath = route.routepath
96 96 def replace(matchobj):
97 97 if matchobj.group(1):
98 98 return "%%(%s)s" % matchobj.group(1).split(':')[0]
99 99 else:
100 100 return "%%(%s)s" % matchobj.group(2)
101 101
102 102 routepath = self._argument_prog.sub(replace, routepath)
103 103 return (
104 104 route.name,
105 105 routepath,
106 106 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
107 107 for arg in self._argument_prog.findall(route.routepath)]
108 108 )
109 109
110 110 def jsroutes(self):
111 111 """
112 112 Return a list of pyroutes.js compatible routes
113 113 """
114 114 for route_name in self._jsroutes:
115 115 yield self._extract_route_information(self._routenames[route_name])
116 116
117 117
118 118 def make_map(config):
119 119 """Create, configure and return the routes Mapper"""
120 120 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
121 121 always_scan=config['debug'])
122 122 rmap.minimization = False
123 123 rmap.explicit = False
124 124
125 125 from rhodecode.lib.utils2 import str2bool
126 126 from rhodecode.model import repo, repo_group
127 127
128 128 def check_repo(environ, match_dict):
129 129 """
130 130 check for valid repository for proper 404 handling
131 131
132 132 :param environ:
133 133 :param match_dict:
134 134 """
135 135 repo_name = match_dict.get('repo_name')
136 136
137 137 if match_dict.get('f_path'):
138 138 # fix for multiple initial slashes that causes errors
139 139 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
140 140 repo_model = repo.RepoModel()
141 141 by_name_match = repo_model.get_by_repo_name(repo_name)
142 142 # if we match quickly from database, short circuit the operation,
143 143 # and validate repo based on the type.
144 144 if by_name_match:
145 145 return True
146 146
147 147 by_id_match = repo_model.get_repo_by_id(repo_name)
148 148 if by_id_match:
149 149 repo_name = by_id_match.repo_name
150 150 match_dict['repo_name'] = repo_name
151 151 return True
152 152
153 153 return False
154 154
155 155 def check_group(environ, match_dict):
156 156 """
157 157 check for valid repository group path for proper 404 handling
158 158
159 159 :param environ:
160 160 :param match_dict:
161 161 """
162 162 repo_group_name = match_dict.get('group_name')
163 163 repo_group_model = repo_group.RepoGroupModel()
164 164 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
165 165 if by_name_match:
166 166 return True
167 167
168 168 return False
169 169
170 170 def check_user_group(environ, match_dict):
171 171 """
172 172 check for valid user group for proper 404 handling
173 173
174 174 :param environ:
175 175 :param match_dict:
176 176 """
177 177 return True
178 178
179 179 def check_int(environ, match_dict):
180 180 return match_dict.get('id').isdigit()
181 181
182 182
183 183 #==========================================================================
184 184 # CUSTOM ROUTES HERE
185 185 #==========================================================================
186 186
187 187 # MAIN PAGE
188 188 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
189 189
190 190 # ping and pylons error test
191 191 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
192 192 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
193 193
194 194 # ADMIN REPOSITORY ROUTES
195 195 with rmap.submapper(path_prefix=ADMIN_PREFIX,
196 196 controller='admin/repos') as m:
197 197 m.connect('repos', '/repos',
198 198 action='create', conditions={'method': ['POST']})
199 199 m.connect('repos', '/repos',
200 200 action='index', conditions={'method': ['GET']})
201 201 m.connect('new_repo', '/create_repository', jsroute=True,
202 202 action='create_repository', conditions={'method': ['GET']})
203 203 m.connect('delete_repo', '/repos/{repo_name}',
204 204 action='delete', conditions={'method': ['DELETE']},
205 205 requirements=URL_NAME_REQUIREMENTS)
206 206 m.connect('repo', '/repos/{repo_name}',
207 207 action='show', conditions={'method': ['GET'],
208 208 'function': check_repo},
209 209 requirements=URL_NAME_REQUIREMENTS)
210 210
211 211 # ADMIN REPOSITORY GROUPS ROUTES
212 212 with rmap.submapper(path_prefix=ADMIN_PREFIX,
213 213 controller='admin/repo_groups') as m:
214 214 m.connect('repo_groups', '/repo_groups',
215 215 action='create', conditions={'method': ['POST']})
216 216 m.connect('repo_groups', '/repo_groups',
217 217 action='index', conditions={'method': ['GET']})
218 218 m.connect('new_repo_group', '/repo_groups/new',
219 219 action='new', conditions={'method': ['GET']})
220 220 m.connect('update_repo_group', '/repo_groups/{group_name}',
221 221 action='update', conditions={'method': ['PUT'],
222 222 'function': check_group},
223 223 requirements=URL_NAME_REQUIREMENTS)
224 224
225 225 # EXTRAS REPO GROUP ROUTES
226 226 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
227 227 action='edit',
228 228 conditions={'method': ['GET'], 'function': check_group},
229 229 requirements=URL_NAME_REQUIREMENTS)
230 230 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
231 231 action='edit',
232 232 conditions={'method': ['PUT'], 'function': check_group},
233 233 requirements=URL_NAME_REQUIREMENTS)
234 234
235 235 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
236 236 action='edit_repo_group_advanced',
237 237 conditions={'method': ['GET'], 'function': check_group},
238 238 requirements=URL_NAME_REQUIREMENTS)
239 239 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
240 240 action='edit_repo_group_advanced',
241 241 conditions={'method': ['PUT'], 'function': check_group},
242 242 requirements=URL_NAME_REQUIREMENTS)
243 243
244 244 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
245 245 action='edit_repo_group_perms',
246 246 conditions={'method': ['GET'], 'function': check_group},
247 247 requirements=URL_NAME_REQUIREMENTS)
248 248 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
249 249 action='update_perms',
250 250 conditions={'method': ['PUT'], 'function': check_group},
251 251 requirements=URL_NAME_REQUIREMENTS)
252 252
253 253 m.connect('delete_repo_group', '/repo_groups/{group_name}',
254 254 action='delete', conditions={'method': ['DELETE'],
255 255 'function': check_group},
256 256 requirements=URL_NAME_REQUIREMENTS)
257 257
258 258 # ADMIN USER ROUTES
259 259 with rmap.submapper(path_prefix=ADMIN_PREFIX,
260 260 controller='admin/users') as m:
261 261 m.connect('users', '/users',
262 262 action='create', conditions={'method': ['POST']})
263 263 m.connect('new_user', '/users/new',
264 264 action='new', conditions={'method': ['GET']})
265 265 m.connect('update_user', '/users/{user_id}',
266 266 action='update', conditions={'method': ['PUT']})
267 267 m.connect('delete_user', '/users/{user_id}',
268 268 action='delete', conditions={'method': ['DELETE']})
269 269 m.connect('edit_user', '/users/{user_id}/edit',
270 270 action='edit', conditions={'method': ['GET']}, jsroute=True)
271 271 m.connect('user', '/users/{user_id}',
272 272 action='show', conditions={'method': ['GET']})
273 273 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
274 274 action='reset_password', conditions={'method': ['POST']})
275 275 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
276 276 action='create_personal_repo_group', conditions={'method': ['POST']})
277 277
278 278 # EXTRAS USER ROUTES
279 279 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
280 280 action='edit_advanced', conditions={'method': ['GET']})
281 281 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
282 282 action='update_advanced', conditions={'method': ['PUT']})
283 283
284 284 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
285 285 action='edit_global_perms', conditions={'method': ['GET']})
286 286 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
287 287 action='update_global_perms', conditions={'method': ['PUT']})
288 288
289 289 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
290 290 action='edit_perms_summary', conditions={'method': ['GET']})
291 291
292 292 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
293 293 action='edit_emails', conditions={'method': ['GET']})
294 294 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
295 295 action='add_email', conditions={'method': ['PUT']})
296 296 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
297 297 action='delete_email', conditions={'method': ['DELETE']})
298 298
299 299 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
300 300 action='edit_ips', conditions={'method': ['GET']})
301 301 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
302 302 action='add_ip', conditions={'method': ['PUT']})
303 303 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
304 304 action='delete_ip', conditions={'method': ['DELETE']})
305 305
306 306 # ADMIN USER GROUPS REST ROUTES
307 307 with rmap.submapper(path_prefix=ADMIN_PREFIX,
308 308 controller='admin/user_groups') as m:
309 309 m.connect('users_groups', '/user_groups',
310 310 action='create', conditions={'method': ['POST']})
311 311 m.connect('users_groups', '/user_groups',
312 312 action='index', conditions={'method': ['GET']})
313 313 m.connect('new_users_group', '/user_groups/new',
314 314 action='new', conditions={'method': ['GET']})
315 315 m.connect('update_users_group', '/user_groups/{user_group_id}',
316 316 action='update', conditions={'method': ['PUT']})
317 317 m.connect('delete_users_group', '/user_groups/{user_group_id}',
318 318 action='delete', conditions={'method': ['DELETE']})
319 319 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
320 320 action='edit', conditions={'method': ['GET']},
321 321 function=check_user_group)
322 322
323 323 # EXTRAS USER GROUP ROUTES
324 324 m.connect('edit_user_group_global_perms',
325 325 '/user_groups/{user_group_id}/edit/global_permissions',
326 326 action='edit_global_perms', conditions={'method': ['GET']})
327 327 m.connect('edit_user_group_global_perms',
328 328 '/user_groups/{user_group_id}/edit/global_permissions',
329 329 action='update_global_perms', conditions={'method': ['PUT']})
330 330 m.connect('edit_user_group_perms_summary',
331 331 '/user_groups/{user_group_id}/edit/permissions_summary',
332 332 action='edit_perms_summary', conditions={'method': ['GET']})
333 333
334 334 m.connect('edit_user_group_perms',
335 335 '/user_groups/{user_group_id}/edit/permissions',
336 336 action='edit_perms', conditions={'method': ['GET']})
337 337 m.connect('edit_user_group_perms',
338 338 '/user_groups/{user_group_id}/edit/permissions',
339 339 action='update_perms', conditions={'method': ['PUT']})
340 340
341 341 m.connect('edit_user_group_advanced',
342 342 '/user_groups/{user_group_id}/edit/advanced',
343 343 action='edit_advanced', conditions={'method': ['GET']})
344 344
345 345 m.connect('edit_user_group_advanced_sync',
346 346 '/user_groups/{user_group_id}/edit/advanced/sync',
347 347 action='edit_advanced_set_synchronization', conditions={'method': ['POST']})
348 348
349 349 m.connect('edit_user_group_members',
350 350 '/user_groups/{user_group_id}/edit/members', jsroute=True,
351 351 action='user_group_members', conditions={'method': ['GET']})
352 352
353 353 # ADMIN PERMISSIONS ROUTES
354 354 with rmap.submapper(path_prefix=ADMIN_PREFIX,
355 355 controller='admin/permissions') as m:
356 356 m.connect('admin_permissions_application', '/permissions/application',
357 357 action='permission_application_update', conditions={'method': ['POST']})
358 358 m.connect('admin_permissions_application', '/permissions/application',
359 359 action='permission_application', conditions={'method': ['GET']})
360 360
361 361 m.connect('admin_permissions_global', '/permissions/global',
362 362 action='permission_global_update', conditions={'method': ['POST']})
363 363 m.connect('admin_permissions_global', '/permissions/global',
364 364 action='permission_global', conditions={'method': ['GET']})
365 365
366 366 m.connect('admin_permissions_object', '/permissions/object',
367 367 action='permission_objects_update', conditions={'method': ['POST']})
368 368 m.connect('admin_permissions_object', '/permissions/object',
369 369 action='permission_objects', conditions={'method': ['GET']})
370 370
371 371 m.connect('admin_permissions_ips', '/permissions/ips',
372 372 action='permission_ips', conditions={'method': ['POST']})
373 373 m.connect('admin_permissions_ips', '/permissions/ips',
374 374 action='permission_ips', conditions={'method': ['GET']})
375 375
376 376 m.connect('admin_permissions_overview', '/permissions/overview',
377 377 action='permission_perms', conditions={'method': ['GET']})
378 378
379 379 # ADMIN DEFAULTS REST ROUTES
380 380 with rmap.submapper(path_prefix=ADMIN_PREFIX,
381 381 controller='admin/defaults') as m:
382 382 m.connect('admin_defaults_repositories', '/defaults/repositories',
383 383 action='update_repository_defaults', conditions={'method': ['POST']})
384 384 m.connect('admin_defaults_repositories', '/defaults/repositories',
385 385 action='index', conditions={'method': ['GET']})
386 386
387 387 # ADMIN DEBUG STYLE ROUTES
388 388 if str2bool(config.get('debug_style')):
389 389 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
390 390 controller='debug_style') as m:
391 391 m.connect('debug_style_home', '',
392 392 action='index', conditions={'method': ['GET']})
393 393 m.connect('debug_style_template', '/t/{t_path}',
394 394 action='template', conditions={'method': ['GET']})
395 395
396 396 # ADMIN SETTINGS ROUTES
397 397 with rmap.submapper(path_prefix=ADMIN_PREFIX,
398 398 controller='admin/settings') as m:
399 399
400 400 # default
401 401 m.connect('admin_settings', '/settings',
402 402 action='settings_global_update',
403 403 conditions={'method': ['POST']})
404 404 m.connect('admin_settings', '/settings',
405 405 action='settings_global', conditions={'method': ['GET']})
406 406
407 407 m.connect('admin_settings_vcs', '/settings/vcs',
408 408 action='settings_vcs_update',
409 409 conditions={'method': ['POST']})
410 410 m.connect('admin_settings_vcs', '/settings/vcs',
411 411 action='settings_vcs',
412 412 conditions={'method': ['GET']})
413 413 m.connect('admin_settings_vcs', '/settings/vcs',
414 414 action='delete_svn_pattern',
415 415 conditions={'method': ['DELETE']})
416 416
417 417 m.connect('admin_settings_mapping', '/settings/mapping',
418 418 action='settings_mapping_update',
419 419 conditions={'method': ['POST']})
420 420 m.connect('admin_settings_mapping', '/settings/mapping',
421 421 action='settings_mapping', conditions={'method': ['GET']})
422 422
423 423 m.connect('admin_settings_global', '/settings/global',
424 424 action='settings_global_update',
425 425 conditions={'method': ['POST']})
426 426 m.connect('admin_settings_global', '/settings/global',
427 427 action='settings_global', conditions={'method': ['GET']})
428 428
429 429 m.connect('admin_settings_visual', '/settings/visual',
430 430 action='settings_visual_update',
431 431 conditions={'method': ['POST']})
432 432 m.connect('admin_settings_visual', '/settings/visual',
433 433 action='settings_visual', conditions={'method': ['GET']})
434 434
435 435 m.connect('admin_settings_issuetracker',
436 436 '/settings/issue-tracker', action='settings_issuetracker',
437 437 conditions={'method': ['GET']})
438 438 m.connect('admin_settings_issuetracker_save',
439 439 '/settings/issue-tracker/save',
440 440 action='settings_issuetracker_save',
441 441 conditions={'method': ['POST']})
442 442 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
443 443 action='settings_issuetracker_test',
444 444 conditions={'method': ['POST']})
445 445 m.connect('admin_issuetracker_delete',
446 446 '/settings/issue-tracker/delete',
447 447 action='settings_issuetracker_delete',
448 448 conditions={'method': ['DELETE']})
449 449
450 450 m.connect('admin_settings_email', '/settings/email',
451 451 action='settings_email_update',
452 452 conditions={'method': ['POST']})
453 453 m.connect('admin_settings_email', '/settings/email',
454 454 action='settings_email', conditions={'method': ['GET']})
455 455
456 456 m.connect('admin_settings_hooks', '/settings/hooks',
457 457 action='settings_hooks_update',
458 458 conditions={'method': ['POST', 'DELETE']})
459 459 m.connect('admin_settings_hooks', '/settings/hooks',
460 460 action='settings_hooks', conditions={'method': ['GET']})
461 461
462 462 m.connect('admin_settings_search', '/settings/search',
463 463 action='settings_search', conditions={'method': ['GET']})
464 464
465 465 m.connect('admin_settings_supervisor', '/settings/supervisor',
466 466 action='settings_supervisor', conditions={'method': ['GET']})
467 467 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
468 468 action='settings_supervisor_log', conditions={'method': ['GET']})
469 469
470 470 m.connect('admin_settings_labs', '/settings/labs',
471 471 action='settings_labs_update',
472 472 conditions={'method': ['POST']})
473 473 m.connect('admin_settings_labs', '/settings/labs',
474 474 action='settings_labs', conditions={'method': ['GET']})
475 475
476 476 # ADMIN MY ACCOUNT
477 477 with rmap.submapper(path_prefix=ADMIN_PREFIX,
478 478 controller='admin/my_account') as m:
479 479
480 480 m.connect('my_account_edit', '/my_account/edit',
481 481 action='my_account_edit', conditions={'method': ['GET']})
482 482 m.connect('my_account', '/my_account/update',
483 483 action='my_account_update', conditions={'method': ['POST']})
484 484
485 485 # NOTE(marcink): this needs to be kept for password force flag to be
486 486 # handler, remove after migration to pyramid
487 487 m.connect('my_account_password', '/my_account/password',
488 488 action='my_account_password', conditions={'method': ['GET']})
489 489
490 490 m.connect('my_account_repos', '/my_account/repos',
491 491 action='my_account_repos', conditions={'method': ['GET']})
492 492
493 493 m.connect('my_account_watched', '/my_account/watched',
494 494 action='my_account_watched', conditions={'method': ['GET']})
495 495
496 496 m.connect('my_account_pullrequests', '/my_account/pull_requests',
497 497 action='my_account_pullrequests', conditions={'method': ['GET']})
498 498
499 499 m.connect('my_account_perms', '/my_account/perms',
500 500 action='my_account_perms', conditions={'method': ['GET']})
501 501
502 502 m.connect('my_account_emails', '/my_account/emails',
503 503 action='my_account_emails', conditions={'method': ['GET']})
504 504 m.connect('my_account_emails', '/my_account/emails',
505 505 action='my_account_emails_add', conditions={'method': ['POST']})
506 506 m.connect('my_account_emails', '/my_account/emails',
507 507 action='my_account_emails_delete', conditions={'method': ['DELETE']})
508 508
509 509 m.connect('my_account_notifications', '/my_account/notifications',
510 510 action='my_notifications',
511 511 conditions={'method': ['GET']})
512 512 m.connect('my_account_notifications_toggle_visibility',
513 513 '/my_account/toggle_visibility',
514 514 action='my_notifications_toggle_visibility',
515 515 conditions={'method': ['POST']})
516 516 m.connect('my_account_notifications_test_channelstream',
517 517 '/my_account/test_channelstream',
518 518 action='my_account_notifications_test_channelstream',
519 519 conditions={'method': ['POST']})
520 520
521 521 # NOTIFICATION REST ROUTES
522 522 with rmap.submapper(path_prefix=ADMIN_PREFIX,
523 523 controller='admin/notifications') as m:
524 524 m.connect('notifications', '/notifications',
525 525 action='index', conditions={'method': ['GET']})
526 526 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
527 527 action='mark_all_read', conditions={'method': ['POST']})
528 528 m.connect('/notifications/{notification_id}',
529 529 action='update', conditions={'method': ['PUT']})
530 530 m.connect('/notifications/{notification_id}',
531 531 action='delete', conditions={'method': ['DELETE']})
532 532 m.connect('notification', '/notifications/{notification_id}',
533 533 action='show', conditions={'method': ['GET']})
534 534
535 535 # ADMIN GIST
536 536 with rmap.submapper(path_prefix=ADMIN_PREFIX,
537 537 controller='admin/gists') as m:
538 538 m.connect('gists', '/gists',
539 539 action='create', conditions={'method': ['POST']})
540 540 m.connect('gists', '/gists', jsroute=True,
541 541 action='index', conditions={'method': ['GET']})
542 542 m.connect('new_gist', '/gists/new', jsroute=True,
543 543 action='new', conditions={'method': ['GET']})
544 544
545 545 m.connect('/gists/{gist_id}',
546 546 action='delete', conditions={'method': ['DELETE']})
547 547 m.connect('edit_gist', '/gists/{gist_id}/edit',
548 548 action='edit_form', conditions={'method': ['GET']})
549 549 m.connect('edit_gist', '/gists/{gist_id}/edit',
550 550 action='edit', conditions={'method': ['POST']})
551 551 m.connect(
552 552 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
553 553 action='check_revision', conditions={'method': ['GET']})
554 554
555 555 m.connect('gist', '/gists/{gist_id}',
556 556 action='show', conditions={'method': ['GET']})
557 557 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
558 558 revision='tip',
559 559 action='show', conditions={'method': ['GET']})
560 560 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
561 561 revision='tip',
562 562 action='show', conditions={'method': ['GET']})
563 563 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
564 564 revision='tip',
565 565 action='show', conditions={'method': ['GET']},
566 566 requirements=URL_NAME_REQUIREMENTS)
567 567
568 568 # ADMIN MAIN PAGES
569 569 with rmap.submapper(path_prefix=ADMIN_PREFIX,
570 570 controller='admin/admin') as m:
571 571 m.connect('admin_home', '', action='index')
572 572 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
573 573 action='add_repo')
574 574 m.connect(
575 575 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
576 576 action='pull_requests')
577 577 m.connect(
578 578 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
579 579 action='pull_requests')
580 580 m.connect(
581 581 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
582 582 action='pull_requests')
583 583
584 584 # USER JOURNAL
585 585 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
586 586 controller='journal', action='index')
587 587 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
588 588 controller='journal', action='journal_rss')
589 589 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
590 590 controller='journal', action='journal_atom')
591 591
592 592 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
593 593 controller='journal', action='public_journal')
594 594
595 595 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
596 596 controller='journal', action='public_journal_rss')
597 597
598 598 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
599 599 controller='journal', action='public_journal_rss')
600 600
601 601 rmap.connect('public_journal_atom',
602 602 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
603 603 action='public_journal_atom')
604 604
605 605 rmap.connect('public_journal_atom_old',
606 606 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
607 607 action='public_journal_atom')
608 608
609 609 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
610 610 controller='journal', action='toggle_following', jsroute=True,
611 611 conditions={'method': ['POST']})
612 612
613 613 # FEEDS
614 614 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
615 615 controller='feed', action='rss',
616 616 conditions={'function': check_repo},
617 617 requirements=URL_NAME_REQUIREMENTS)
618 618
619 619 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
620 620 controller='feed', action='atom',
621 621 conditions={'function': check_repo},
622 622 requirements=URL_NAME_REQUIREMENTS)
623 623
624 624 #==========================================================================
625 625 # REPOSITORY ROUTES
626 626 #==========================================================================
627 627
628 628 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
629 629 controller='admin/repos', action='repo_creating',
630 630 requirements=URL_NAME_REQUIREMENTS)
631 631 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
632 632 controller='admin/repos', action='repo_check',
633 633 requirements=URL_NAME_REQUIREMENTS)
634 634
635 635 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
636 636 controller='summary', action='repo_stats',
637 637 conditions={'function': check_repo},
638 638 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
639 639
640 640 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
641 641 controller='summary', action='repo_refs_data',
642 642 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
643 643 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
644 644 controller='summary', action='repo_refs_changelog_data',
645 645 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
646 646 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
647 647 controller='summary', action='repo_default_reviewers_data',
648 648 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
649 649
650 650 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
651 651 controller='changeset', revision='tip',
652 652 conditions={'function': check_repo},
653 653 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
654 654 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
655 655 controller='changeset', revision='tip', action='changeset_children',
656 656 conditions={'function': check_repo},
657 657 requirements=URL_NAME_REQUIREMENTS)
658 658 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
659 659 controller='changeset', revision='tip', action='changeset_parents',
660 660 conditions={'function': check_repo},
661 661 requirements=URL_NAME_REQUIREMENTS)
662 662
663 663 # repo edit options
664 664 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
665 665 controller='admin/repos', action='edit_fields',
666 666 conditions={'method': ['GET'], 'function': check_repo},
667 667 requirements=URL_NAME_REQUIREMENTS)
668 668 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
669 669 controller='admin/repos', action='create_repo_field',
670 670 conditions={'method': ['PUT'], 'function': check_repo},
671 671 requirements=URL_NAME_REQUIREMENTS)
672 672 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
673 673 controller='admin/repos', action='delete_repo_field',
674 674 conditions={'method': ['DELETE'], 'function': check_repo},
675 675 requirements=URL_NAME_REQUIREMENTS)
676 676
677 677 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
678 678 controller='admin/repos', action='edit_advanced',
679 679 conditions={'method': ['GET'], 'function': check_repo},
680 680 requirements=URL_NAME_REQUIREMENTS)
681 681
682 682 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
683 683 controller='admin/repos', action='edit_advanced_locking',
684 684 conditions={'method': ['PUT'], 'function': check_repo},
685 685 requirements=URL_NAME_REQUIREMENTS)
686 686 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
687 687 controller='admin/repos', action='toggle_locking',
688 688 conditions={'method': ['GET'], 'function': check_repo},
689 689 requirements=URL_NAME_REQUIREMENTS)
690 690
691 691 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
692 692 controller='admin/repos', action='edit_advanced_journal',
693 693 conditions={'method': ['PUT'], 'function': check_repo},
694 694 requirements=URL_NAME_REQUIREMENTS)
695 695
696 696 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
697 697 controller='admin/repos', action='edit_advanced_fork',
698 698 conditions={'method': ['PUT'], 'function': check_repo},
699 699 requirements=URL_NAME_REQUIREMENTS)
700 700
701 701 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
702 702 controller='admin/repos', action='edit_remote_form',
703 703 conditions={'method': ['GET'], 'function': check_repo},
704 704 requirements=URL_NAME_REQUIREMENTS)
705 705 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
706 706 controller='admin/repos', action='edit_remote',
707 707 conditions={'method': ['PUT'], 'function': check_repo},
708 708 requirements=URL_NAME_REQUIREMENTS)
709 709
710 710 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
711 711 controller='admin/repos', action='edit_statistics_form',
712 712 conditions={'method': ['GET'], 'function': check_repo},
713 713 requirements=URL_NAME_REQUIREMENTS)
714 714 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
715 715 controller='admin/repos', action='edit_statistics',
716 716 conditions={'method': ['PUT'], 'function': check_repo},
717 717 requirements=URL_NAME_REQUIREMENTS)
718 718 rmap.connect('repo_settings_issuetracker',
719 719 '/{repo_name}/settings/issue-tracker',
720 720 controller='admin/repos', action='repo_issuetracker',
721 721 conditions={'method': ['GET'], 'function': check_repo},
722 722 requirements=URL_NAME_REQUIREMENTS)
723 723 rmap.connect('repo_issuetracker_test',
724 724 '/{repo_name}/settings/issue-tracker/test',
725 725 controller='admin/repos', action='repo_issuetracker_test',
726 726 conditions={'method': ['POST'], 'function': check_repo},
727 727 requirements=URL_NAME_REQUIREMENTS)
728 728 rmap.connect('repo_issuetracker_delete',
729 729 '/{repo_name}/settings/issue-tracker/delete',
730 730 controller='admin/repos', action='repo_issuetracker_delete',
731 731 conditions={'method': ['DELETE'], 'function': check_repo},
732 732 requirements=URL_NAME_REQUIREMENTS)
733 733 rmap.connect('repo_issuetracker_save',
734 734 '/{repo_name}/settings/issue-tracker/save',
735 735 controller='admin/repos', action='repo_issuetracker_save',
736 736 conditions={'method': ['POST'], 'function': check_repo},
737 737 requirements=URL_NAME_REQUIREMENTS)
738 738 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
739 739 controller='admin/repos', action='repo_settings_vcs_update',
740 740 conditions={'method': ['POST'], 'function': check_repo},
741 741 requirements=URL_NAME_REQUIREMENTS)
742 742 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
743 743 controller='admin/repos', action='repo_settings_vcs',
744 744 conditions={'method': ['GET'], 'function': check_repo},
745 745 requirements=URL_NAME_REQUIREMENTS)
746 746 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
747 747 controller='admin/repos', action='repo_delete_svn_pattern',
748 748 conditions={'method': ['DELETE'], 'function': check_repo},
749 749 requirements=URL_NAME_REQUIREMENTS)
750 750 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
751 751 controller='admin/repos', action='repo_settings_pullrequest',
752 752 conditions={'method': ['GET', 'POST'], 'function': check_repo},
753 753 requirements=URL_NAME_REQUIREMENTS)
754 754
755 755 # still working url for backward compat.
756 756 rmap.connect('raw_changeset_home_depraced',
757 757 '/{repo_name}/raw-changeset/{revision}',
758 758 controller='changeset', action='changeset_raw',
759 759 revision='tip', conditions={'function': check_repo},
760 760 requirements=URL_NAME_REQUIREMENTS)
761 761
762 762 # new URLs
763 763 rmap.connect('changeset_raw_home',
764 764 '/{repo_name}/changeset-diff/{revision}',
765 765 controller='changeset', action='changeset_raw',
766 766 revision='tip', conditions={'function': check_repo},
767 767 requirements=URL_NAME_REQUIREMENTS)
768 768
769 769 rmap.connect('changeset_patch_home',
770 770 '/{repo_name}/changeset-patch/{revision}',
771 771 controller='changeset', action='changeset_patch',
772 772 revision='tip', conditions={'function': check_repo},
773 773 requirements=URL_NAME_REQUIREMENTS)
774 774
775 775 rmap.connect('changeset_download_home',
776 776 '/{repo_name}/changeset-download/{revision}',
777 777 controller='changeset', action='changeset_download',
778 778 revision='tip', conditions={'function': check_repo},
779 779 requirements=URL_NAME_REQUIREMENTS)
780 780
781 781 rmap.connect('changeset_comment',
782 782 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
783 783 controller='changeset', revision='tip', action='comment',
784 784 conditions={'function': check_repo},
785 785 requirements=URL_NAME_REQUIREMENTS)
786 786
787 787 rmap.connect('changeset_comment_preview',
788 788 '/{repo_name}/changeset/comment/preview', jsroute=True,
789 789 controller='changeset', action='preview_comment',
790 790 conditions={'function': check_repo, 'method': ['POST']},
791 791 requirements=URL_NAME_REQUIREMENTS)
792 792
793 793 rmap.connect('changeset_comment_delete',
794 794 '/{repo_name}/changeset/comment/{comment_id}/delete',
795 795 controller='changeset', action='delete_comment',
796 796 conditions={'function': check_repo, 'method': ['DELETE']},
797 797 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
798 798
799 799 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
800 800 controller='changeset', action='changeset_info',
801 801 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
802 802
803 803 rmap.connect('compare_home',
804 804 '/{repo_name}/compare',
805 805 controller='compare', action='index',
806 806 conditions={'function': check_repo},
807 807 requirements=URL_NAME_REQUIREMENTS)
808 808
809 809 rmap.connect('compare_url',
810 810 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
811 811 controller='compare', action='compare',
812 812 conditions={'function': check_repo},
813 813 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
814 814
815 815 rmap.connect('pullrequest_home',
816 816 '/{repo_name}/pull-request/new', controller='pullrequests',
817 817 action='index', conditions={'function': check_repo,
818 818 'method': ['GET']},
819 819 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
820 820
821 821 rmap.connect('pullrequest',
822 822 '/{repo_name}/pull-request/new', controller='pullrequests',
823 823 action='create', conditions={'function': check_repo,
824 824 'method': ['POST']},
825 825 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
826 826
827 827 rmap.connect('pullrequest_repo_refs',
828 828 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
829 829 controller='pullrequests',
830 830 action='get_repo_refs',
831 831 conditions={'function': check_repo, 'method': ['GET']},
832 832 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
833 833
834 834 rmap.connect('pullrequest_repo_destinations',
835 835 '/{repo_name}/pull-request/repo-destinations',
836 836 controller='pullrequests',
837 837 action='get_repo_destinations',
838 838 conditions={'function': check_repo, 'method': ['GET']},
839 839 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
840 840
841 841 rmap.connect('pullrequest_show',
842 842 '/{repo_name}/pull-request/{pull_request_id}',
843 843 controller='pullrequests',
844 844 action='show', conditions={'function': check_repo,
845 845 'method': ['GET']},
846 846 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
847 847
848 848 rmap.connect('pullrequest_update',
849 849 '/{repo_name}/pull-request/{pull_request_id}',
850 850 controller='pullrequests',
851 851 action='update', conditions={'function': check_repo,
852 852 'method': ['PUT']},
853 853 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
854 854
855 855 rmap.connect('pullrequest_merge',
856 856 '/{repo_name}/pull-request/{pull_request_id}',
857 857 controller='pullrequests',
858 858 action='merge', conditions={'function': check_repo,
859 859 'method': ['POST']},
860 860 requirements=URL_NAME_REQUIREMENTS)
861 861
862 862 rmap.connect('pullrequest_delete',
863 863 '/{repo_name}/pull-request/{pull_request_id}',
864 864 controller='pullrequests',
865 865 action='delete', conditions={'function': check_repo,
866 866 'method': ['DELETE']},
867 867 requirements=URL_NAME_REQUIREMENTS)
868 868
869 869 rmap.connect('pullrequest_show_all',
870 870 '/{repo_name}/pull-request',
871 871 controller='pullrequests',
872 872 action='show_all', conditions={'function': check_repo,
873 873 'method': ['GET']},
874 874 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
875 875
876 876 rmap.connect('pullrequest_comment',
877 877 '/{repo_name}/pull-request-comment/{pull_request_id}',
878 878 controller='pullrequests',
879 879 action='comment', conditions={'function': check_repo,
880 880 'method': ['POST']},
881 881 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
882 882
883 883 rmap.connect('pullrequest_comment_delete',
884 884 '/{repo_name}/pull-request-comment/{comment_id}/delete',
885 885 controller='pullrequests', action='delete_comment',
886 886 conditions={'function': check_repo, 'method': ['DELETE']},
887 887 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
888 888
889 889 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
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)
908 896
909 897 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
910 898 controller='changelog', action='changelog_summary',
911 899 conditions={'function': check_repo},
912 900 requirements=URL_NAME_REQUIREMENTS)
913 901
914 902 rmap.connect('changelog_file_home',
915 903 '/{repo_name}/changelog/{revision}/{f_path}',
916 904 controller='changelog', f_path=None,
917 905 conditions={'function': check_repo},
918 906 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
919 907
920 908 rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
921 909 controller='changelog', action='changelog_elements',
922 910 conditions={'function': check_repo},
923 911 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
924 912
925 913 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
926 914 controller='files', revision='tip', f_path='',
927 915 conditions={'function': check_repo},
928 916 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
929 917
930 918 rmap.connect('files_home_simple_catchrev',
931 919 '/{repo_name}/files/{revision}',
932 920 controller='files', revision='tip', f_path='',
933 921 conditions={'function': check_repo},
934 922 requirements=URL_NAME_REQUIREMENTS)
935 923
936 924 rmap.connect('files_home_simple_catchall',
937 925 '/{repo_name}/files',
938 926 controller='files', revision='tip', f_path='',
939 927 conditions={'function': check_repo},
940 928 requirements=URL_NAME_REQUIREMENTS)
941 929
942 930 rmap.connect('files_history_home',
943 931 '/{repo_name}/history/{revision}/{f_path}',
944 932 controller='files', action='history', revision='tip', f_path='',
945 933 conditions={'function': check_repo},
946 934 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
947 935
948 936 rmap.connect('files_authors_home',
949 937 '/{repo_name}/authors/{revision}/{f_path}',
950 938 controller='files', action='authors', revision='tip', f_path='',
951 939 conditions={'function': check_repo},
952 940 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
953 941
954 942 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
955 943 controller='files', action='diff', f_path='',
956 944 conditions={'function': check_repo},
957 945 requirements=URL_NAME_REQUIREMENTS)
958 946
959 947 rmap.connect('files_diff_2way_home',
960 948 '/{repo_name}/diff-2way/{f_path}',
961 949 controller='files', action='diff_2way', f_path='',
962 950 conditions={'function': check_repo},
963 951 requirements=URL_NAME_REQUIREMENTS)
964 952
965 953 rmap.connect('files_rawfile_home',
966 954 '/{repo_name}/rawfile/{revision}/{f_path}',
967 955 controller='files', action='rawfile', revision='tip',
968 956 f_path='', conditions={'function': check_repo},
969 957 requirements=URL_NAME_REQUIREMENTS)
970 958
971 959 rmap.connect('files_raw_home',
972 960 '/{repo_name}/raw/{revision}/{f_path}',
973 961 controller='files', action='raw', revision='tip', f_path='',
974 962 conditions={'function': check_repo},
975 963 requirements=URL_NAME_REQUIREMENTS)
976 964
977 965 rmap.connect('files_render_home',
978 966 '/{repo_name}/render/{revision}/{f_path}',
979 967 controller='files', action='index', revision='tip', f_path='',
980 968 rendered=True, conditions={'function': check_repo},
981 969 requirements=URL_NAME_REQUIREMENTS)
982 970
983 971 rmap.connect('files_annotate_home',
984 972 '/{repo_name}/annotate/{revision}/{f_path}',
985 973 controller='files', action='index', revision='tip',
986 974 f_path='', annotate=True, conditions={'function': check_repo},
987 975 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
988 976
989 977 rmap.connect('files_annotate_previous',
990 978 '/{repo_name}/annotate-previous/{revision}/{f_path}',
991 979 controller='files', action='annotate_previous', revision='tip',
992 980 f_path='', annotate=True, conditions={'function': check_repo},
993 981 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
994 982
995 983 rmap.connect('files_edit',
996 984 '/{repo_name}/edit/{revision}/{f_path}',
997 985 controller='files', action='edit', revision='tip',
998 986 f_path='',
999 987 conditions={'function': check_repo, 'method': ['POST']},
1000 988 requirements=URL_NAME_REQUIREMENTS)
1001 989
1002 990 rmap.connect('files_edit_home',
1003 991 '/{repo_name}/edit/{revision}/{f_path}',
1004 992 controller='files', action='edit_home', revision='tip',
1005 993 f_path='', conditions={'function': check_repo},
1006 994 requirements=URL_NAME_REQUIREMENTS)
1007 995
1008 996 rmap.connect('files_add',
1009 997 '/{repo_name}/add/{revision}/{f_path}',
1010 998 controller='files', action='add', revision='tip',
1011 999 f_path='',
1012 1000 conditions={'function': check_repo, 'method': ['POST']},
1013 1001 requirements=URL_NAME_REQUIREMENTS)
1014 1002
1015 1003 rmap.connect('files_add_home',
1016 1004 '/{repo_name}/add/{revision}/{f_path}',
1017 1005 controller='files', action='add_home', revision='tip',
1018 1006 f_path='', conditions={'function': check_repo},
1019 1007 requirements=URL_NAME_REQUIREMENTS)
1020 1008
1021 1009 rmap.connect('files_delete',
1022 1010 '/{repo_name}/delete/{revision}/{f_path}',
1023 1011 controller='files', action='delete', revision='tip',
1024 1012 f_path='',
1025 1013 conditions={'function': check_repo, 'method': ['POST']},
1026 1014 requirements=URL_NAME_REQUIREMENTS)
1027 1015
1028 1016 rmap.connect('files_delete_home',
1029 1017 '/{repo_name}/delete/{revision}/{f_path}',
1030 1018 controller='files', action='delete_home', revision='tip',
1031 1019 f_path='', conditions={'function': check_repo},
1032 1020 requirements=URL_NAME_REQUIREMENTS)
1033 1021
1034 1022 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1035 1023 controller='files', action='archivefile',
1036 1024 conditions={'function': check_repo},
1037 1025 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1038 1026
1039 1027 rmap.connect('files_nodelist_home',
1040 1028 '/{repo_name}/nodelist/{revision}/{f_path}',
1041 1029 controller='files', action='nodelist',
1042 1030 conditions={'function': check_repo},
1043 1031 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1044 1032
1045 1033 rmap.connect('files_nodetree_full',
1046 1034 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1047 1035 controller='files', action='nodetree_full',
1048 1036 conditions={'function': check_repo},
1049 1037 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1050 1038
1051 1039 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1052 1040 controller='forks', action='fork_create',
1053 1041 conditions={'function': check_repo, 'method': ['POST']},
1054 1042 requirements=URL_NAME_REQUIREMENTS)
1055 1043
1056 1044 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1057 1045 controller='forks', action='fork',
1058 1046 conditions={'function': check_repo},
1059 1047 requirements=URL_NAME_REQUIREMENTS)
1060 1048
1061 1049 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1062 1050 controller='forks', action='forks',
1063 1051 conditions={'function': check_repo},
1064 1052 requirements=URL_NAME_REQUIREMENTS)
1065 1053
1066 1054 # must be here for proper group/repo catching pattern
1067 1055 _connect_with_slash(
1068 1056 rmap, 'repo_group_home', '/{group_name}',
1069 1057 controller='home', action='index_repo_group',
1070 1058 conditions={'function': check_group},
1071 1059 requirements=URL_NAME_REQUIREMENTS)
1072 1060
1073 1061 # catch all, at the end
1074 1062 _connect_with_slash(
1075 1063 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1076 1064 controller='summary', action='index',
1077 1065 conditions={'function': check_repo},
1078 1066 requirements=URL_NAME_REQUIREMENTS)
1079 1067
1080 1068 return rmap
1081 1069
1082 1070
1083 1071 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1084 1072 """
1085 1073 Connect a route with an optional trailing slash in `path`.
1086 1074 """
1087 1075 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1088 1076 mapper.connect(name, path, *args, **kwargs)
@@ -1,118 +1,121 b''
1 1
2 2 /******************************************************************************
3 3 * *
4 4 * DO NOT CHANGE THIS FILE MANUALLY *
5 5 * *
6 6 * *
7 7 * This file is automatically generated when the app starts up with *
8 8 * generate_js_files = true *
9 9 * *
10 10 * To add a route here pass jsroute=True to the route definition in the app *
11 11 * *
12 12 ******************************************************************************/
13 13 function registerRCRoutes() {
14 14 // routes registration
15 15 pyroutes.register('home', '/', []);
16 16 pyroutes.register('new_repo', '/_admin/create_repository', []);
17 17 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
18 18 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
19 19 pyroutes.register('gists', '/_admin/gists', []);
20 20 pyroutes.register('new_gist', '/_admin/gists/new', []);
21 21 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
22 22 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
23 23 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
24 24 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
25 25 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
26 26 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
27 27 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
28 28 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
29 29 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
30 30 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
31 31 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
32 32 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
33 33 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
34 34 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
35 35 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
36 36 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
37 37 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
38 38 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
39 39 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
40 40 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
41 41 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
42 42 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
43 43 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
44 44 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
45 45 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
46 46 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 47 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 48 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 49 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
50 50 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
51 51 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
52 52 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
53 53 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
54 54 pyroutes.register('favicon', '/favicon.ico', []);
55 55 pyroutes.register('robots', '/robots.txt', []);
56 56 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
57 57 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
58 58 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
59 59 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
60 60 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
61 61 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
62 62 pyroutes.register('repo_group_integrations_home', '%(repo_group_name)s/settings/integrations', ['repo_group_name']);
63 63 pyroutes.register('repo_group_integrations_list', '%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
64 64 pyroutes.register('repo_group_integrations_new', '%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
65 65 pyroutes.register('repo_group_integrations_create', '%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
66 66 pyroutes.register('repo_group_integrations_edit', '%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
67 67 pyroutes.register('repo_integrations_home', '%(repo_name)s/settings/integrations', ['repo_name']);
68 68 pyroutes.register('repo_integrations_list', '%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
69 69 pyroutes.register('repo_integrations_new', '%(repo_name)s/settings/integrations/new', ['repo_name']);
70 70 pyroutes.register('repo_integrations_create', '%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
71 71 pyroutes.register('repo_integrations_edit', '%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
72 72 pyroutes.register('ops_ping', '_admin/ops/ping', []);
73 73 pyroutes.register('admin_settings_open_source', '_admin/settings/open_source', []);
74 74 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '_admin/settings/vcs/svn_generate_cfg', []);
75 75 pyroutes.register('admin_settings_system', '_admin/settings/system', []);
76 76 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
77 77 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
78 78 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
79 79 pyroutes.register('users', '_admin/users', []);
80 80 pyroutes.register('users_data', '_admin/users_data', []);
81 81 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
82 82 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
83 83 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
84 84 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
85 85 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
86 86 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
87 87 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
88 88 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
89 89 pyroutes.register('channelstream_proxy', '/_channelstream', []);
90 90 pyroutes.register('login', '/_admin/login', []);
91 91 pyroutes.register('logout', '/_admin/logout', []);
92 92 pyroutes.register('register', '/_admin/register', []);
93 93 pyroutes.register('reset_password', '/_admin/password_reset', []);
94 94 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
95 95 pyroutes.register('user_autocomplete_data', '/_users', []);
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']);
102 105 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
103 106 pyroutes.register('repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
104 107 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
105 108 pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']);
106 109 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
107 110 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
108 111 pyroutes.register('search', '/_admin/search', []);
109 112 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
110 113 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
111 114 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
112 115 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
113 116 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
114 117 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
115 118 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
116 119 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
117 120 pyroutes.register('apiv2', '/_admin/api', []);
118 121 }
@@ -1,202 +1,202 b''
1 1 <%def name="refs_counters(branches, closed_branches, tags, bookmarks)">
2 2 <span class="branchtag tag">
3 <a href="${h.url('branches_home',repo_name=c.repo_name)}" class="childs">
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.url('branches_home',repo_name=c.repo_name)}" class="childs">
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.url('tags_home',repo_name=c.repo_name)}" class="childs">
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.url('bookmarks_home',repo_name=c.repo_name)}" class="childs">
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>
28 28 %endif
29 29 </%def>
30 30
31 31 <%def name="summary_detail(breadcrumbs_links, show_downloads=True)">
32 32 <% summary = lambda n:{False:'summary-short'}.get(n) %>
33 33
34 34 <div id="summary-menu-stats" class="summary-detail">
35 35 <div class="summary-detail-header">
36 36 <div class="breadcrumbs files_location">
37 37 <h4>
38 38 ${breadcrumbs_links}
39 39 </h4>
40 40 </div>
41 41 <div id="summary_details_expand" class="btn-collapse" data-toggle="summary-details">
42 42 ${_('Show More')}
43 43 </div>
44 44 </div>
45 45
46 46 <div class="fieldset">
47 47 %if h.is_svn_without_proxy(c.rhodecode_db_repo):
48 48 <div class="left-label disabled">
49 49 ${_('Read-only url')}:
50 50 </div>
51 51 <div class="right-content disabled">
52 52 <input type="text" class="input-monospace" id="clone_url" disabled value="${c.clone_repo_url}"/>
53 53 <input type="text" class="input-monospace" id="clone_url_id" disabled value="${c.clone_repo_url_id}" style="display: none;"/>
54 54 <a id="clone_by_name" class="clone" style="display: none;">${_('Show by Name')}</a>
55 55 <a id="clone_by_id" class="clone">${_('Show by ID')}</a>
56 56 <p class="help-block">${_('SVN Protocol is disabled. To enable it, see the')} <a href="${h.route_url('enterprise_svn_setup')}" target="_blank">${_('documentation here')}</a>.</p>
57 57 </div>
58 58 %else:
59 59 <div class="left-label">
60 60 ${_('Clone url')}:
61 61 </div>
62 62 <div class="right-content">
63 63 <input type="text" class="input-monospace" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/>
64 64 <input type="text" class="input-monospace" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}" style="display: none;"/>
65 65 <a id="clone_by_name" class="clone" style="display: none;">${_('Show by Name')}</a>
66 66 <a id="clone_by_id" class="clone">${_('Show by ID')}</a>
67 67 </div>
68 68 %endif
69 69 </div>
70 70
71 71 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
72 72 <div class="left-label">
73 73 ${_('Description')}:
74 74 </div>
75 75 <div class="right-content">
76 76 %if c.visual.stylify_metatags:
77 77 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.escaped_stylize(c.rhodecode_db_repo.description))}</div>
78 78 %else:
79 79 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.html_escape(c.rhodecode_db_repo.description))}</div>
80 80 %endif
81 81 </div>
82 82 </div>
83 83
84 84 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
85 85 <div class="left-label">
86 86 ${_('Information')}:
87 87 </div>
88 88 <div class="right-content">
89 89
90 90 <div class="repo-size">
91 91 <% commit_rev = c.rhodecode_db_repo.changeset_cache.get('revision') %>
92 92
93 93 ## commits
94 94 % if commit_rev == -1:
95 95 ${ungettext('%(num)s Commit', '%(num)s Commits', 0) % {'num': 0}},
96 96 % else:
97 97 <a href="${h.url('changelog_home', repo_name=c.repo_name)}">
98 98 ${ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}}</a>,
99 99 % endif
100 100
101 101 ## forks
102 102 <a title="${_('Number of Repository Forks')}" href="${h.url('repo_forks_home', repo_name=c.repo_name)}">
103 103 ${c.repository_forks} ${ungettext('Fork', 'Forks', c.repository_forks)}</a>,
104 104
105 105 ## repo size
106 106 % if commit_rev == -1:
107 107 <span class="stats-bullet">0 B</span>
108 108 % else:
109 109 <span class="stats-bullet" id="repo_size_container">
110 110 ${_('Calculating Repository Size...')}
111 111 </span>
112 112 % endif
113 113 </div>
114 114
115 115 <div class="commit-info">
116 116 <div class="tags">
117 117 % if c.rhodecode_repo:
118 118 ${refs_counters(
119 119 c.rhodecode_repo.branches,
120 120 c.rhodecode_repo.branches_closed,
121 121 c.rhodecode_repo.tags,
122 122 c.rhodecode_repo.bookmarks)}
123 123 % else:
124 124 ## missing requirements can make c.rhodecode_repo None
125 125 ${refs_counters([], [], [], [])}
126 126 % endif
127 127 </div>
128 128 </div>
129 129
130 130 </div>
131 131 </div>
132 132
133 133 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
134 134 <div class="left-label">
135 135 ${_('Statistics')}:
136 136 </div>
137 137 <div class="right-content">
138 138 <div class="input ${summary(c.show_stats)} statistics">
139 139 % if c.show_stats:
140 140 <div id="lang_stats" class="enabled">
141 141 ${_('Calculating Code Statistics...')}
142 142 </div>
143 143 % else:
144 144 <span class="disabled">
145 145 ${_('Statistics are disabled for this repository')}
146 146 </span>
147 147 % if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
148 148 , ${h.link_to(_('enable statistics'),h.route_path('edit_repo',repo_name=c.repo_name, anchor='repo_enable_statistics'))}
149 149 % endif
150 150 % endif
151 151 </div>
152 152
153 153 </div>
154 154 </div>
155 155
156 156 % if show_downloads:
157 157 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
158 158 <div class="left-label">
159 159 ${_('Downloads')}:
160 160 </div>
161 161 <div class="right-content">
162 162 <div class="input ${summary(c.show_stats)} downloads">
163 163 % if c.rhodecode_repo and len(c.rhodecode_repo.revisions) == 0:
164 164 <span class="disabled">
165 165 ${_('There are no downloads yet')}
166 166 </span>
167 167 % elif not c.enable_downloads:
168 168 <span class="disabled">
169 169 ${_('Downloads are disabled for this repository')}
170 170 </span>
171 171 % if h.HasPermissionAll('hg.admin')('enable downloads on from summary'):
172 172 , ${h.link_to(_('enable downloads'),h.route_path('edit_repo',repo_name=c.repo_name, anchor='repo_enable_downloads'))}
173 173 % endif
174 174 % else:
175 175 <span class="enabled">
176 176 <a id="archive_link" class="btn btn-small" href="${h.url('files_archive_home',repo_name=c.rhodecode_db_repo.repo_name,fname='tip.zip')}">
177 177 <i class="icon-archive"></i> tip.zip
178 178 ## replaced by some JS on select
179 179 </a>
180 180 </span>
181 181 ${h.hidden('download_options')}
182 182 % endif
183 183 </div>
184 184 </div>
185 185 </div>
186 186 % endif
187 187
188 188 </div><!--end summary-detail-->
189 189 </%def>
190 190
191 191 <%def name="summary_stats(gravatar_function)">
192 192 <div class="sidebar-right">
193 193 <div class="summary-detail-header">
194 194 <h4 class="item">
195 195 ${_('Owner')}
196 196 </h4>
197 197 </div>
198 198 <div class="sidebar-right-content">
199 199 ${gravatar_function(c.rhodecode_db_repo.user.email, 16)}
200 200 </div>
201 201 </div><!--end sidebar-right-->
202 202 </%def>
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