##// END OF EJS Templates
journal: ported controller to pyramid code
marcink -
r1933:b6b05465 default
parent child Browse files
Show More
@@ -0,0 +1,53 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-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
22 from rhodecode.apps._base import ADMIN_PREFIX
23
24
25 def admin_routes(config):
26
27 config.add_route(
28 name='journal', pattern='/journal')
29 config.add_route(
30 name='journal_rss', pattern='/journal/rss')
31 config.add_route(
32 name='journal_atom', pattern='/journal/atom')
33
34 config.add_route(
35 name='journal_public', pattern='/public_journal')
36 config.add_route(
37 name='journal_public_atom', pattern='/public_journal/atom')
38 config.add_route(
39 name='journal_public_atom_old', pattern='/public_journal_atom')
40
41 config.add_route(
42 name='journal_public_rss', pattern='/public_journal/rss')
43 config.add_route(
44 name='journal_public_rss_old', pattern='/public_journal_rss')
45
46 config.add_route(
47 name='toggle_following', pattern='/toggle_following')
48
49
50 def includeme(config):
51 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
52 # Scan module for configuration decorators.
53 config.scan() No newline at end of file
@@ -0,0 +1,19 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-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/
@@ -0,0 +1,377 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-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
22 import logging
23 import itertools
24
25 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
26
27 from pyramid.view import view_config
28 from pyramid.httpexceptions import HTTPBadRequest
29 from pyramid.response import Response
30 from pyramid.renderers import render
31
32 from rhodecode.apps._base import BaseAppView
33 from rhodecode.model.db import (
34 or_, joinedload, UserLog, UserFollowing, User, UserApiKeys)
35 from rhodecode.model.meta import Session
36 import rhodecode.lib.helpers as h
37 from rhodecode.lib.helpers import Page
38 from rhodecode.lib.user_log_filter import user_log_filter
39 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
40 from rhodecode.lib.utils2 import safe_int, AttributeDict
41 from rhodecode.model.scm import ScmModel
42
43 log = logging.getLogger(__name__)
44
45
46 class JournalView(BaseAppView):
47
48 def load_default_context(self):
49 c = self._get_local_tmpl_context(include_app_defaults=True)
50 self._register_global_c(c)
51 self._load_defaults(c.rhodecode_name)
52
53 # TODO(marcink): what is this, why we need a global register ?
54 c.search_term = self.request.GET.get('filter') or ''
55 return c
56
57 def _get_config(self, rhodecode_name):
58 import rhodecode
59 config = rhodecode.CONFIG
60
61 return {
62 'language': 'en-us',
63 'feed_ttl': '5', # TTL of feed,
64 'feed_items_per_page':
65 safe_int(config.get('rss_items_per_page', 20)),
66 'rhodecode_name': rhodecode_name
67 }
68
69 def _load_defaults(self, rhodecode_name):
70 config = self._get_config(rhodecode_name)
71 # common values for feeds
72 self.language = config["language"]
73 self.ttl = config["feed_ttl"]
74 self.feed_items_per_page = config['feed_items_per_page']
75 self.rhodecode_name = config['rhodecode_name']
76
77 def _get_daily_aggregate(self, journal):
78 groups = []
79 for k, g in itertools.groupby(journal, lambda x: x.action_as_day):
80 user_group = []
81 # groupby username if it's a present value, else
82 # fallback to journal username
83 for _, g2 in itertools.groupby(
84 list(g), lambda x: x.user.username if x.user else x.username):
85 l = list(g2)
86 user_group.append((l[0].user, l))
87
88 groups.append((k, user_group,))
89
90 return groups
91
92 def _get_journal_data(self, following_repos, search_term):
93 repo_ids = [x.follows_repository.repo_id for x in following_repos
94 if x.follows_repository is not None]
95 user_ids = [x.follows_user.user_id for x in following_repos
96 if x.follows_user is not None]
97
98 filtering_criterion = None
99
100 if repo_ids and user_ids:
101 filtering_criterion = or_(UserLog.repository_id.in_(repo_ids),
102 UserLog.user_id.in_(user_ids))
103 if repo_ids and not user_ids:
104 filtering_criterion = UserLog.repository_id.in_(repo_ids)
105 if not repo_ids and user_ids:
106 filtering_criterion = UserLog.user_id.in_(user_ids)
107 if filtering_criterion is not None:
108 journal = Session().query(UserLog)\
109 .options(joinedload(UserLog.user))\
110 .options(joinedload(UserLog.repository))
111 # filter
112 try:
113 journal = user_log_filter(journal, search_term)
114 except Exception:
115 # we want this to crash for now
116 raise
117 journal = journal.filter(filtering_criterion)\
118 .order_by(UserLog.action_date.desc())
119 else:
120 journal = []
121
122 return journal
123
124 def _atom_feed(self, repos, search_term, public=True):
125 _ = self.request.translate
126 journal = self._get_journal_data(repos, search_term)
127 if public:
128 _link = h.route_url('journal_public_atom')
129 _desc = '%s %s %s' % (self.rhodecode_name, _('public journal'),
130 'atom feed')
131 else:
132 _link = h.route_url('journal_atom')
133 _desc = '%s %s %s' % (self.rhodecode_name, _('journal'), 'atom feed')
134
135 feed = Atom1Feed(
136 title=_desc, link=_link, description=_desc,
137 language=self.language, ttl=self.ttl)
138
139 for entry in journal[:self.feed_items_per_page]:
140 user = entry.user
141 if user is None:
142 # fix deleted users
143 user = AttributeDict({'short_contact': entry.username,
144 'email': '',
145 'full_contact': ''})
146 action, action_extra, ico = h.action_parser(entry, feed=True)
147 title = "%s - %s %s" % (user.short_contact, action(),
148 entry.repository.repo_name)
149 desc = action_extra()
150 _url = h.route_url('home')
151 if entry.repository is not None:
152 _url = h.route_url('repo_changelog',
153 repo_name=entry.repository.repo_name)
154
155 feed.add_item(title=title,
156 pubdate=entry.action_date,
157 link=_url,
158 author_email=user.email,
159 author_name=user.full_contact,
160 description=desc)
161
162 response = Response(feed.writeString('utf-8'))
163 response.content_type = feed.mime_type
164 return response
165
166 def _rss_feed(self, repos, search_term, public=True):
167 _ = self.request.translate
168 journal = self._get_journal_data(repos, search_term)
169 if public:
170 _link = h.route_url('journal_public_atom')
171 _desc = '%s %s %s' % (
172 self.rhodecode_name, _('public journal'), 'rss feed')
173 else:
174 _link = h.route_url('journal_atom')
175 _desc = '%s %s %s' % (
176 self.rhodecode_name, _('journal'), 'rss feed')
177
178 feed = Rss201rev2Feed(
179 title=_desc, link=_link, description=_desc,
180 language=self.language, ttl=self.ttl)
181
182 for entry in journal[:self.feed_items_per_page]:
183 user = entry.user
184 if user is None:
185 # fix deleted users
186 user = AttributeDict({'short_contact': entry.username,
187 'email': '',
188 'full_contact': ''})
189 action, action_extra, ico = h.action_parser(entry, feed=True)
190 title = "%s - %s %s" % (user.short_contact, action(),
191 entry.repository.repo_name)
192 desc = action_extra()
193 _url = h.route_url('home')
194 if entry.repository is not None:
195 _url = h.route_url('repo_changelog',
196 repo_name=entry.repository.repo_name)
197
198 feed.add_item(title=title,
199 pubdate=entry.action_date,
200 link=_url,
201 author_email=user.email,
202 author_name=user.full_contact,
203 description=desc)
204
205 response = Response(feed.writeString('utf-8'))
206 response.content_type = feed.mime_type
207 return response
208
209 @LoginRequired()
210 @NotAnonymous()
211 @view_config(
212 route_name='journal', request_method='GET',
213 renderer=None)
214 def journal(self):
215 c = self.load_default_context()
216
217 p = safe_int(self.request.GET.get('page', 1), 1)
218 c.user = User.get(self._rhodecode_user.user_id)
219 following = Session().query(UserFollowing)\
220 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
221 .options(joinedload(UserFollowing.follows_repository))\
222 .all()
223
224 journal = self._get_journal_data(following, c.search_term)
225
226 def url_generator(**kw):
227 query_params = {
228 'filter': c.search_term
229 }
230 query_params.update(kw)
231 return self.request.current_route_path(_query=query_params)
232
233 c.journal_pager = Page(
234 journal, page=p, items_per_page=20, url=url_generator)
235 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
236
237 c.journal_data = render(
238 'rhodecode:templates/journal/journal_data.mako',
239 self._get_template_context(c), self.request)
240
241 if self.request.is_xhr:
242 return Response(c.journal_data)
243
244 html = render(
245 'rhodecode:templates/journal/journal.mako',
246 self._get_template_context(c), self.request)
247 return Response(html)
248
249 @LoginRequired(auth_token_access=[UserApiKeys.ROLE_FEED])
250 @NotAnonymous()
251 @view_config(
252 route_name='journal_atom', request_method='GET',
253 renderer=None)
254 def journal_atom(self):
255 """
256 Produce an atom-1.0 feed via feedgenerator module
257 """
258 c = self.load_default_context()
259 following_repos = Session().query(UserFollowing)\
260 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
261 .options(joinedload(UserFollowing.follows_repository))\
262 .all()
263 return self._atom_feed(following_repos, c.search_term, public=False)
264
265 @LoginRequired(auth_token_access=[UserApiKeys.ROLE_FEED])
266 @NotAnonymous()
267 @view_config(
268 route_name='journal_rss', request_method='GET',
269 renderer=None)
270 def journal_rss(self):
271 """
272 Produce an rss feed via feedgenerator module
273 """
274 c = self.load_default_context()
275 following_repos = Session().query(UserFollowing)\
276 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
277 .options(joinedload(UserFollowing.follows_repository))\
278 .all()
279 return self._rss_feed(following_repos, c.search_term, public=False)
280
281 @LoginRequired()
282 @NotAnonymous()
283 @CSRFRequired()
284 @view_config(
285 route_name='toggle_following', request_method='POST',
286 renderer='json_ext')
287 def toggle_following(self):
288 user_id = self.request.POST.get('follows_user_id')
289 if user_id:
290 try:
291 ScmModel().toggle_following_user(
292 user_id, self._rhodecode_user.user_id)
293 Session().commit()
294 return 'ok'
295 except Exception:
296 raise HTTPBadRequest()
297
298 repo_id = self.request.POST.get('follows_repo_id')
299 if repo_id:
300 try:
301 ScmModel().toggle_following_repo(
302 repo_id, self._rhodecode_user.user_id)
303 Session().commit()
304 return 'ok'
305 except Exception:
306 raise HTTPBadRequest()
307
308 raise HTTPBadRequest()
309
310 @LoginRequired()
311 @view_config(
312 route_name='journal_public', request_method='GET',
313 renderer=None)
314 def journal_public(self):
315 c = self.load_default_context()
316 # Return a rendered template
317 p = safe_int(self.request.GET.get('page', 1), 1)
318
319 c.following = Session().query(UserFollowing)\
320 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
321 .options(joinedload(UserFollowing.follows_repository))\
322 .all()
323
324 journal = self._get_journal_data(c.following, c.search_term)
325
326 def url_generator(**kw):
327 query_params = {}
328 query_params.update(kw)
329 return self.request.current_route_path(_query=query_params)
330
331 c.journal_pager = Page(
332 journal, page=p, items_per_page=20, url=url_generator)
333 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
334
335 c.journal_data = render(
336 'rhodecode:templates/journal/journal_data.mako',
337 self._get_template_context(c), self.request)
338
339 if self.request.is_xhr:
340 return Response(c.journal_data)
341
342 html = render(
343 'rhodecode:templates/journal/public_journal.mako',
344 self._get_template_context(c), self.request)
345 return Response(html)
346
347 @LoginRequired(auth_token_access=[UserApiKeys.ROLE_FEED])
348 @view_config(
349 route_name='journal_public_atom', request_method='GET',
350 renderer=None)
351 def journal_public_atom(self):
352 """
353 Produce an atom-1.0 feed via feedgenerator module
354 """
355 c = self.load_default_context()
356 following_repos = Session().query(UserFollowing)\
357 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
358 .options(joinedload(UserFollowing.follows_repository))\
359 .all()
360
361 return self._atom_feed(following_repos, c.search_term)
362
363 @LoginRequired(auth_token_access=[UserApiKeys.ROLE_FEED])
364 @view_config(
365 route_name='journal_public_rss', request_method='GET',
366 renderer=None)
367 def journal_public_rss(self):
368 """
369 Produce an rss2 feed via feedgenerator module
370 """
371 c = self.load_default_context()
372 following_repos = Session().query(UserFollowing)\
373 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
374 .options(joinedload(UserFollowing.follows_repository))\
375 .all()
376
377 return self._rss_feed(following_repos, c.search_term)
@@ -1,64 +1,106 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import datetime
21 import datetime
22 from rhodecode.tests import TestController, url
22
23 import pytest
24
25 from rhodecode.apps._base import ADMIN_PREFIX
26 from rhodecode.tests import TestController
23 from rhodecode.model.db import UserFollowing, Repository
27 from rhodecode.model.db import UserFollowing, Repository
24
28
25
29
26 class TestJournalController(TestController):
30 def route_path(name, params=None, **kwargs):
31 import urllib
27
32
28 def test_index(self):
33 base_url = {
34 'journal': ADMIN_PREFIX + '/journal',
35 'journal_rss': ADMIN_PREFIX + '/journal/rss',
36 'journal_atom': ADMIN_PREFIX + '/journal/atom',
37 'journal_public': ADMIN_PREFIX + '/public_journal',
38 'journal_public_atom': ADMIN_PREFIX + '/public_journal/atom',
39 'journal_public_atom_old': ADMIN_PREFIX + '/public_journal_atom',
40 'journal_public_rss': ADMIN_PREFIX + '/public_journal/rss',
41 'journal_public_rss_old': ADMIN_PREFIX + '/public_journal_rss',
42 'toggle_following': ADMIN_PREFIX + '/toggle_following',
43 }[name].format(**kwargs)
44
45 if params:
46 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
47 return base_url
48
49
50 class TestJournalViews(TestController):
51
52 def test_journal(self):
29 self.log_user()
53 self.log_user()
30 response = self.app.get(url(controller='journal', action='index'))
54 response = self.app.get(route_path('journal'))
31 response.mustcontain(
55 # response.mustcontain(
32 """<div class="journal_day">%s</div>""" % datetime.date.today())
56 # """<div class="journal_day">%s</div>""" % datetime.date.today())
57
58 @pytest.mark.parametrize("feed_type, content_type", [
59 ('rss', "application/rss+xml"),
60 ('atom', "application/atom+xml")
61 ])
62 def test_journal_feed(self, feed_type, content_type):
63 self.log_user()
64 response = self.app.get(
65 route_path(
66 'journal_{}'.format(feed_type)),
67 status=200)
68
69 assert response.content_type == content_type
33
70
34 def test_toggle_following_repository(self, backend):
71 def test_toggle_following_repository(self, backend):
35 user = self.log_user()
72 user = self.log_user()
36 repo = Repository.get_by_repo_name(backend.repo_name)
73 repo = Repository.get_by_repo_name(backend.repo_name)
37 repo_id = repo.repo_id
74 repo_id = repo.repo_id
38 self.app.post(url('toggle_following'), {'follows_repo_id': repo_id,
75 self.app.post(
39 'csrf_token': self.csrf_token})
76 route_path('toggle_following'), {'follows_repo_id': repo_id,
77 'csrf_token': self.csrf_token})
40
78
41 followings = UserFollowing.query()\
79 followings = UserFollowing.query()\
42 .filter(UserFollowing.user_id == user['user_id'])\
80 .filter(UserFollowing.user_id == user['user_id'])\
43 .filter(UserFollowing.follows_repo_id == repo_id).all()
81 .filter(UserFollowing.follows_repo_id == repo_id).all()
44
82
45 assert len(followings) == 0
83 assert len(followings) == 0
46
84
47 self.app.post(url('toggle_following'), {'follows_repo_id': repo_id,
85 self.app.post(
48 'csrf_token': self.csrf_token})
86 route_path('toggle_following'), {'follows_repo_id': repo_id,
87 'csrf_token': self.csrf_token})
49
88
50 followings = UserFollowing.query()\
89 followings = UserFollowing.query()\
51 .filter(UserFollowing.user_id == user['user_id'])\
90 .filter(UserFollowing.user_id == user['user_id'])\
52 .filter(UserFollowing.follows_repo_id == repo_id).all()
91 .filter(UserFollowing.follows_repo_id == repo_id).all()
53
92
54 assert len(followings) == 1
93 assert len(followings) == 1
55
94
56 def test_public_journal_atom(self):
95 @pytest.mark.parametrize("feed_type, content_type", [
96 ('rss', "application/rss+xml"),
97 ('atom', "application/atom+xml")
98 ])
99 def test_public_journal_feed(self, feed_type, content_type):
57 self.log_user()
100 self.log_user()
58 response = self.app.get(url(controller='journal',
101 response = self.app.get(
59 action='public_journal_atom'),)
102 route_path(
103 'journal_public_{}'.format(feed_type)),
104 status=200)
60
105
61 def test_public_journal_rss(self):
106 assert response.content_type == content_type
62 self.log_user()
63 response = self.app.get(url(controller='journal',
64 action='public_journal_rss'),)
@@ -1,528 +1,529 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Pylons middleware initialization
22 Pylons middleware initialization
23 """
23 """
24 import logging
24 import logging
25 import traceback
25 import traceback
26 from collections import OrderedDict
26 from collections import OrderedDict
27
27
28 from paste.registry import RegistryManager
28 from paste.registry import RegistryManager
29 from paste.gzipper import make_gzip_middleware
29 from paste.gzipper import make_gzip_middleware
30 from pylons.wsgiapp import PylonsApp
30 from pylons.wsgiapp import PylonsApp
31 from pyramid.authorization import ACLAuthorizationPolicy
31 from pyramid.authorization import ACLAuthorizationPolicy
32 from pyramid.config import Configurator
32 from pyramid.config import Configurator
33 from pyramid.settings import asbool, aslist
33 from pyramid.settings import asbool, aslist
34 from pyramid.wsgi import wsgiapp
34 from pyramid.wsgi import wsgiapp
35 from pyramid.httpexceptions import (
35 from pyramid.httpexceptions import (
36 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
36 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
37 from pyramid.events import ApplicationCreated
37 from pyramid.events import ApplicationCreated
38 from pyramid.renderers import render_to_response
38 from pyramid.renderers import render_to_response
39 from routes.middleware import RoutesMiddleware
39 from routes.middleware import RoutesMiddleware
40 import rhodecode
40 import rhodecode
41
41
42 from rhodecode.model import meta
42 from rhodecode.model import meta
43 from rhodecode.config import patches
43 from rhodecode.config import patches
44 from rhodecode.config.routing import STATIC_FILE_PREFIX
44 from rhodecode.config.routing import STATIC_FILE_PREFIX
45 from rhodecode.config.environment import (
45 from rhodecode.config.environment import (
46 load_environment, load_pyramid_environment)
46 load_environment, load_pyramid_environment)
47
47
48 from rhodecode.lib.vcs import VCSCommunicationError
48 from rhodecode.lib.vcs import VCSCommunicationError
49 from rhodecode.lib.exceptions import VCSServerUnavailable
49 from rhodecode.lib.exceptions import VCSServerUnavailable
50 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
50 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
51 from rhodecode.lib.middleware.error_handling import (
51 from rhodecode.lib.middleware.error_handling import (
52 PylonsErrorHandlingMiddleware)
52 PylonsErrorHandlingMiddleware)
53 from rhodecode.lib.middleware.https_fixup import HttpsFixup
53 from rhodecode.lib.middleware.https_fixup import HttpsFixup
54 from rhodecode.lib.middleware.vcs import VCSMiddleware
54 from rhodecode.lib.middleware.vcs import VCSMiddleware
55 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
55 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
56 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
56 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
57 from rhodecode.subscribers import (
57 from rhodecode.subscribers import (
58 scan_repositories_if_enabled, write_js_routes_if_enabled,
58 scan_repositories_if_enabled, write_js_routes_if_enabled,
59 write_metadata_if_needed)
59 write_metadata_if_needed)
60
60
61
61
62 log = logging.getLogger(__name__)
62 log = logging.getLogger(__name__)
63
63
64
64
65 # this is used to avoid avoid the route lookup overhead in routesmiddleware
65 # this is used to avoid avoid the route lookup overhead in routesmiddleware
66 # for certain routes which won't go to pylons to - eg. static files, debugger
66 # for certain routes which won't go to pylons to - eg. static files, debugger
67 # it is only needed for the pylons migration and can be removed once complete
67 # it is only needed for the pylons migration and can be removed once complete
68 class SkippableRoutesMiddleware(RoutesMiddleware):
68 class SkippableRoutesMiddleware(RoutesMiddleware):
69 """ Routes middleware that allows you to skip prefixes """
69 """ Routes middleware that allows you to skip prefixes """
70
70
71 def __init__(self, *args, **kw):
71 def __init__(self, *args, **kw):
72 self.skip_prefixes = kw.pop('skip_prefixes', [])
72 self.skip_prefixes = kw.pop('skip_prefixes', [])
73 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
73 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
74
74
75 def __call__(self, environ, start_response):
75 def __call__(self, environ, start_response):
76 for prefix in self.skip_prefixes:
76 for prefix in self.skip_prefixes:
77 if environ['PATH_INFO'].startswith(prefix):
77 if environ['PATH_INFO'].startswith(prefix):
78 # added to avoid the case when a missing /_static route falls
78 # added to avoid the case when a missing /_static route falls
79 # through to pylons and causes an exception as pylons is
79 # through to pylons and causes an exception as pylons is
80 # expecting wsgiorg.routingargs to be set in the environ
80 # expecting wsgiorg.routingargs to be set in the environ
81 # by RoutesMiddleware.
81 # by RoutesMiddleware.
82 if 'wsgiorg.routing_args' not in environ:
82 if 'wsgiorg.routing_args' not in environ:
83 environ['wsgiorg.routing_args'] = (None, {})
83 environ['wsgiorg.routing_args'] = (None, {})
84 return self.app(environ, start_response)
84 return self.app(environ, start_response)
85
85
86 return super(SkippableRoutesMiddleware, self).__call__(
86 return super(SkippableRoutesMiddleware, self).__call__(
87 environ, start_response)
87 environ, start_response)
88
88
89
89
90 def make_app(global_conf, static_files=True, **app_conf):
90 def make_app(global_conf, static_files=True, **app_conf):
91 """Create a Pylons WSGI application and return it
91 """Create a Pylons WSGI application and return it
92
92
93 ``global_conf``
93 ``global_conf``
94 The inherited configuration for this application. Normally from
94 The inherited configuration for this application. Normally from
95 the [DEFAULT] section of the Paste ini file.
95 the [DEFAULT] section of the Paste ini file.
96
96
97 ``app_conf``
97 ``app_conf``
98 The application's local configuration. Normally specified in
98 The application's local configuration. Normally specified in
99 the [app:<name>] section of the Paste ini file (where <name>
99 the [app:<name>] section of the Paste ini file (where <name>
100 defaults to main).
100 defaults to main).
101
101
102 """
102 """
103 # Apply compatibility patches
103 # Apply compatibility patches
104 patches.kombu_1_5_1_python_2_7_11()
104 patches.kombu_1_5_1_python_2_7_11()
105 patches.inspect_getargspec()
105 patches.inspect_getargspec()
106
106
107 # Configure the Pylons environment
107 # Configure the Pylons environment
108 config = load_environment(global_conf, app_conf)
108 config = load_environment(global_conf, app_conf)
109
109
110 # The Pylons WSGI app
110 # The Pylons WSGI app
111 app = PylonsApp(config=config)
111 app = PylonsApp(config=config)
112
112
113 # Establish the Registry for this application
113 # Establish the Registry for this application
114 app = RegistryManager(app)
114 app = RegistryManager(app)
115
115
116 app.config = config
116 app.config = config
117
117
118 return app
118 return app
119
119
120
120
121 def make_pyramid_app(global_config, **settings):
121 def make_pyramid_app(global_config, **settings):
122 """
122 """
123 Constructs the WSGI application based on Pyramid and wraps the Pylons based
123 Constructs the WSGI application based on Pyramid and wraps the Pylons based
124 application.
124 application.
125
125
126 Specials:
126 Specials:
127
127
128 * We migrate from Pylons to Pyramid. While doing this, we keep both
128 * We migrate from Pylons to Pyramid. While doing this, we keep both
129 frameworks functional. This involves moving some WSGI middlewares around
129 frameworks functional. This involves moving some WSGI middlewares around
130 and providing access to some data internals, so that the old code is
130 and providing access to some data internals, so that the old code is
131 still functional.
131 still functional.
132
132
133 * The application can also be integrated like a plugin via the call to
133 * The application can also be integrated like a plugin via the call to
134 `includeme`. This is accompanied with the other utility functions which
134 `includeme`. This is accompanied with the other utility functions which
135 are called. Changing this should be done with great care to not break
135 are called. Changing this should be done with great care to not break
136 cases when these fragments are assembled from another place.
136 cases when these fragments are assembled from another place.
137
137
138 """
138 """
139 # The edition string should be available in pylons too, so we add it here
139 # The edition string should be available in pylons too, so we add it here
140 # before copying the settings.
140 # before copying the settings.
141 settings.setdefault('rhodecode.edition', 'Community Edition')
141 settings.setdefault('rhodecode.edition', 'Community Edition')
142
142
143 # As long as our Pylons application does expect "unprepared" settings, make
143 # As long as our Pylons application does expect "unprepared" settings, make
144 # sure that we keep an unmodified copy. This avoids unintentional change of
144 # sure that we keep an unmodified copy. This avoids unintentional change of
145 # behavior in the old application.
145 # behavior in the old application.
146 settings_pylons = settings.copy()
146 settings_pylons = settings.copy()
147
147
148 sanitize_settings_and_apply_defaults(settings)
148 sanitize_settings_and_apply_defaults(settings)
149 config = Configurator(settings=settings)
149 config = Configurator(settings=settings)
150 add_pylons_compat_data(config.registry, global_config, settings_pylons)
150 add_pylons_compat_data(config.registry, global_config, settings_pylons)
151
151
152 load_pyramid_environment(global_config, settings)
152 load_pyramid_environment(global_config, settings)
153
153
154 includeme_first(config)
154 includeme_first(config)
155 includeme(config)
155 includeme(config)
156
156
157 pyramid_app = config.make_wsgi_app()
157 pyramid_app = config.make_wsgi_app()
158 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
158 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
159 pyramid_app.config = config
159 pyramid_app.config = config
160
160
161 # creating the app uses a connection - return it after we are done
161 # creating the app uses a connection - return it after we are done
162 meta.Session.remove()
162 meta.Session.remove()
163
163
164 return pyramid_app
164 return pyramid_app
165
165
166
166
167 def make_not_found_view(config):
167 def make_not_found_view(config):
168 """
168 """
169 This creates the view which should be registered as not-found-view to
169 This creates the view which should be registered as not-found-view to
170 pyramid. Basically it contains of the old pylons app, converted to a view.
170 pyramid. Basically it contains of the old pylons app, converted to a view.
171 Additionally it is wrapped by some other middlewares.
171 Additionally it is wrapped by some other middlewares.
172 """
172 """
173 settings = config.registry.settings
173 settings = config.registry.settings
174 vcs_server_enabled = settings['vcs.server.enable']
174 vcs_server_enabled = settings['vcs.server.enable']
175
175
176 # Make pylons app from unprepared settings.
176 # Make pylons app from unprepared settings.
177 pylons_app = make_app(
177 pylons_app = make_app(
178 config.registry._pylons_compat_global_config,
178 config.registry._pylons_compat_global_config,
179 **config.registry._pylons_compat_settings)
179 **config.registry._pylons_compat_settings)
180 config.registry._pylons_compat_config = pylons_app.config
180 config.registry._pylons_compat_config = pylons_app.config
181
181
182 # Appenlight monitoring.
182 # Appenlight monitoring.
183 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
183 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
184 pylons_app, settings)
184 pylons_app, settings)
185
185
186 # The pylons app is executed inside of the pyramid 404 exception handler.
186 # The pylons app is executed inside of the pyramid 404 exception handler.
187 # Exceptions which are raised inside of it are not handled by pyramid
187 # Exceptions which are raised inside of it are not handled by pyramid
188 # again. Therefore we add a middleware that invokes the error handler in
188 # again. Therefore we add a middleware that invokes the error handler in
189 # case of an exception or error response. This way we return proper error
189 # case of an exception or error response. This way we return proper error
190 # HTML pages in case of an error.
190 # HTML pages in case of an error.
191 reraise = (settings.get('debugtoolbar.enabled', False) or
191 reraise = (settings.get('debugtoolbar.enabled', False) or
192 rhodecode.disable_error_handler)
192 rhodecode.disable_error_handler)
193 pylons_app = PylonsErrorHandlingMiddleware(
193 pylons_app = PylonsErrorHandlingMiddleware(
194 pylons_app, error_handler, reraise)
194 pylons_app, error_handler, reraise)
195
195
196 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
196 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
197 # view to handle the request. Therefore it is wrapped around the pylons
197 # view to handle the request. Therefore it is wrapped around the pylons
198 # app. It has to be outside of the error handling otherwise error responses
198 # app. It has to be outside of the error handling otherwise error responses
199 # from the vcsserver are converted to HTML error pages. This confuses the
199 # from the vcsserver are converted to HTML error pages. This confuses the
200 # command line tools and the user won't get a meaningful error message.
200 # command line tools and the user won't get a meaningful error message.
201 if vcs_server_enabled:
201 if vcs_server_enabled:
202 pylons_app = VCSMiddleware(
202 pylons_app = VCSMiddleware(
203 pylons_app, settings, appenlight_client, registry=config.registry)
203 pylons_app, settings, appenlight_client, registry=config.registry)
204
204
205 # Convert WSGI app to pyramid view and return it.
205 # Convert WSGI app to pyramid view and return it.
206 return wsgiapp(pylons_app)
206 return wsgiapp(pylons_app)
207
207
208
208
209 def add_pylons_compat_data(registry, global_config, settings):
209 def add_pylons_compat_data(registry, global_config, settings):
210 """
210 """
211 Attach data to the registry to support the Pylons integration.
211 Attach data to the registry to support the Pylons integration.
212 """
212 """
213 registry._pylons_compat_global_config = global_config
213 registry._pylons_compat_global_config = global_config
214 registry._pylons_compat_settings = settings
214 registry._pylons_compat_settings = settings
215
215
216
216
217 def error_handler(exception, request):
217 def error_handler(exception, request):
218 import rhodecode
218 import rhodecode
219 from rhodecode.lib import helpers
219 from rhodecode.lib import helpers
220
220
221 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
221 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
222
222
223 base_response = HTTPInternalServerError()
223 base_response = HTTPInternalServerError()
224 # prefer original exception for the response since it may have headers set
224 # prefer original exception for the response since it may have headers set
225 if isinstance(exception, HTTPException):
225 if isinstance(exception, HTTPException):
226 base_response = exception
226 base_response = exception
227 elif isinstance(exception, VCSCommunicationError):
227 elif isinstance(exception, VCSCommunicationError):
228 base_response = VCSServerUnavailable()
228 base_response = VCSServerUnavailable()
229
229
230 def is_http_error(response):
230 def is_http_error(response):
231 # error which should have traceback
231 # error which should have traceback
232 return response.status_code > 499
232 return response.status_code > 499
233
233
234 if is_http_error(base_response):
234 if is_http_error(base_response):
235 log.exception(
235 log.exception(
236 'error occurred handling this request for path: %s', request.path)
236 'error occurred handling this request for path: %s', request.path)
237
237
238 c = AttributeDict()
238 c = AttributeDict()
239 c.error_message = base_response.status
239 c.error_message = base_response.status
240 c.error_explanation = base_response.explanation or str(base_response)
240 c.error_explanation = base_response.explanation or str(base_response)
241 c.visual = AttributeDict()
241 c.visual = AttributeDict()
242
242
243 c.visual.rhodecode_support_url = (
243 c.visual.rhodecode_support_url = (
244 request.registry.settings.get('rhodecode_support_url') or
244 request.registry.settings.get('rhodecode_support_url') or
245 request.route_url('rhodecode_support')
245 request.route_url('rhodecode_support')
246 )
246 )
247 c.redirect_time = 0
247 c.redirect_time = 0
248 c.rhodecode_name = rhodecode_title
248 c.rhodecode_name = rhodecode_title
249 if not c.rhodecode_name:
249 if not c.rhodecode_name:
250 c.rhodecode_name = 'Rhodecode'
250 c.rhodecode_name = 'Rhodecode'
251
251
252 c.causes = []
252 c.causes = []
253 if hasattr(base_response, 'causes'):
253 if hasattr(base_response, 'causes'):
254 c.causes = base_response.causes
254 c.causes = base_response.causes
255 c.messages = helpers.flash.pop_messages(request=request)
255 c.messages = helpers.flash.pop_messages(request=request)
256 c.traceback = traceback.format_exc()
256 c.traceback = traceback.format_exc()
257 response = render_to_response(
257 response = render_to_response(
258 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
258 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
259 response=base_response)
259 response=base_response)
260
260
261 return response
261 return response
262
262
263
263
264 def includeme(config):
264 def includeme(config):
265 settings = config.registry.settings
265 settings = config.registry.settings
266
266
267 # plugin information
267 # plugin information
268 config.registry.rhodecode_plugins = OrderedDict()
268 config.registry.rhodecode_plugins = OrderedDict()
269
269
270 config.add_directive(
270 config.add_directive(
271 'register_rhodecode_plugin', register_rhodecode_plugin)
271 'register_rhodecode_plugin', register_rhodecode_plugin)
272
272
273 if asbool(settings.get('appenlight', 'false')):
273 if asbool(settings.get('appenlight', 'false')):
274 config.include('appenlight_client.ext.pyramid_tween')
274 config.include('appenlight_client.ext.pyramid_tween')
275
275
276 # Includes which are required. The application would fail without them.
276 # Includes which are required. The application would fail without them.
277 config.include('pyramid_mako')
277 config.include('pyramid_mako')
278 config.include('pyramid_beaker')
278 config.include('pyramid_beaker')
279
279
280 config.include('rhodecode.authentication')
280 config.include('rhodecode.authentication')
281 config.include('rhodecode.integrations')
281 config.include('rhodecode.integrations')
282
282
283 # apps
283 # apps
284 config.include('rhodecode.apps._base')
284 config.include('rhodecode.apps._base')
285 config.include('rhodecode.apps.ops')
285 config.include('rhodecode.apps.ops')
286
286
287 config.include('rhodecode.apps.admin')
287 config.include('rhodecode.apps.admin')
288 config.include('rhodecode.apps.channelstream')
288 config.include('rhodecode.apps.channelstream')
289 config.include('rhodecode.apps.login')
289 config.include('rhodecode.apps.login')
290 config.include('rhodecode.apps.home')
290 config.include('rhodecode.apps.home')
291 config.include('rhodecode.apps.journal')
291 config.include('rhodecode.apps.repository')
292 config.include('rhodecode.apps.repository')
292 config.include('rhodecode.apps.repo_group')
293 config.include('rhodecode.apps.repo_group')
293 config.include('rhodecode.apps.search')
294 config.include('rhodecode.apps.search')
294 config.include('rhodecode.apps.user_profile')
295 config.include('rhodecode.apps.user_profile')
295 config.include('rhodecode.apps.my_account')
296 config.include('rhodecode.apps.my_account')
296 config.include('rhodecode.apps.svn_support')
297 config.include('rhodecode.apps.svn_support')
297 config.include('rhodecode.apps.gist')
298 config.include('rhodecode.apps.gist')
298
299
299 config.include('rhodecode.apps.debug_style')
300 config.include('rhodecode.apps.debug_style')
300 config.include('rhodecode.tweens')
301 config.include('rhodecode.tweens')
301 config.include('rhodecode.api')
302 config.include('rhodecode.api')
302
303
303 config.add_route(
304 config.add_route(
304 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
305 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
305
306
306 config.add_translation_dirs('rhodecode:i18n/')
307 config.add_translation_dirs('rhodecode:i18n/')
307 settings['default_locale_name'] = settings.get('lang', 'en')
308 settings['default_locale_name'] = settings.get('lang', 'en')
308
309
309 # Add subscribers.
310 # Add subscribers.
310 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
311 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
311 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
312 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
312 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
313 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
313
314
314 config.add_request_method(
315 config.add_request_method(
315 'rhodecode.lib.partial_renderer.get_partial_renderer',
316 'rhodecode.lib.partial_renderer.get_partial_renderer',
316 'get_partial_renderer')
317 'get_partial_renderer')
317
318
318 # events
319 # events
319 # TODO(marcink): this should be done when pyramid migration is finished
320 # TODO(marcink): this should be done when pyramid migration is finished
320 # config.add_subscriber(
321 # config.add_subscriber(
321 # 'rhodecode.integrations.integrations_event_handler',
322 # 'rhodecode.integrations.integrations_event_handler',
322 # 'rhodecode.events.RhodecodeEvent')
323 # 'rhodecode.events.RhodecodeEvent')
323
324
324 # Set the authorization policy.
325 # Set the authorization policy.
325 authz_policy = ACLAuthorizationPolicy()
326 authz_policy = ACLAuthorizationPolicy()
326 config.set_authorization_policy(authz_policy)
327 config.set_authorization_policy(authz_policy)
327
328
328 # Set the default renderer for HTML templates to mako.
329 # Set the default renderer for HTML templates to mako.
329 config.add_mako_renderer('.html')
330 config.add_mako_renderer('.html')
330
331
331 config.add_renderer(
332 config.add_renderer(
332 name='json_ext',
333 name='json_ext',
333 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
334 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
334
335
335 # include RhodeCode plugins
336 # include RhodeCode plugins
336 includes = aslist(settings.get('rhodecode.includes', []))
337 includes = aslist(settings.get('rhodecode.includes', []))
337 for inc in includes:
338 for inc in includes:
338 config.include(inc)
339 config.include(inc)
339
340
340 # This is the glue which allows us to migrate in chunks. By registering the
341 # This is the glue which allows us to migrate in chunks. By registering the
341 # pylons based application as the "Not Found" view in Pyramid, we will
342 # pylons based application as the "Not Found" view in Pyramid, we will
342 # fallback to the old application each time the new one does not yet know
343 # fallback to the old application each time the new one does not yet know
343 # how to handle a request.
344 # how to handle a request.
344 config.add_notfound_view(make_not_found_view(config))
345 config.add_notfound_view(make_not_found_view(config))
345
346
346 if not settings.get('debugtoolbar.enabled', False):
347 if not settings.get('debugtoolbar.enabled', False):
347 # disabled debugtoolbar handle all exceptions via the error_handlers
348 # disabled debugtoolbar handle all exceptions via the error_handlers
348 config.add_view(error_handler, context=Exception)
349 config.add_view(error_handler, context=Exception)
349
350
350 config.add_view(error_handler, context=HTTPError)
351 config.add_view(error_handler, context=HTTPError)
351
352
352
353
353 def includeme_first(config):
354 def includeme_first(config):
354 # redirect automatic browser favicon.ico requests to correct place
355 # redirect automatic browser favicon.ico requests to correct place
355 def favicon_redirect(context, request):
356 def favicon_redirect(context, request):
356 return HTTPFound(
357 return HTTPFound(
357 request.static_path('rhodecode:public/images/favicon.ico'))
358 request.static_path('rhodecode:public/images/favicon.ico'))
358
359
359 config.add_view(favicon_redirect, route_name='favicon')
360 config.add_view(favicon_redirect, route_name='favicon')
360 config.add_route('favicon', '/favicon.ico')
361 config.add_route('favicon', '/favicon.ico')
361
362
362 def robots_redirect(context, request):
363 def robots_redirect(context, request):
363 return HTTPFound(
364 return HTTPFound(
364 request.static_path('rhodecode:public/robots.txt'))
365 request.static_path('rhodecode:public/robots.txt'))
365
366
366 config.add_view(robots_redirect, route_name='robots')
367 config.add_view(robots_redirect, route_name='robots')
367 config.add_route('robots', '/robots.txt')
368 config.add_route('robots', '/robots.txt')
368
369
369 config.add_static_view(
370 config.add_static_view(
370 '_static/deform', 'deform:static')
371 '_static/deform', 'deform:static')
371 config.add_static_view(
372 config.add_static_view(
372 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
373 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
373
374
374
375
375 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
376 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
376 """
377 """
377 Apply outer WSGI middlewares around the application.
378 Apply outer WSGI middlewares around the application.
378
379
379 Part of this has been moved up from the Pylons layer, so that the
380 Part of this has been moved up from the Pylons layer, so that the
380 data is also available if old Pylons code is hit through an already ported
381 data is also available if old Pylons code is hit through an already ported
381 view.
382 view.
382 """
383 """
383 settings = config.registry.settings
384 settings = config.registry.settings
384
385
385 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
386 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
386 pyramid_app = HttpsFixup(pyramid_app, settings)
387 pyramid_app = HttpsFixup(pyramid_app, settings)
387
388
388 # Add RoutesMiddleware to support the pylons compatibility tween during
389 # Add RoutesMiddleware to support the pylons compatibility tween during
389 # migration to pyramid.
390 # migration to pyramid.
390
391
391 # TODO(marcink): remove after migration to pyramid
392 # TODO(marcink): remove after migration to pyramid
392 if hasattr(config.registry, '_pylons_compat_config'):
393 if hasattr(config.registry, '_pylons_compat_config'):
393 routes_map = config.registry._pylons_compat_config['routes.map']
394 routes_map = config.registry._pylons_compat_config['routes.map']
394 pyramid_app = SkippableRoutesMiddleware(
395 pyramid_app = SkippableRoutesMiddleware(
395 pyramid_app, routes_map,
396 pyramid_app, routes_map,
396 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
397 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
397
398
398 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
399 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
399
400
400 if settings['gzip_responses']:
401 if settings['gzip_responses']:
401 pyramid_app = make_gzip_middleware(
402 pyramid_app = make_gzip_middleware(
402 pyramid_app, settings, compress_level=1)
403 pyramid_app, settings, compress_level=1)
403
404
404 # this should be the outer most middleware in the wsgi stack since
405 # this should be the outer most middleware in the wsgi stack since
405 # middleware like Routes make database calls
406 # middleware like Routes make database calls
406 def pyramid_app_with_cleanup(environ, start_response):
407 def pyramid_app_with_cleanup(environ, start_response):
407 try:
408 try:
408 return pyramid_app(environ, start_response)
409 return pyramid_app(environ, start_response)
409 finally:
410 finally:
410 # Dispose current database session and rollback uncommitted
411 # Dispose current database session and rollback uncommitted
411 # transactions.
412 # transactions.
412 meta.Session.remove()
413 meta.Session.remove()
413
414
414 # In a single threaded mode server, on non sqlite db we should have
415 # In a single threaded mode server, on non sqlite db we should have
415 # '0 Current Checked out connections' at the end of a request,
416 # '0 Current Checked out connections' at the end of a request,
416 # if not, then something, somewhere is leaving a connection open
417 # if not, then something, somewhere is leaving a connection open
417 pool = meta.Base.metadata.bind.engine.pool
418 pool = meta.Base.metadata.bind.engine.pool
418 log.debug('sa pool status: %s', pool.status())
419 log.debug('sa pool status: %s', pool.status())
419
420
420 return pyramid_app_with_cleanup
421 return pyramid_app_with_cleanup
421
422
422
423
423 def sanitize_settings_and_apply_defaults(settings):
424 def sanitize_settings_and_apply_defaults(settings):
424 """
425 """
425 Applies settings defaults and does all type conversion.
426 Applies settings defaults and does all type conversion.
426
427
427 We would move all settings parsing and preparation into this place, so that
428 We would move all settings parsing and preparation into this place, so that
428 we have only one place left which deals with this part. The remaining parts
429 we have only one place left which deals with this part. The remaining parts
429 of the application would start to rely fully on well prepared settings.
430 of the application would start to rely fully on well prepared settings.
430
431
431 This piece would later be split up per topic to avoid a big fat monster
432 This piece would later be split up per topic to avoid a big fat monster
432 function.
433 function.
433 """
434 """
434
435
435 # Pyramid's mako renderer has to search in the templates folder so that the
436 # Pyramid's mako renderer has to search in the templates folder so that the
436 # old templates still work. Ported and new templates are expected to use
437 # old templates still work. Ported and new templates are expected to use
437 # real asset specifications for the includes.
438 # real asset specifications for the includes.
438 mako_directories = settings.setdefault('mako.directories', [
439 mako_directories = settings.setdefault('mako.directories', [
439 # Base templates of the original Pylons application
440 # Base templates of the original Pylons application
440 'rhodecode:templates',
441 'rhodecode:templates',
441 ])
442 ])
442 log.debug(
443 log.debug(
443 "Using the following Mako template directories: %s",
444 "Using the following Mako template directories: %s",
444 mako_directories)
445 mako_directories)
445
446
446 # Default includes, possible to change as a user
447 # Default includes, possible to change as a user
447 pyramid_includes = settings.setdefault('pyramid.includes', [
448 pyramid_includes = settings.setdefault('pyramid.includes', [
448 'rhodecode.lib.middleware.request_wrapper',
449 'rhodecode.lib.middleware.request_wrapper',
449 ])
450 ])
450 log.debug(
451 log.debug(
451 "Using the following pyramid.includes: %s",
452 "Using the following pyramid.includes: %s",
452 pyramid_includes)
453 pyramid_includes)
453
454
454 # TODO: johbo: Re-think this, usually the call to config.include
455 # TODO: johbo: Re-think this, usually the call to config.include
455 # should allow to pass in a prefix.
456 # should allow to pass in a prefix.
456 settings.setdefault('rhodecode.api.url', '/_admin/api')
457 settings.setdefault('rhodecode.api.url', '/_admin/api')
457
458
458 # Sanitize generic settings.
459 # Sanitize generic settings.
459 _list_setting(settings, 'default_encoding', 'UTF-8')
460 _list_setting(settings, 'default_encoding', 'UTF-8')
460 _bool_setting(settings, 'is_test', 'false')
461 _bool_setting(settings, 'is_test', 'false')
461 _bool_setting(settings, 'gzip_responses', 'false')
462 _bool_setting(settings, 'gzip_responses', 'false')
462
463
463 # Call split out functions that sanitize settings for each topic.
464 # Call split out functions that sanitize settings for each topic.
464 _sanitize_appenlight_settings(settings)
465 _sanitize_appenlight_settings(settings)
465 _sanitize_vcs_settings(settings)
466 _sanitize_vcs_settings(settings)
466
467
467 return settings
468 return settings
468
469
469
470
470 def _sanitize_appenlight_settings(settings):
471 def _sanitize_appenlight_settings(settings):
471 _bool_setting(settings, 'appenlight', 'false')
472 _bool_setting(settings, 'appenlight', 'false')
472
473
473
474
474 def _sanitize_vcs_settings(settings):
475 def _sanitize_vcs_settings(settings):
475 """
476 """
476 Applies settings defaults and does type conversion for all VCS related
477 Applies settings defaults and does type conversion for all VCS related
477 settings.
478 settings.
478 """
479 """
479 _string_setting(settings, 'vcs.svn.compatible_version', '')
480 _string_setting(settings, 'vcs.svn.compatible_version', '')
480 _string_setting(settings, 'git_rev_filter', '--all')
481 _string_setting(settings, 'git_rev_filter', '--all')
481 _string_setting(settings, 'vcs.hooks.protocol', 'http')
482 _string_setting(settings, 'vcs.hooks.protocol', 'http')
482 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
483 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
483 _string_setting(settings, 'vcs.server', '')
484 _string_setting(settings, 'vcs.server', '')
484 _string_setting(settings, 'vcs.server.log_level', 'debug')
485 _string_setting(settings, 'vcs.server.log_level', 'debug')
485 _string_setting(settings, 'vcs.server.protocol', 'http')
486 _string_setting(settings, 'vcs.server.protocol', 'http')
486 _bool_setting(settings, 'startup.import_repos', 'false')
487 _bool_setting(settings, 'startup.import_repos', 'false')
487 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
488 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
488 _bool_setting(settings, 'vcs.server.enable', 'true')
489 _bool_setting(settings, 'vcs.server.enable', 'true')
489 _bool_setting(settings, 'vcs.start_server', 'false')
490 _bool_setting(settings, 'vcs.start_server', 'false')
490 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
491 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
491 _int_setting(settings, 'vcs.connection_timeout', 3600)
492 _int_setting(settings, 'vcs.connection_timeout', 3600)
492
493
493 # Support legacy values of vcs.scm_app_implementation. Legacy
494 # Support legacy values of vcs.scm_app_implementation. Legacy
494 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
495 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
495 # which is now mapped to 'http'.
496 # which is now mapped to 'http'.
496 scm_app_impl = settings['vcs.scm_app_implementation']
497 scm_app_impl = settings['vcs.scm_app_implementation']
497 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
498 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
498 settings['vcs.scm_app_implementation'] = 'http'
499 settings['vcs.scm_app_implementation'] = 'http'
499
500
500
501
501 def _int_setting(settings, name, default):
502 def _int_setting(settings, name, default):
502 settings[name] = int(settings.get(name, default))
503 settings[name] = int(settings.get(name, default))
503
504
504
505
505 def _bool_setting(settings, name, default):
506 def _bool_setting(settings, name, default):
506 input = settings.get(name, default)
507 input = settings.get(name, default)
507 if isinstance(input, unicode):
508 if isinstance(input, unicode):
508 input = input.encode('utf8')
509 input = input.encode('utf8')
509 settings[name] = asbool(input)
510 settings[name] = asbool(input)
510
511
511
512
512 def _list_setting(settings, name, default):
513 def _list_setting(settings, name, default):
513 raw_value = settings.get(name, default)
514 raw_value = settings.get(name, default)
514
515
515 old_separator = ','
516 old_separator = ','
516 if old_separator in raw_value:
517 if old_separator in raw_value:
517 # If we get a comma separated list, pass it to our own function.
518 # If we get a comma separated list, pass it to our own function.
518 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
519 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
519 else:
520 else:
520 # Otherwise we assume it uses pyramids space/newline separation.
521 # Otherwise we assume it uses pyramids space/newline separation.
521 settings[name] = aslist(raw_value)
522 settings[name] = aslist(raw_value)
522
523
523
524
524 def _string_setting(settings, name, default, lower=True):
525 def _string_setting(settings, name, default, lower=True):
525 value = settings.get(name, default)
526 value = settings.get(name, default)
526 if lower:
527 if lower:
527 value = value.lower()
528 value = value.lower()
528 settings[name] = value
529 settings[name] = value
@@ -1,715 +1,686 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Routes configuration
22 Routes configuration
23
23
24 The more specific and detailed routes should be defined first so they
24 The more specific and detailed routes should be defined first so they
25 may take precedent over the more generic routes. For more information
25 may take precedent over the more generic routes. For more information
26 refer to the routes manual at http://routes.groovie.org/docs/
26 refer to the routes manual at http://routes.groovie.org/docs/
27
27
28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 and _route_name variable which uses some of stored naming here to do redirects.
29 and _route_name variable which uses some of stored naming here to do redirects.
30 """
30 """
31 import os
31 import os
32 import re
32 import re
33 from routes import Mapper
33 from routes import Mapper
34
34
35 # prefix for non repository related links needs to be prefixed with `/`
35 # prefix for non repository related links needs to be prefixed with `/`
36 ADMIN_PREFIX = '/_admin'
36 ADMIN_PREFIX = '/_admin'
37 STATIC_FILE_PREFIX = '/_static'
37 STATIC_FILE_PREFIX = '/_static'
38
38
39 # Default requirements for URL parts
39 # Default requirements for URL parts
40 URL_NAME_REQUIREMENTS = {
40 URL_NAME_REQUIREMENTS = {
41 # group name can have a slash in them, but they must not end with a slash
41 # group name can have a slash in them, but they must not end with a slash
42 'group_name': r'.*?[^/]',
42 'group_name': r'.*?[^/]',
43 'repo_group_name': r'.*?[^/]',
43 'repo_group_name': r'.*?[^/]',
44 # repo names can have a slash in them, but they must not end with a slash
44 # repo names can have a slash in them, but they must not end with a slash
45 'repo_name': r'.*?[^/]',
45 'repo_name': r'.*?[^/]',
46 # file path eats up everything at the end
46 # file path eats up everything at the end
47 'f_path': r'.*',
47 'f_path': r'.*',
48 # reference types
48 # reference types
49 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
49 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
50 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
50 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
51 }
51 }
52
52
53
53
54 class JSRoutesMapper(Mapper):
54 class JSRoutesMapper(Mapper):
55 """
55 """
56 Wrapper for routes.Mapper to make pyroutes compatible url definitions
56 Wrapper for routes.Mapper to make pyroutes compatible url definitions
57 """
57 """
58 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
58 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
59 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
59 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
60 def __init__(self, *args, **kw):
60 def __init__(self, *args, **kw):
61 super(JSRoutesMapper, self).__init__(*args, **kw)
61 super(JSRoutesMapper, self).__init__(*args, **kw)
62 self._jsroutes = []
62 self._jsroutes = []
63
63
64 def connect(self, *args, **kw):
64 def connect(self, *args, **kw):
65 """
65 """
66 Wrapper for connect to take an extra argument jsroute=True
66 Wrapper for connect to take an extra argument jsroute=True
67
67
68 :param jsroute: boolean, if True will add the route to the pyroutes list
68 :param jsroute: boolean, if True will add the route to the pyroutes list
69 """
69 """
70 if kw.pop('jsroute', False):
70 if kw.pop('jsroute', False):
71 if not self._named_route_regex.match(args[0]):
71 if not self._named_route_regex.match(args[0]):
72 raise Exception('only named routes can be added to pyroutes')
72 raise Exception('only named routes can be added to pyroutes')
73 self._jsroutes.append(args[0])
73 self._jsroutes.append(args[0])
74
74
75 super(JSRoutesMapper, self).connect(*args, **kw)
75 super(JSRoutesMapper, self).connect(*args, **kw)
76
76
77 def _extract_route_information(self, route):
77 def _extract_route_information(self, route):
78 """
78 """
79 Convert a route into tuple(name, path, args), eg:
79 Convert a route into tuple(name, path, args), eg:
80 ('show_user', '/profile/%(username)s', ['username'])
80 ('show_user', '/profile/%(username)s', ['username'])
81 """
81 """
82 routepath = route.routepath
82 routepath = route.routepath
83 def replace(matchobj):
83 def replace(matchobj):
84 if matchobj.group(1):
84 if matchobj.group(1):
85 return "%%(%s)s" % matchobj.group(1).split(':')[0]
85 return "%%(%s)s" % matchobj.group(1).split(':')[0]
86 else:
86 else:
87 return "%%(%s)s" % matchobj.group(2)
87 return "%%(%s)s" % matchobj.group(2)
88
88
89 routepath = self._argument_prog.sub(replace, routepath)
89 routepath = self._argument_prog.sub(replace, routepath)
90 return (
90 return (
91 route.name,
91 route.name,
92 routepath,
92 routepath,
93 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
93 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
94 for arg in self._argument_prog.findall(route.routepath)]
94 for arg in self._argument_prog.findall(route.routepath)]
95 )
95 )
96
96
97 def jsroutes(self):
97 def jsroutes(self):
98 """
98 """
99 Return a list of pyroutes.js compatible routes
99 Return a list of pyroutes.js compatible routes
100 """
100 """
101 for route_name in self._jsroutes:
101 for route_name in self._jsroutes:
102 yield self._extract_route_information(self._routenames[route_name])
102 yield self._extract_route_information(self._routenames[route_name])
103
103
104
104
105 def make_map(config):
105 def make_map(config):
106 """Create, configure and return the routes Mapper"""
106 """Create, configure and return the routes Mapper"""
107 rmap = JSRoutesMapper(
107 rmap = JSRoutesMapper(
108 directory=config['pylons.paths']['controllers'],
108 directory=config['pylons.paths']['controllers'],
109 always_scan=config['debug'])
109 always_scan=config['debug'])
110 rmap.minimization = False
110 rmap.minimization = False
111 rmap.explicit = False
111 rmap.explicit = False
112
112
113 from rhodecode.lib.utils2 import str2bool
113 from rhodecode.lib.utils2 import str2bool
114 from rhodecode.model import repo, repo_group
114 from rhodecode.model import repo, repo_group
115
115
116 def check_repo(environ, match_dict):
116 def check_repo(environ, match_dict):
117 """
117 """
118 check for valid repository for proper 404 handling
118 check for valid repository for proper 404 handling
119
119
120 :param environ:
120 :param environ:
121 :param match_dict:
121 :param match_dict:
122 """
122 """
123 repo_name = match_dict.get('repo_name')
123 repo_name = match_dict.get('repo_name')
124
124
125 if match_dict.get('f_path'):
125 if match_dict.get('f_path'):
126 # fix for multiple initial slashes that causes errors
126 # fix for multiple initial slashes that causes errors
127 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
127 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
128 repo_model = repo.RepoModel()
128 repo_model = repo.RepoModel()
129 by_name_match = repo_model.get_by_repo_name(repo_name)
129 by_name_match = repo_model.get_by_repo_name(repo_name)
130 # if we match quickly from database, short circuit the operation,
130 # if we match quickly from database, short circuit the operation,
131 # and validate repo based on the type.
131 # and validate repo based on the type.
132 if by_name_match:
132 if by_name_match:
133 return True
133 return True
134
134
135 by_id_match = repo_model.get_repo_by_id(repo_name)
135 by_id_match = repo_model.get_repo_by_id(repo_name)
136 if by_id_match:
136 if by_id_match:
137 repo_name = by_id_match.repo_name
137 repo_name = by_id_match.repo_name
138 match_dict['repo_name'] = repo_name
138 match_dict['repo_name'] = repo_name
139 return True
139 return True
140
140
141 return False
141 return False
142
142
143 def check_group(environ, match_dict):
143 def check_group(environ, match_dict):
144 """
144 """
145 check for valid repository group path for proper 404 handling
145 check for valid repository group path for proper 404 handling
146
146
147 :param environ:
147 :param environ:
148 :param match_dict:
148 :param match_dict:
149 """
149 """
150 repo_group_name = match_dict.get('group_name')
150 repo_group_name = match_dict.get('group_name')
151 repo_group_model = repo_group.RepoGroupModel()
151 repo_group_model = repo_group.RepoGroupModel()
152 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
152 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
153 if by_name_match:
153 if by_name_match:
154 return True
154 return True
155
155
156 return False
156 return False
157
157
158 def check_user_group(environ, match_dict):
158 def check_user_group(environ, match_dict):
159 """
159 """
160 check for valid user group for proper 404 handling
160 check for valid user group for proper 404 handling
161
161
162 :param environ:
162 :param environ:
163 :param match_dict:
163 :param match_dict:
164 """
164 """
165 return True
165 return True
166
166
167 def check_int(environ, match_dict):
167 def check_int(environ, match_dict):
168 return match_dict.get('id').isdigit()
168 return match_dict.get('id').isdigit()
169
169
170
170
171 #==========================================================================
171 #==========================================================================
172 # CUSTOM ROUTES HERE
172 # CUSTOM ROUTES HERE
173 #==========================================================================
173 #==========================================================================
174
174
175 # ping and pylons error test
175 # ping and pylons error test
176 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
176 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
177 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
177 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
178
178
179 # ADMIN REPOSITORY ROUTES
179 # ADMIN REPOSITORY ROUTES
180 with rmap.submapper(path_prefix=ADMIN_PREFIX,
180 with rmap.submapper(path_prefix=ADMIN_PREFIX,
181 controller='admin/repos') as m:
181 controller='admin/repos') as m:
182 m.connect('repos', '/repos',
182 m.connect('repos', '/repos',
183 action='create', conditions={'method': ['POST']})
183 action='create', conditions={'method': ['POST']})
184 m.connect('repos', '/repos',
184 m.connect('repos', '/repos',
185 action='index', conditions={'method': ['GET']})
185 action='index', conditions={'method': ['GET']})
186 m.connect('new_repo', '/create_repository', jsroute=True,
186 m.connect('new_repo', '/create_repository', jsroute=True,
187 action='create_repository', conditions={'method': ['GET']})
187 action='create_repository', conditions={'method': ['GET']})
188 m.connect('delete_repo', '/repos/{repo_name}',
188 m.connect('delete_repo', '/repos/{repo_name}',
189 action='delete', conditions={'method': ['DELETE']},
189 action='delete', conditions={'method': ['DELETE']},
190 requirements=URL_NAME_REQUIREMENTS)
190 requirements=URL_NAME_REQUIREMENTS)
191 m.connect('repo', '/repos/{repo_name}',
191 m.connect('repo', '/repos/{repo_name}',
192 action='show', conditions={'method': ['GET'],
192 action='show', conditions={'method': ['GET'],
193 'function': check_repo},
193 'function': check_repo},
194 requirements=URL_NAME_REQUIREMENTS)
194 requirements=URL_NAME_REQUIREMENTS)
195
195
196 # ADMIN REPOSITORY GROUPS ROUTES
196 # ADMIN REPOSITORY GROUPS ROUTES
197 with rmap.submapper(path_prefix=ADMIN_PREFIX,
197 with rmap.submapper(path_prefix=ADMIN_PREFIX,
198 controller='admin/repo_groups') as m:
198 controller='admin/repo_groups') as m:
199 m.connect('repo_groups', '/repo_groups',
199 m.connect('repo_groups', '/repo_groups',
200 action='create', conditions={'method': ['POST']})
200 action='create', conditions={'method': ['POST']})
201 m.connect('repo_groups', '/repo_groups',
201 m.connect('repo_groups', '/repo_groups',
202 action='index', conditions={'method': ['GET']})
202 action='index', conditions={'method': ['GET']})
203 m.connect('new_repo_group', '/repo_groups/new',
203 m.connect('new_repo_group', '/repo_groups/new',
204 action='new', conditions={'method': ['GET']})
204 action='new', conditions={'method': ['GET']})
205 m.connect('update_repo_group', '/repo_groups/{group_name}',
205 m.connect('update_repo_group', '/repo_groups/{group_name}',
206 action='update', conditions={'method': ['PUT'],
206 action='update', conditions={'method': ['PUT'],
207 'function': check_group},
207 'function': check_group},
208 requirements=URL_NAME_REQUIREMENTS)
208 requirements=URL_NAME_REQUIREMENTS)
209
209
210 # EXTRAS REPO GROUP ROUTES
210 # EXTRAS REPO GROUP ROUTES
211 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
211 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
212 action='edit',
212 action='edit',
213 conditions={'method': ['GET'], 'function': check_group},
213 conditions={'method': ['GET'], 'function': check_group},
214 requirements=URL_NAME_REQUIREMENTS)
214 requirements=URL_NAME_REQUIREMENTS)
215 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
215 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
216 action='edit',
216 action='edit',
217 conditions={'method': ['PUT'], 'function': check_group},
217 conditions={'method': ['PUT'], 'function': check_group},
218 requirements=URL_NAME_REQUIREMENTS)
218 requirements=URL_NAME_REQUIREMENTS)
219
219
220 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
220 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
221 action='edit_repo_group_advanced',
221 action='edit_repo_group_advanced',
222 conditions={'method': ['GET'], 'function': check_group},
222 conditions={'method': ['GET'], 'function': check_group},
223 requirements=URL_NAME_REQUIREMENTS)
223 requirements=URL_NAME_REQUIREMENTS)
224 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
224 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
225 action='edit_repo_group_advanced',
225 action='edit_repo_group_advanced',
226 conditions={'method': ['PUT'], 'function': check_group},
226 conditions={'method': ['PUT'], 'function': check_group},
227 requirements=URL_NAME_REQUIREMENTS)
227 requirements=URL_NAME_REQUIREMENTS)
228
228
229 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
229 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
230 action='edit_repo_group_perms',
230 action='edit_repo_group_perms',
231 conditions={'method': ['GET'], 'function': check_group},
231 conditions={'method': ['GET'], 'function': check_group},
232 requirements=URL_NAME_REQUIREMENTS)
232 requirements=URL_NAME_REQUIREMENTS)
233 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
233 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
234 action='update_perms',
234 action='update_perms',
235 conditions={'method': ['PUT'], 'function': check_group},
235 conditions={'method': ['PUT'], 'function': check_group},
236 requirements=URL_NAME_REQUIREMENTS)
236 requirements=URL_NAME_REQUIREMENTS)
237
237
238 m.connect('delete_repo_group', '/repo_groups/{group_name}',
238 m.connect('delete_repo_group', '/repo_groups/{group_name}',
239 action='delete', conditions={'method': ['DELETE'],
239 action='delete', conditions={'method': ['DELETE'],
240 'function': check_group},
240 'function': check_group},
241 requirements=URL_NAME_REQUIREMENTS)
241 requirements=URL_NAME_REQUIREMENTS)
242
242
243 # ADMIN USER ROUTES
243 # ADMIN USER ROUTES
244 with rmap.submapper(path_prefix=ADMIN_PREFIX,
244 with rmap.submapper(path_prefix=ADMIN_PREFIX,
245 controller='admin/users') as m:
245 controller='admin/users') as m:
246 m.connect('users', '/users',
246 m.connect('users', '/users',
247 action='create', conditions={'method': ['POST']})
247 action='create', conditions={'method': ['POST']})
248 m.connect('new_user', '/users/new',
248 m.connect('new_user', '/users/new',
249 action='new', conditions={'method': ['GET']})
249 action='new', conditions={'method': ['GET']})
250 m.connect('update_user', '/users/{user_id}',
250 m.connect('update_user', '/users/{user_id}',
251 action='update', conditions={'method': ['PUT']})
251 action='update', conditions={'method': ['PUT']})
252 m.connect('delete_user', '/users/{user_id}',
252 m.connect('delete_user', '/users/{user_id}',
253 action='delete', conditions={'method': ['DELETE']})
253 action='delete', conditions={'method': ['DELETE']})
254 m.connect('edit_user', '/users/{user_id}/edit',
254 m.connect('edit_user', '/users/{user_id}/edit',
255 action='edit', conditions={'method': ['GET']}, jsroute=True)
255 action='edit', conditions={'method': ['GET']}, jsroute=True)
256 m.connect('user', '/users/{user_id}',
256 m.connect('user', '/users/{user_id}',
257 action='show', conditions={'method': ['GET']})
257 action='show', conditions={'method': ['GET']})
258 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
258 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
259 action='reset_password', conditions={'method': ['POST']})
259 action='reset_password', conditions={'method': ['POST']})
260 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
260 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
261 action='create_personal_repo_group', conditions={'method': ['POST']})
261 action='create_personal_repo_group', conditions={'method': ['POST']})
262
262
263 # EXTRAS USER ROUTES
263 # EXTRAS USER ROUTES
264 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
264 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
265 action='edit_advanced', conditions={'method': ['GET']})
265 action='edit_advanced', conditions={'method': ['GET']})
266 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
266 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
267 action='update_advanced', conditions={'method': ['PUT']})
267 action='update_advanced', conditions={'method': ['PUT']})
268
268
269 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
269 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
270 action='edit_global_perms', conditions={'method': ['GET']})
270 action='edit_global_perms', conditions={'method': ['GET']})
271 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
271 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
272 action='update_global_perms', conditions={'method': ['PUT']})
272 action='update_global_perms', conditions={'method': ['PUT']})
273
273
274 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
274 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
275 action='edit_perms_summary', conditions={'method': ['GET']})
275 action='edit_perms_summary', conditions={'method': ['GET']})
276
276
277 # ADMIN USER GROUPS REST ROUTES
277 # ADMIN USER GROUPS REST ROUTES
278 with rmap.submapper(path_prefix=ADMIN_PREFIX,
278 with rmap.submapper(path_prefix=ADMIN_PREFIX,
279 controller='admin/user_groups') as m:
279 controller='admin/user_groups') as m:
280 m.connect('users_groups', '/user_groups',
280 m.connect('users_groups', '/user_groups',
281 action='create', conditions={'method': ['POST']})
281 action='create', conditions={'method': ['POST']})
282 m.connect('users_groups', '/user_groups',
282 m.connect('users_groups', '/user_groups',
283 action='index', conditions={'method': ['GET']})
283 action='index', conditions={'method': ['GET']})
284 m.connect('new_users_group', '/user_groups/new',
284 m.connect('new_users_group', '/user_groups/new',
285 action='new', conditions={'method': ['GET']})
285 action='new', conditions={'method': ['GET']})
286 m.connect('update_users_group', '/user_groups/{user_group_id}',
286 m.connect('update_users_group', '/user_groups/{user_group_id}',
287 action='update', conditions={'method': ['PUT']})
287 action='update', conditions={'method': ['PUT']})
288 m.connect('delete_users_group', '/user_groups/{user_group_id}',
288 m.connect('delete_users_group', '/user_groups/{user_group_id}',
289 action='delete', conditions={'method': ['DELETE']})
289 action='delete', conditions={'method': ['DELETE']})
290 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
290 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
291 action='edit', conditions={'method': ['GET']},
291 action='edit', conditions={'method': ['GET']},
292 function=check_user_group)
292 function=check_user_group)
293
293
294 # EXTRAS USER GROUP ROUTES
294 # EXTRAS USER GROUP ROUTES
295 m.connect('edit_user_group_global_perms',
295 m.connect('edit_user_group_global_perms',
296 '/user_groups/{user_group_id}/edit/global_permissions',
296 '/user_groups/{user_group_id}/edit/global_permissions',
297 action='edit_global_perms', conditions={'method': ['GET']})
297 action='edit_global_perms', conditions={'method': ['GET']})
298 m.connect('edit_user_group_global_perms',
298 m.connect('edit_user_group_global_perms',
299 '/user_groups/{user_group_id}/edit/global_permissions',
299 '/user_groups/{user_group_id}/edit/global_permissions',
300 action='update_global_perms', conditions={'method': ['PUT']})
300 action='update_global_perms', conditions={'method': ['PUT']})
301 m.connect('edit_user_group_perms_summary',
301 m.connect('edit_user_group_perms_summary',
302 '/user_groups/{user_group_id}/edit/permissions_summary',
302 '/user_groups/{user_group_id}/edit/permissions_summary',
303 action='edit_perms_summary', conditions={'method': ['GET']})
303 action='edit_perms_summary', conditions={'method': ['GET']})
304
304
305 m.connect('edit_user_group_perms',
305 m.connect('edit_user_group_perms',
306 '/user_groups/{user_group_id}/edit/permissions',
306 '/user_groups/{user_group_id}/edit/permissions',
307 action='edit_perms', conditions={'method': ['GET']})
307 action='edit_perms', conditions={'method': ['GET']})
308 m.connect('edit_user_group_perms',
308 m.connect('edit_user_group_perms',
309 '/user_groups/{user_group_id}/edit/permissions',
309 '/user_groups/{user_group_id}/edit/permissions',
310 action='update_perms', conditions={'method': ['PUT']})
310 action='update_perms', conditions={'method': ['PUT']})
311
311
312 m.connect('edit_user_group_advanced',
312 m.connect('edit_user_group_advanced',
313 '/user_groups/{user_group_id}/edit/advanced',
313 '/user_groups/{user_group_id}/edit/advanced',
314 action='edit_advanced', conditions={'method': ['GET']})
314 action='edit_advanced', conditions={'method': ['GET']})
315
315
316 m.connect('edit_user_group_advanced_sync',
316 m.connect('edit_user_group_advanced_sync',
317 '/user_groups/{user_group_id}/edit/advanced/sync',
317 '/user_groups/{user_group_id}/edit/advanced/sync',
318 action='edit_advanced_set_synchronization', conditions={'method': ['POST']})
318 action='edit_advanced_set_synchronization', conditions={'method': ['POST']})
319
319
320 m.connect('edit_user_group_members',
320 m.connect('edit_user_group_members',
321 '/user_groups/{user_group_id}/edit/members', jsroute=True,
321 '/user_groups/{user_group_id}/edit/members', jsroute=True,
322 action='user_group_members', conditions={'method': ['GET']})
322 action='user_group_members', conditions={'method': ['GET']})
323
323
324 # ADMIN PERMISSIONS ROUTES
324 # ADMIN PERMISSIONS ROUTES
325 with rmap.submapper(path_prefix=ADMIN_PREFIX,
325 with rmap.submapper(path_prefix=ADMIN_PREFIX,
326 controller='admin/permissions') as m:
326 controller='admin/permissions') as m:
327 m.connect('admin_permissions_application', '/permissions/application',
327 m.connect('admin_permissions_application', '/permissions/application',
328 action='permission_application_update', conditions={'method': ['POST']})
328 action='permission_application_update', conditions={'method': ['POST']})
329 m.connect('admin_permissions_application', '/permissions/application',
329 m.connect('admin_permissions_application', '/permissions/application',
330 action='permission_application', conditions={'method': ['GET']})
330 action='permission_application', conditions={'method': ['GET']})
331
331
332 m.connect('admin_permissions_global', '/permissions/global',
332 m.connect('admin_permissions_global', '/permissions/global',
333 action='permission_global_update', conditions={'method': ['POST']})
333 action='permission_global_update', conditions={'method': ['POST']})
334 m.connect('admin_permissions_global', '/permissions/global',
334 m.connect('admin_permissions_global', '/permissions/global',
335 action='permission_global', conditions={'method': ['GET']})
335 action='permission_global', conditions={'method': ['GET']})
336
336
337 m.connect('admin_permissions_object', '/permissions/object',
337 m.connect('admin_permissions_object', '/permissions/object',
338 action='permission_objects_update', conditions={'method': ['POST']})
338 action='permission_objects_update', conditions={'method': ['POST']})
339 m.connect('admin_permissions_object', '/permissions/object',
339 m.connect('admin_permissions_object', '/permissions/object',
340 action='permission_objects', conditions={'method': ['GET']})
340 action='permission_objects', conditions={'method': ['GET']})
341
341
342 m.connect('admin_permissions_ips', '/permissions/ips',
342 m.connect('admin_permissions_ips', '/permissions/ips',
343 action='permission_ips', conditions={'method': ['POST']})
343 action='permission_ips', conditions={'method': ['POST']})
344 m.connect('admin_permissions_ips', '/permissions/ips',
344 m.connect('admin_permissions_ips', '/permissions/ips',
345 action='permission_ips', conditions={'method': ['GET']})
345 action='permission_ips', conditions={'method': ['GET']})
346
346
347 m.connect('admin_permissions_overview', '/permissions/overview',
347 m.connect('admin_permissions_overview', '/permissions/overview',
348 action='permission_perms', conditions={'method': ['GET']})
348 action='permission_perms', conditions={'method': ['GET']})
349
349
350 # ADMIN DEFAULTS REST ROUTES
350 # ADMIN DEFAULTS REST ROUTES
351 with rmap.submapper(path_prefix=ADMIN_PREFIX,
351 with rmap.submapper(path_prefix=ADMIN_PREFIX,
352 controller='admin/defaults') as m:
352 controller='admin/defaults') as m:
353 m.connect('admin_defaults_repositories', '/defaults/repositories',
353 m.connect('admin_defaults_repositories', '/defaults/repositories',
354 action='update_repository_defaults', conditions={'method': ['POST']})
354 action='update_repository_defaults', conditions={'method': ['POST']})
355 m.connect('admin_defaults_repositories', '/defaults/repositories',
355 m.connect('admin_defaults_repositories', '/defaults/repositories',
356 action='index', conditions={'method': ['GET']})
356 action='index', conditions={'method': ['GET']})
357
357
358 # ADMIN SETTINGS ROUTES
358 # ADMIN SETTINGS ROUTES
359 with rmap.submapper(path_prefix=ADMIN_PREFIX,
359 with rmap.submapper(path_prefix=ADMIN_PREFIX,
360 controller='admin/settings') as m:
360 controller='admin/settings') as m:
361
361
362 # default
362 # default
363 m.connect('admin_settings', '/settings',
363 m.connect('admin_settings', '/settings',
364 action='settings_global_update',
364 action='settings_global_update',
365 conditions={'method': ['POST']})
365 conditions={'method': ['POST']})
366 m.connect('admin_settings', '/settings',
366 m.connect('admin_settings', '/settings',
367 action='settings_global', conditions={'method': ['GET']})
367 action='settings_global', conditions={'method': ['GET']})
368
368
369 m.connect('admin_settings_vcs', '/settings/vcs',
369 m.connect('admin_settings_vcs', '/settings/vcs',
370 action='settings_vcs_update',
370 action='settings_vcs_update',
371 conditions={'method': ['POST']})
371 conditions={'method': ['POST']})
372 m.connect('admin_settings_vcs', '/settings/vcs',
372 m.connect('admin_settings_vcs', '/settings/vcs',
373 action='settings_vcs',
373 action='settings_vcs',
374 conditions={'method': ['GET']})
374 conditions={'method': ['GET']})
375 m.connect('admin_settings_vcs', '/settings/vcs',
375 m.connect('admin_settings_vcs', '/settings/vcs',
376 action='delete_svn_pattern',
376 action='delete_svn_pattern',
377 conditions={'method': ['DELETE']})
377 conditions={'method': ['DELETE']})
378
378
379 m.connect('admin_settings_mapping', '/settings/mapping',
379 m.connect('admin_settings_mapping', '/settings/mapping',
380 action='settings_mapping_update',
380 action='settings_mapping_update',
381 conditions={'method': ['POST']})
381 conditions={'method': ['POST']})
382 m.connect('admin_settings_mapping', '/settings/mapping',
382 m.connect('admin_settings_mapping', '/settings/mapping',
383 action='settings_mapping', conditions={'method': ['GET']})
383 action='settings_mapping', conditions={'method': ['GET']})
384
384
385 m.connect('admin_settings_global', '/settings/global',
385 m.connect('admin_settings_global', '/settings/global',
386 action='settings_global_update',
386 action='settings_global_update',
387 conditions={'method': ['POST']})
387 conditions={'method': ['POST']})
388 m.connect('admin_settings_global', '/settings/global',
388 m.connect('admin_settings_global', '/settings/global',
389 action='settings_global', conditions={'method': ['GET']})
389 action='settings_global', conditions={'method': ['GET']})
390
390
391 m.connect('admin_settings_visual', '/settings/visual',
391 m.connect('admin_settings_visual', '/settings/visual',
392 action='settings_visual_update',
392 action='settings_visual_update',
393 conditions={'method': ['POST']})
393 conditions={'method': ['POST']})
394 m.connect('admin_settings_visual', '/settings/visual',
394 m.connect('admin_settings_visual', '/settings/visual',
395 action='settings_visual', conditions={'method': ['GET']})
395 action='settings_visual', conditions={'method': ['GET']})
396
396
397 m.connect('admin_settings_issuetracker',
397 m.connect('admin_settings_issuetracker',
398 '/settings/issue-tracker', action='settings_issuetracker',
398 '/settings/issue-tracker', action='settings_issuetracker',
399 conditions={'method': ['GET']})
399 conditions={'method': ['GET']})
400 m.connect('admin_settings_issuetracker_save',
400 m.connect('admin_settings_issuetracker_save',
401 '/settings/issue-tracker/save',
401 '/settings/issue-tracker/save',
402 action='settings_issuetracker_save',
402 action='settings_issuetracker_save',
403 conditions={'method': ['POST']})
403 conditions={'method': ['POST']})
404 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
404 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
405 action='settings_issuetracker_test',
405 action='settings_issuetracker_test',
406 conditions={'method': ['POST']})
406 conditions={'method': ['POST']})
407 m.connect('admin_issuetracker_delete',
407 m.connect('admin_issuetracker_delete',
408 '/settings/issue-tracker/delete',
408 '/settings/issue-tracker/delete',
409 action='settings_issuetracker_delete',
409 action='settings_issuetracker_delete',
410 conditions={'method': ['DELETE']})
410 conditions={'method': ['DELETE']})
411
411
412 m.connect('admin_settings_email', '/settings/email',
412 m.connect('admin_settings_email', '/settings/email',
413 action='settings_email_update',
413 action='settings_email_update',
414 conditions={'method': ['POST']})
414 conditions={'method': ['POST']})
415 m.connect('admin_settings_email', '/settings/email',
415 m.connect('admin_settings_email', '/settings/email',
416 action='settings_email', conditions={'method': ['GET']})
416 action='settings_email', conditions={'method': ['GET']})
417
417
418 m.connect('admin_settings_hooks', '/settings/hooks',
418 m.connect('admin_settings_hooks', '/settings/hooks',
419 action='settings_hooks_update',
419 action='settings_hooks_update',
420 conditions={'method': ['POST', 'DELETE']})
420 conditions={'method': ['POST', 'DELETE']})
421 m.connect('admin_settings_hooks', '/settings/hooks',
421 m.connect('admin_settings_hooks', '/settings/hooks',
422 action='settings_hooks', conditions={'method': ['GET']})
422 action='settings_hooks', conditions={'method': ['GET']})
423
423
424 m.connect('admin_settings_search', '/settings/search',
424 m.connect('admin_settings_search', '/settings/search',
425 action='settings_search', conditions={'method': ['GET']})
425 action='settings_search', conditions={'method': ['GET']})
426
426
427 m.connect('admin_settings_supervisor', '/settings/supervisor',
427 m.connect('admin_settings_supervisor', '/settings/supervisor',
428 action='settings_supervisor', conditions={'method': ['GET']})
428 action='settings_supervisor', conditions={'method': ['GET']})
429 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
429 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
430 action='settings_supervisor_log', conditions={'method': ['GET']})
430 action='settings_supervisor_log', conditions={'method': ['GET']})
431
431
432 m.connect('admin_settings_labs', '/settings/labs',
432 m.connect('admin_settings_labs', '/settings/labs',
433 action='settings_labs_update',
433 action='settings_labs_update',
434 conditions={'method': ['POST']})
434 conditions={'method': ['POST']})
435 m.connect('admin_settings_labs', '/settings/labs',
435 m.connect('admin_settings_labs', '/settings/labs',
436 action='settings_labs', conditions={'method': ['GET']})
436 action='settings_labs', conditions={'method': ['GET']})
437
437
438 # ADMIN MY ACCOUNT
438 # ADMIN MY ACCOUNT
439 with rmap.submapper(path_prefix=ADMIN_PREFIX,
439 with rmap.submapper(path_prefix=ADMIN_PREFIX,
440 controller='admin/my_account') as m:
440 controller='admin/my_account') as m:
441
441
442 # NOTE(marcink): this needs to be kept for password force flag to be
442 # NOTE(marcink): this needs to be kept for password force flag to be
443 # handled in pylons controllers, remove after full migration to pyramid
443 # handled in pylons controllers, remove after full migration to pyramid
444 m.connect('my_account_password', '/my_account/password',
444 m.connect('my_account_password', '/my_account/password',
445 action='my_account_password', conditions={'method': ['GET']})
445 action='my_account_password', conditions={'method': ['GET']})
446
446
447 # USER JOURNAL
448 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
449 controller='journal', action='index')
450 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
451 controller='journal', action='journal_rss')
452 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
453 controller='journal', action='journal_atom')
454
455 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
456 controller='journal', action='public_journal')
457
458 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
459 controller='journal', action='public_journal_rss')
460
461 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
462 controller='journal', action='public_journal_rss')
463
464 rmap.connect('public_journal_atom',
465 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
466 action='public_journal_atom')
467
468 rmap.connect('public_journal_atom_old',
469 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
470 action='public_journal_atom')
471
472 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
473 controller='journal', action='toggle_following', jsroute=True,
474 conditions={'method': ['POST']})
475
476 #==========================================================================
447 #==========================================================================
477 # REPOSITORY ROUTES
448 # REPOSITORY ROUTES
478 #==========================================================================
449 #==========================================================================
479
450
480 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
451 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
481 controller='admin/repos', action='repo_creating',
452 controller='admin/repos', action='repo_creating',
482 requirements=URL_NAME_REQUIREMENTS)
453 requirements=URL_NAME_REQUIREMENTS)
483 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
454 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
484 controller='admin/repos', action='repo_check',
455 controller='admin/repos', action='repo_check',
485 requirements=URL_NAME_REQUIREMENTS)
456 requirements=URL_NAME_REQUIREMENTS)
486
457
487 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
458 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
488 controller='changeset', revision='tip',
459 controller='changeset', revision='tip',
489 conditions={'function': check_repo},
460 conditions={'function': check_repo},
490 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
461 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
491 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
462 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
492 controller='changeset', revision='tip', action='changeset_children',
463 controller='changeset', revision='tip', action='changeset_children',
493 conditions={'function': check_repo},
464 conditions={'function': check_repo},
494 requirements=URL_NAME_REQUIREMENTS)
465 requirements=URL_NAME_REQUIREMENTS)
495 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
466 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
496 controller='changeset', revision='tip', action='changeset_parents',
467 controller='changeset', revision='tip', action='changeset_parents',
497 conditions={'function': check_repo},
468 conditions={'function': check_repo},
498 requirements=URL_NAME_REQUIREMENTS)
469 requirements=URL_NAME_REQUIREMENTS)
499
470
500 # repo edit options
471 # repo edit options
501 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
472 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
502 controller='admin/repos', action='edit_fields',
473 controller='admin/repos', action='edit_fields',
503 conditions={'method': ['GET'], 'function': check_repo},
474 conditions={'method': ['GET'], 'function': check_repo},
504 requirements=URL_NAME_REQUIREMENTS)
475 requirements=URL_NAME_REQUIREMENTS)
505 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
476 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
506 controller='admin/repos', action='create_repo_field',
477 controller='admin/repos', action='create_repo_field',
507 conditions={'method': ['PUT'], 'function': check_repo},
478 conditions={'method': ['PUT'], 'function': check_repo},
508 requirements=URL_NAME_REQUIREMENTS)
479 requirements=URL_NAME_REQUIREMENTS)
509 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
480 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
510 controller='admin/repos', action='delete_repo_field',
481 controller='admin/repos', action='delete_repo_field',
511 conditions={'method': ['DELETE'], 'function': check_repo},
482 conditions={'method': ['DELETE'], 'function': check_repo},
512 requirements=URL_NAME_REQUIREMENTS)
483 requirements=URL_NAME_REQUIREMENTS)
513
484
514 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
485 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
515 controller='admin/repos', action='toggle_locking',
486 controller='admin/repos', action='toggle_locking',
516 conditions={'method': ['GET'], 'function': check_repo},
487 conditions={'method': ['GET'], 'function': check_repo},
517 requirements=URL_NAME_REQUIREMENTS)
488 requirements=URL_NAME_REQUIREMENTS)
518
489
519 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
490 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
520 controller='admin/repos', action='edit_remote_form',
491 controller='admin/repos', action='edit_remote_form',
521 conditions={'method': ['GET'], 'function': check_repo},
492 conditions={'method': ['GET'], 'function': check_repo},
522 requirements=URL_NAME_REQUIREMENTS)
493 requirements=URL_NAME_REQUIREMENTS)
523 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
494 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
524 controller='admin/repos', action='edit_remote',
495 controller='admin/repos', action='edit_remote',
525 conditions={'method': ['PUT'], 'function': check_repo},
496 conditions={'method': ['PUT'], 'function': check_repo},
526 requirements=URL_NAME_REQUIREMENTS)
497 requirements=URL_NAME_REQUIREMENTS)
527
498
528 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
499 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
529 controller='admin/repos', action='edit_statistics_form',
500 controller='admin/repos', action='edit_statistics_form',
530 conditions={'method': ['GET'], 'function': check_repo},
501 conditions={'method': ['GET'], 'function': check_repo},
531 requirements=URL_NAME_REQUIREMENTS)
502 requirements=URL_NAME_REQUIREMENTS)
532 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
503 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
533 controller='admin/repos', action='edit_statistics',
504 controller='admin/repos', action='edit_statistics',
534 conditions={'method': ['PUT'], 'function': check_repo},
505 conditions={'method': ['PUT'], 'function': check_repo},
535 requirements=URL_NAME_REQUIREMENTS)
506 requirements=URL_NAME_REQUIREMENTS)
536 rmap.connect('repo_settings_issuetracker',
507 rmap.connect('repo_settings_issuetracker',
537 '/{repo_name}/settings/issue-tracker',
508 '/{repo_name}/settings/issue-tracker',
538 controller='admin/repos', action='repo_issuetracker',
509 controller='admin/repos', action='repo_issuetracker',
539 conditions={'method': ['GET'], 'function': check_repo},
510 conditions={'method': ['GET'], 'function': check_repo},
540 requirements=URL_NAME_REQUIREMENTS)
511 requirements=URL_NAME_REQUIREMENTS)
541 rmap.connect('repo_issuetracker_test',
512 rmap.connect('repo_issuetracker_test',
542 '/{repo_name}/settings/issue-tracker/test',
513 '/{repo_name}/settings/issue-tracker/test',
543 controller='admin/repos', action='repo_issuetracker_test',
514 controller='admin/repos', action='repo_issuetracker_test',
544 conditions={'method': ['POST'], 'function': check_repo},
515 conditions={'method': ['POST'], 'function': check_repo},
545 requirements=URL_NAME_REQUIREMENTS)
516 requirements=URL_NAME_REQUIREMENTS)
546 rmap.connect('repo_issuetracker_delete',
517 rmap.connect('repo_issuetracker_delete',
547 '/{repo_name}/settings/issue-tracker/delete',
518 '/{repo_name}/settings/issue-tracker/delete',
548 controller='admin/repos', action='repo_issuetracker_delete',
519 controller='admin/repos', action='repo_issuetracker_delete',
549 conditions={'method': ['DELETE'], 'function': check_repo},
520 conditions={'method': ['DELETE'], 'function': check_repo},
550 requirements=URL_NAME_REQUIREMENTS)
521 requirements=URL_NAME_REQUIREMENTS)
551 rmap.connect('repo_issuetracker_save',
522 rmap.connect('repo_issuetracker_save',
552 '/{repo_name}/settings/issue-tracker/save',
523 '/{repo_name}/settings/issue-tracker/save',
553 controller='admin/repos', action='repo_issuetracker_save',
524 controller='admin/repos', action='repo_issuetracker_save',
554 conditions={'method': ['POST'], 'function': check_repo},
525 conditions={'method': ['POST'], 'function': check_repo},
555 requirements=URL_NAME_REQUIREMENTS)
526 requirements=URL_NAME_REQUIREMENTS)
556 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
527 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
557 controller='admin/repos', action='repo_settings_vcs_update',
528 controller='admin/repos', action='repo_settings_vcs_update',
558 conditions={'method': ['POST'], 'function': check_repo},
529 conditions={'method': ['POST'], 'function': check_repo},
559 requirements=URL_NAME_REQUIREMENTS)
530 requirements=URL_NAME_REQUIREMENTS)
560 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
531 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
561 controller='admin/repos', action='repo_settings_vcs',
532 controller='admin/repos', action='repo_settings_vcs',
562 conditions={'method': ['GET'], 'function': check_repo},
533 conditions={'method': ['GET'], 'function': check_repo},
563 requirements=URL_NAME_REQUIREMENTS)
534 requirements=URL_NAME_REQUIREMENTS)
564 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
535 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
565 controller='admin/repos', action='repo_delete_svn_pattern',
536 controller='admin/repos', action='repo_delete_svn_pattern',
566 conditions={'method': ['DELETE'], 'function': check_repo},
537 conditions={'method': ['DELETE'], 'function': check_repo},
567 requirements=URL_NAME_REQUIREMENTS)
538 requirements=URL_NAME_REQUIREMENTS)
568 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
539 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
569 controller='admin/repos', action='repo_settings_pullrequest',
540 controller='admin/repos', action='repo_settings_pullrequest',
570 conditions={'method': ['GET', 'POST'], 'function': check_repo},
541 conditions={'method': ['GET', 'POST'], 'function': check_repo},
571 requirements=URL_NAME_REQUIREMENTS)
542 requirements=URL_NAME_REQUIREMENTS)
572
543
573 # still working url for backward compat.
544 # still working url for backward compat.
574 rmap.connect('raw_changeset_home_depraced',
545 rmap.connect('raw_changeset_home_depraced',
575 '/{repo_name}/raw-changeset/{revision}',
546 '/{repo_name}/raw-changeset/{revision}',
576 controller='changeset', action='changeset_raw',
547 controller='changeset', action='changeset_raw',
577 revision='tip', conditions={'function': check_repo},
548 revision='tip', conditions={'function': check_repo},
578 requirements=URL_NAME_REQUIREMENTS)
549 requirements=URL_NAME_REQUIREMENTS)
579
550
580 # new URLs
551 # new URLs
581 rmap.connect('changeset_raw_home',
552 rmap.connect('changeset_raw_home',
582 '/{repo_name}/changeset-diff/{revision}',
553 '/{repo_name}/changeset-diff/{revision}',
583 controller='changeset', action='changeset_raw',
554 controller='changeset', action='changeset_raw',
584 revision='tip', conditions={'function': check_repo},
555 revision='tip', conditions={'function': check_repo},
585 requirements=URL_NAME_REQUIREMENTS)
556 requirements=URL_NAME_REQUIREMENTS)
586
557
587 rmap.connect('changeset_patch_home',
558 rmap.connect('changeset_patch_home',
588 '/{repo_name}/changeset-patch/{revision}',
559 '/{repo_name}/changeset-patch/{revision}',
589 controller='changeset', action='changeset_patch',
560 controller='changeset', action='changeset_patch',
590 revision='tip', conditions={'function': check_repo},
561 revision='tip', conditions={'function': check_repo},
591 requirements=URL_NAME_REQUIREMENTS)
562 requirements=URL_NAME_REQUIREMENTS)
592
563
593 rmap.connect('changeset_download_home',
564 rmap.connect('changeset_download_home',
594 '/{repo_name}/changeset-download/{revision}',
565 '/{repo_name}/changeset-download/{revision}',
595 controller='changeset', action='changeset_download',
566 controller='changeset', action='changeset_download',
596 revision='tip', conditions={'function': check_repo},
567 revision='tip', conditions={'function': check_repo},
597 requirements=URL_NAME_REQUIREMENTS)
568 requirements=URL_NAME_REQUIREMENTS)
598
569
599 rmap.connect('changeset_comment',
570 rmap.connect('changeset_comment',
600 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
571 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
601 controller='changeset', revision='tip', action='comment',
572 controller='changeset', revision='tip', action='comment',
602 conditions={'function': check_repo},
573 conditions={'function': check_repo},
603 requirements=URL_NAME_REQUIREMENTS)
574 requirements=URL_NAME_REQUIREMENTS)
604
575
605 rmap.connect('changeset_comment_preview',
576 rmap.connect('changeset_comment_preview',
606 '/{repo_name}/changeset/comment/preview', jsroute=True,
577 '/{repo_name}/changeset/comment/preview', jsroute=True,
607 controller='changeset', action='preview_comment',
578 controller='changeset', action='preview_comment',
608 conditions={'function': check_repo, 'method': ['POST']},
579 conditions={'function': check_repo, 'method': ['POST']},
609 requirements=URL_NAME_REQUIREMENTS)
580 requirements=URL_NAME_REQUIREMENTS)
610
581
611 rmap.connect('changeset_comment_delete',
582 rmap.connect('changeset_comment_delete',
612 '/{repo_name}/changeset/comment/{comment_id}/delete',
583 '/{repo_name}/changeset/comment/{comment_id}/delete',
613 controller='changeset', action='delete_comment',
584 controller='changeset', action='delete_comment',
614 conditions={'function': check_repo, 'method': ['DELETE']},
585 conditions={'function': check_repo, 'method': ['DELETE']},
615 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
586 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
616
587
617 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
588 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
618 controller='changeset', action='changeset_info',
589 controller='changeset', action='changeset_info',
619 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
590 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
620
591
621 rmap.connect('compare_home',
592 rmap.connect('compare_home',
622 '/{repo_name}/compare',
593 '/{repo_name}/compare',
623 controller='compare', action='index',
594 controller='compare', action='index',
624 conditions={'function': check_repo},
595 conditions={'function': check_repo},
625 requirements=URL_NAME_REQUIREMENTS)
596 requirements=URL_NAME_REQUIREMENTS)
626
597
627 rmap.connect('compare_url',
598 rmap.connect('compare_url',
628 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
599 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
629 controller='compare', action='compare',
600 controller='compare', action='compare',
630 conditions={'function': check_repo},
601 conditions={'function': check_repo},
631 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
602 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
632
603
633 rmap.connect('pullrequest_home',
604 rmap.connect('pullrequest_home',
634 '/{repo_name}/pull-request/new', controller='pullrequests',
605 '/{repo_name}/pull-request/new', controller='pullrequests',
635 action='index', conditions={'function': check_repo,
606 action='index', conditions={'function': check_repo,
636 'method': ['GET']},
607 'method': ['GET']},
637 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
608 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
638
609
639 rmap.connect('pullrequest',
610 rmap.connect('pullrequest',
640 '/{repo_name}/pull-request/new', controller='pullrequests',
611 '/{repo_name}/pull-request/new', controller='pullrequests',
641 action='create', conditions={'function': check_repo,
612 action='create', conditions={'function': check_repo,
642 'method': ['POST']},
613 'method': ['POST']},
643 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
614 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
644
615
645 rmap.connect('pullrequest_repo_refs',
616 rmap.connect('pullrequest_repo_refs',
646 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
617 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
647 controller='pullrequests',
618 controller='pullrequests',
648 action='get_repo_refs',
619 action='get_repo_refs',
649 conditions={'function': check_repo, 'method': ['GET']},
620 conditions={'function': check_repo, 'method': ['GET']},
650 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
621 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
651
622
652 rmap.connect('pullrequest_repo_destinations',
623 rmap.connect('pullrequest_repo_destinations',
653 '/{repo_name}/pull-request/repo-destinations',
624 '/{repo_name}/pull-request/repo-destinations',
654 controller='pullrequests',
625 controller='pullrequests',
655 action='get_repo_destinations',
626 action='get_repo_destinations',
656 conditions={'function': check_repo, 'method': ['GET']},
627 conditions={'function': check_repo, 'method': ['GET']},
657 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
628 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
658
629
659 rmap.connect('pullrequest_show',
630 rmap.connect('pullrequest_show',
660 '/{repo_name}/pull-request/{pull_request_id}',
631 '/{repo_name}/pull-request/{pull_request_id}',
661 controller='pullrequests',
632 controller='pullrequests',
662 action='show', conditions={'function': check_repo,
633 action='show', conditions={'function': check_repo,
663 'method': ['GET']},
634 'method': ['GET']},
664 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
635 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
665
636
666 rmap.connect('pullrequest_update',
637 rmap.connect('pullrequest_update',
667 '/{repo_name}/pull-request/{pull_request_id}',
638 '/{repo_name}/pull-request/{pull_request_id}',
668 controller='pullrequests',
639 controller='pullrequests',
669 action='update', conditions={'function': check_repo,
640 action='update', conditions={'function': check_repo,
670 'method': ['PUT']},
641 'method': ['PUT']},
671 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
642 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
672
643
673 rmap.connect('pullrequest_merge',
644 rmap.connect('pullrequest_merge',
674 '/{repo_name}/pull-request/{pull_request_id}',
645 '/{repo_name}/pull-request/{pull_request_id}',
675 controller='pullrequests',
646 controller='pullrequests',
676 action='merge', conditions={'function': check_repo,
647 action='merge', conditions={'function': check_repo,
677 'method': ['POST']},
648 'method': ['POST']},
678 requirements=URL_NAME_REQUIREMENTS)
649 requirements=URL_NAME_REQUIREMENTS)
679
650
680 rmap.connect('pullrequest_delete',
651 rmap.connect('pullrequest_delete',
681 '/{repo_name}/pull-request/{pull_request_id}',
652 '/{repo_name}/pull-request/{pull_request_id}',
682 controller='pullrequests',
653 controller='pullrequests',
683 action='delete', conditions={'function': check_repo,
654 action='delete', conditions={'function': check_repo,
684 'method': ['DELETE']},
655 'method': ['DELETE']},
685 requirements=URL_NAME_REQUIREMENTS)
656 requirements=URL_NAME_REQUIREMENTS)
686
657
687 rmap.connect('pullrequest_comment',
658 rmap.connect('pullrequest_comment',
688 '/{repo_name}/pull-request-comment/{pull_request_id}',
659 '/{repo_name}/pull-request-comment/{pull_request_id}',
689 controller='pullrequests',
660 controller='pullrequests',
690 action='comment', conditions={'function': check_repo,
661 action='comment', conditions={'function': check_repo,
691 'method': ['POST']},
662 'method': ['POST']},
692 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
663 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
693
664
694 rmap.connect('pullrequest_comment_delete',
665 rmap.connect('pullrequest_comment_delete',
695 '/{repo_name}/pull-request-comment/{comment_id}/delete',
666 '/{repo_name}/pull-request-comment/{comment_id}/delete',
696 controller='pullrequests', action='delete_comment',
667 controller='pullrequests', action='delete_comment',
697 conditions={'function': check_repo, 'method': ['DELETE']},
668 conditions={'function': check_repo, 'method': ['DELETE']},
698 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
669 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
699
670
700 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
671 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
701 controller='forks', action='fork_create',
672 controller='forks', action='fork_create',
702 conditions={'function': check_repo, 'method': ['POST']},
673 conditions={'function': check_repo, 'method': ['POST']},
703 requirements=URL_NAME_REQUIREMENTS)
674 requirements=URL_NAME_REQUIREMENTS)
704
675
705 rmap.connect('repo_fork_home', '/{repo_name}/fork',
676 rmap.connect('repo_fork_home', '/{repo_name}/fork',
706 controller='forks', action='fork',
677 controller='forks', action='fork',
707 conditions={'function': check_repo},
678 conditions={'function': check_repo},
708 requirements=URL_NAME_REQUIREMENTS)
679 requirements=URL_NAME_REQUIREMENTS)
709
680
710 rmap.connect('repo_forks_home', '/{repo_name}/forks',
681 rmap.connect('repo_forks_home', '/{repo_name}/forks',
711 controller='forks', action='forks',
682 controller='forks', action='forks',
712 conditions={'function': check_repo},
683 conditions={'function': check_repo},
713 requirements=URL_NAME_REQUIREMENTS)
684 requirements=URL_NAME_REQUIREMENTS)
714
685
715 return rmap
686 return rmap
@@ -1,198 +1,206 b''
1
1
2 /******************************************************************************
2 /******************************************************************************
3 * *
3 * *
4 * DO NOT CHANGE THIS FILE MANUALLY *
4 * DO NOT CHANGE THIS FILE MANUALLY *
5 * *
5 * *
6 * *
6 * *
7 * This file is automatically generated when the app starts up with *
7 * This file is automatically generated when the app starts up with *
8 * generate_js_files = true *
8 * generate_js_files = true *
9 * *
9 * *
10 * To add a route here pass jsroute=True to the route definition in the app *
10 * To add a route here pass jsroute=True to the route definition in the app *
11 * *
11 * *
12 ******************************************************************************/
12 ******************************************************************************/
13 function registerRCRoutes() {
13 function registerRCRoutes() {
14 // routes registration
14 // routes registration
15 pyroutes.register('new_repo', '/_admin/create_repository', []);
15 pyroutes.register('new_repo', '/_admin/create_repository', []);
16 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
16 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
17 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
17 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
18 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
19 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
18 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
20 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
19 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
21 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
20 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
22 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
21 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
23 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
22 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
24 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']);
23 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']);
25 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
24 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
26 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
25 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
27 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
26 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
28 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
27 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
29 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
28 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
30 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
29 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
31 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
30 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
32 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
31 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
33 pyroutes.register('favicon', '/favicon.ico', []);
32 pyroutes.register('favicon', '/favicon.ico', []);
34 pyroutes.register('robots', '/robots.txt', []);
33 pyroutes.register('robots', '/robots.txt', []);
35 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
34 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
36 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
35 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
37 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
36 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
38 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
37 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
39 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
38 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
40 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
39 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
41 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/settings/integrations', ['repo_group_name']);
40 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/settings/integrations', ['repo_group_name']);
42 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
41 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
43 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
42 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
44 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
43 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
45 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
44 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
46 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
45 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
47 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
46 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
48 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
47 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
49 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
48 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
50 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
49 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
51 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
50 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
52 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
51 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
53 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
52 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
54 pyroutes.register('admin_home', '/_admin', []);
53 pyroutes.register('admin_home', '/_admin', []);
55 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
54 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
56 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
55 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
57 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
56 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
58 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
57 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
59 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
58 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
60 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
59 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
61 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
60 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
62 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
61 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
63 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
62 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
64 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
63 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
65 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
64 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
66 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
65 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
67 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
66 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
68 pyroutes.register('users', '/_admin/users', []);
67 pyroutes.register('users', '/_admin/users', []);
69 pyroutes.register('users_data', '/_admin/users_data', []);
68 pyroutes.register('users_data', '/_admin/users_data', []);
70 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
69 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
71 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
70 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
72 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
71 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
73 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
72 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
74 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
73 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
75 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
74 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
76 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
75 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
77 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
76 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
78 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
77 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
79 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
78 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
80 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
79 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
81 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
80 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
82 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
81 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
83 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
82 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
84 pyroutes.register('channelstream_proxy', '/_channelstream', []);
83 pyroutes.register('channelstream_proxy', '/_channelstream', []);
85 pyroutes.register('login', '/_admin/login', []);
84 pyroutes.register('login', '/_admin/login', []);
86 pyroutes.register('logout', '/_admin/logout', []);
85 pyroutes.register('logout', '/_admin/logout', []);
87 pyroutes.register('register', '/_admin/register', []);
86 pyroutes.register('register', '/_admin/register', []);
88 pyroutes.register('reset_password', '/_admin/password_reset', []);
87 pyroutes.register('reset_password', '/_admin/password_reset', []);
89 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
88 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
90 pyroutes.register('home', '/', []);
89 pyroutes.register('home', '/', []);
91 pyroutes.register('user_autocomplete_data', '/_users', []);
90 pyroutes.register('user_autocomplete_data', '/_users', []);
92 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
91 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
93 pyroutes.register('repo_list_data', '/_repos', []);
92 pyroutes.register('repo_list_data', '/_repos', []);
94 pyroutes.register('goto_switcher_data', '/_goto_data', []);
93 pyroutes.register('goto_switcher_data', '/_goto_data', []);
94 pyroutes.register('journal', '/_admin/journal', []);
95 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
96 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
97 pyroutes.register('journal_public', '/_admin/public_journal', []);
98 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
99 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
100 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
101 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
102 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
95 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
103 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
96 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
104 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
97 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
105 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
98 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
106 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
99 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
107 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
100 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
108 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
101 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
109 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
102 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
110 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
103 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
111 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
104 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
112 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
105 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
113 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
106 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
114 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
107 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
115 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
108 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
116 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
109 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
117 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
110 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
118 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
111 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
119 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
112 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
120 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
113 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
121 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
114 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
122 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
115 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
123 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
116 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
124 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
117 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
125 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
118 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
126 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
119 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
127 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
120 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
128 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
121 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
129 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
122 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
130 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
123 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
131 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
124 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
132 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
125 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
133 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
126 pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']);
134 pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']);
127 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
135 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
128 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
136 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
129 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
137 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
130 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
138 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
131 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
139 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
132 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
140 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
133 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
141 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
134 pyroutes.register('changeset_children', '/%(repo_name)s/changeset_children/%(revision)s', ['repo_name', 'revision']);
142 pyroutes.register('changeset_children', '/%(repo_name)s/changeset_children/%(revision)s', ['repo_name', 'revision']);
135 pyroutes.register('changeset_parents', '/%(repo_name)s/changeset_parents/%(revision)s', ['repo_name', 'revision']);
143 pyroutes.register('changeset_parents', '/%(repo_name)s/changeset_parents/%(revision)s', ['repo_name', 'revision']);
136 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
144 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
137 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
145 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
138 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
146 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
139 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
147 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
140 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
148 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
141 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
149 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
142 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
150 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
143 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
151 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
144 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
152 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
145 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
153 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
146 pyroutes.register('repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
154 pyroutes.register('repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
147 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
155 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
148 pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']);
156 pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']);
149 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
157 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
150 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
158 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
151 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']);
159 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']);
152 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
160 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
153 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
161 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
154 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
162 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
155 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
163 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
156 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
164 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
157 pyroutes.register('search', '/_admin/search', []);
165 pyroutes.register('search', '/_admin/search', []);
158 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
166 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
159 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
167 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
160 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
168 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
161 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
169 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
162 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
170 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
163 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
171 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
164 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
172 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
165 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
173 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
166 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
174 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
167 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
175 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
168 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
176 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
169 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
177 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
170 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
178 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
171 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
179 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
172 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
180 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
173 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
181 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
174 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
182 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
175 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
183 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
176 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
184 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
177 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
185 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
178 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
186 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
179 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
187 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
180 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
188 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
181 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
189 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
182 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
190 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
183 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
191 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
184 pyroutes.register('gists_show', '/_admin/gists', []);
192 pyroutes.register('gists_show', '/_admin/gists', []);
185 pyroutes.register('gists_new', '/_admin/gists/new', []);
193 pyroutes.register('gists_new', '/_admin/gists/new', []);
186 pyroutes.register('gists_create', '/_admin/gists/create', []);
194 pyroutes.register('gists_create', '/_admin/gists/create', []);
187 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
195 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
188 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
196 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
189 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
197 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
190 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
198 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
191 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
199 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
192 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
200 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
193 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
201 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
194 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
202 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
195 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
203 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
196 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
204 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
197 pyroutes.register('apiv2', '/_admin/api', []);
205 pyroutes.register('apiv2', '/_admin/api', []);
198 }
206 }
@@ -1,600 +1,600 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.mako"/>
2 <%inherit file="root.mako"/>
3
3
4 <div class="outerwrapper">
4 <div class="outerwrapper">
5 <!-- HEADER -->
5 <!-- HEADER -->
6 <div class="header">
6 <div class="header">
7 <div id="header-inner" class="wrapper">
7 <div id="header-inner" class="wrapper">
8 <div id="logo">
8 <div id="logo">
9 <div class="logo-wrapper">
9 <div class="logo-wrapper">
10 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
10 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
11 </div>
11 </div>
12 %if c.rhodecode_name:
12 %if c.rhodecode_name:
13 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
13 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
14 %endif
14 %endif
15 </div>
15 </div>
16 <!-- MENU BAR NAV -->
16 <!-- MENU BAR NAV -->
17 ${self.menu_bar_nav()}
17 ${self.menu_bar_nav()}
18 <!-- END MENU BAR NAV -->
18 <!-- END MENU BAR NAV -->
19 </div>
19 </div>
20 </div>
20 </div>
21 ${self.menu_bar_subnav()}
21 ${self.menu_bar_subnav()}
22 <!-- END HEADER -->
22 <!-- END HEADER -->
23
23
24 <!-- CONTENT -->
24 <!-- CONTENT -->
25 <div id="content" class="wrapper">
25 <div id="content" class="wrapper">
26
26
27 <rhodecode-toast id="notifications"></rhodecode-toast>
27 <rhodecode-toast id="notifications"></rhodecode-toast>
28
28
29 <div class="main">
29 <div class="main">
30 ${next.main()}
30 ${next.main()}
31 </div>
31 </div>
32 </div>
32 </div>
33 <!-- END CONTENT -->
33 <!-- END CONTENT -->
34
34
35 </div>
35 </div>
36 <!-- FOOTER -->
36 <!-- FOOTER -->
37 <div id="footer">
37 <div id="footer">
38 <div id="footer-inner" class="title wrapper">
38 <div id="footer-inner" class="title wrapper">
39 <div>
39 <div>
40 <p class="footer-link-right">
40 <p class="footer-link-right">
41 % if c.visual.show_version:
41 % if c.visual.show_version:
42 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
42 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
43 % endif
43 % endif
44 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
44 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
45 % if c.visual.rhodecode_support_url:
45 % if c.visual.rhodecode_support_url:
46 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
46 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
47 % endif
47 % endif
48 </p>
48 </p>
49 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
49 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
50 <p class="server-instance" style="display:${sid}">
50 <p class="server-instance" style="display:${sid}">
51 ## display hidden instance ID if specially defined
51 ## display hidden instance ID if specially defined
52 % if c.rhodecode_instanceid:
52 % if c.rhodecode_instanceid:
53 ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid}
53 ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid}
54 % endif
54 % endif
55 </p>
55 </p>
56 </div>
56 </div>
57 </div>
57 </div>
58 </div>
58 </div>
59
59
60 <!-- END FOOTER -->
60 <!-- END FOOTER -->
61
61
62 ### MAKO DEFS ###
62 ### MAKO DEFS ###
63
63
64 <%def name="menu_bar_subnav()">
64 <%def name="menu_bar_subnav()">
65 </%def>
65 </%def>
66
66
67 <%def name="breadcrumbs(class_='breadcrumbs')">
67 <%def name="breadcrumbs(class_='breadcrumbs')">
68 <div class="${class_}">
68 <div class="${class_}">
69 ${self.breadcrumbs_links()}
69 ${self.breadcrumbs_links()}
70 </div>
70 </div>
71 </%def>
71 </%def>
72
72
73 <%def name="admin_menu()">
73 <%def name="admin_menu()">
74 <ul class="admin_menu submenu">
74 <ul class="admin_menu submenu">
75 <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
75 <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
76 <li><a href="${h.url('repos')}">${_('Repositories')}</a></li>
76 <li><a href="${h.url('repos')}">${_('Repositories')}</a></li>
77 <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
77 <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
78 <li><a href="${h.route_path('users')}">${_('Users')}</a></li>
78 <li><a href="${h.route_path('users')}">${_('Users')}</a></li>
79 <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
79 <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
80 <li><a href="${h.url('admin_permissions_application')}">${_('Permissions')}</a></li>
80 <li><a href="${h.url('admin_permissions_application')}">${_('Permissions')}</a></li>
81 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
81 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
82 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
82 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
83 <li><a href="${h.url('admin_defaults_repositories')}">${_('Defaults')}</a></li>
83 <li><a href="${h.url('admin_defaults_repositories')}">${_('Defaults')}</a></li>
84 <li class="last"><a href="${h.url('admin_settings')}">${_('Settings')}</a></li>
84 <li class="last"><a href="${h.url('admin_settings')}">${_('Settings')}</a></li>
85 </ul>
85 </ul>
86 </%def>
86 </%def>
87
87
88
88
89 <%def name="dt_info_panel(elements)">
89 <%def name="dt_info_panel(elements)">
90 <dl class="dl-horizontal">
90 <dl class="dl-horizontal">
91 %for dt, dd, title, show_items in elements:
91 %for dt, dd, title, show_items in elements:
92 <dt>${dt}:</dt>
92 <dt>${dt}:</dt>
93 <dd title="${h.tooltip(title)}">
93 <dd title="${h.tooltip(title)}">
94 %if callable(dd):
94 %if callable(dd):
95 ## allow lazy evaluation of elements
95 ## allow lazy evaluation of elements
96 ${dd()}
96 ${dd()}
97 %else:
97 %else:
98 ${dd}
98 ${dd}
99 %endif
99 %endif
100 %if show_items:
100 %if show_items:
101 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
101 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
102 %endif
102 %endif
103 </dd>
103 </dd>
104
104
105 %if show_items:
105 %if show_items:
106 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
106 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
107 %for item in show_items:
107 %for item in show_items:
108 <dt></dt>
108 <dt></dt>
109 <dd>${item}</dd>
109 <dd>${item}</dd>
110 %endfor
110 %endfor
111 </div>
111 </div>
112 %endif
112 %endif
113
113
114 %endfor
114 %endfor
115 </dl>
115 </dl>
116 </%def>
116 </%def>
117
117
118
118
119 <%def name="gravatar(email, size=16)">
119 <%def name="gravatar(email, size=16)">
120 <%
120 <%
121 if (size > 16):
121 if (size > 16):
122 gravatar_class = 'gravatar gravatar-large'
122 gravatar_class = 'gravatar gravatar-large'
123 else:
123 else:
124 gravatar_class = 'gravatar'
124 gravatar_class = 'gravatar'
125 %>
125 %>
126 <%doc>
126 <%doc>
127 TODO: johbo: For now we serve double size images to make it smooth
127 TODO: johbo: For now we serve double size images to make it smooth
128 for retina. This is how it worked until now. Should be replaced
128 for retina. This is how it worked until now. Should be replaced
129 with a better solution at some point.
129 with a better solution at some point.
130 </%doc>
130 </%doc>
131 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
131 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
132 </%def>
132 </%def>
133
133
134
134
135 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
135 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
136 <% email = h.email_or_none(contact) %>
136 <% email = h.email_or_none(contact) %>
137 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
137 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
138 ${self.gravatar(email, size)}
138 ${self.gravatar(email, size)}
139 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
139 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
140 </div>
140 </div>
141 </%def>
141 </%def>
142
142
143
143
144 ## admin menu used for people that have some admin resources
144 ## admin menu used for people that have some admin resources
145 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
145 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
146 <ul class="submenu">
146 <ul class="submenu">
147 %if repositories:
147 %if repositories:
148 <li class="local-admin-repos"><a href="${h.url('repos')}">${_('Repositories')}</a></li>
148 <li class="local-admin-repos"><a href="${h.url('repos')}">${_('Repositories')}</a></li>
149 %endif
149 %endif
150 %if repository_groups:
150 %if repository_groups:
151 <li class="local-admin-repo-groups"><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
151 <li class="local-admin-repo-groups"><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
152 %endif
152 %endif
153 %if user_groups:
153 %if user_groups:
154 <li class="local-admin-user-groups"><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
154 <li class="local-admin-user-groups"><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
155 %endif
155 %endif
156 </ul>
156 </ul>
157 </%def>
157 </%def>
158
158
159 <%def name="repo_page_title(repo_instance)">
159 <%def name="repo_page_title(repo_instance)">
160 <div class="title-content">
160 <div class="title-content">
161 <div class="title-main">
161 <div class="title-main">
162 ## SVN/HG/GIT icons
162 ## SVN/HG/GIT icons
163 %if h.is_hg(repo_instance):
163 %if h.is_hg(repo_instance):
164 <i class="icon-hg"></i>
164 <i class="icon-hg"></i>
165 %endif
165 %endif
166 %if h.is_git(repo_instance):
166 %if h.is_git(repo_instance):
167 <i class="icon-git"></i>
167 <i class="icon-git"></i>
168 %endif
168 %endif
169 %if h.is_svn(repo_instance):
169 %if h.is_svn(repo_instance):
170 <i class="icon-svn"></i>
170 <i class="icon-svn"></i>
171 %endif
171 %endif
172
172
173 ## public/private
173 ## public/private
174 %if repo_instance.private:
174 %if repo_instance.private:
175 <i class="icon-repo-private"></i>
175 <i class="icon-repo-private"></i>
176 %else:
176 %else:
177 <i class="icon-repo-public"></i>
177 <i class="icon-repo-public"></i>
178 %endif
178 %endif
179
179
180 ## repo name with group name
180 ## repo name with group name
181 ${h.breadcrumb_repo_link(c.rhodecode_db_repo)}
181 ${h.breadcrumb_repo_link(c.rhodecode_db_repo)}
182
182
183 </div>
183 </div>
184
184
185 ## FORKED
185 ## FORKED
186 %if repo_instance.fork:
186 %if repo_instance.fork:
187 <p>
187 <p>
188 <i class="icon-code-fork"></i> ${_('Fork of')}
188 <i class="icon-code-fork"></i> ${_('Fork of')}
189 <a href="${h.route_path('repo_summary',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
189 <a href="${h.route_path('repo_summary',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
190 </p>
190 </p>
191 %endif
191 %endif
192
192
193 ## IMPORTED FROM REMOTE
193 ## IMPORTED FROM REMOTE
194 %if repo_instance.clone_uri:
194 %if repo_instance.clone_uri:
195 <p>
195 <p>
196 <i class="icon-code-fork"></i> ${_('Clone from')}
196 <i class="icon-code-fork"></i> ${_('Clone from')}
197 <a href="${h.url(h.safe_str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
197 <a href="${h.url(h.safe_str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
198 </p>
198 </p>
199 %endif
199 %endif
200
200
201 ## LOCKING STATUS
201 ## LOCKING STATUS
202 %if repo_instance.locked[0]:
202 %if repo_instance.locked[0]:
203 <p class="locking_locked">
203 <p class="locking_locked">
204 <i class="icon-repo-lock"></i>
204 <i class="icon-repo-lock"></i>
205 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
205 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
206 </p>
206 </p>
207 %elif repo_instance.enable_locking:
207 %elif repo_instance.enable_locking:
208 <p class="locking_unlocked">
208 <p class="locking_unlocked">
209 <i class="icon-repo-unlock"></i>
209 <i class="icon-repo-unlock"></i>
210 ${_('Repository not locked. Pull repository to lock it.')}
210 ${_('Repository not locked. Pull repository to lock it.')}
211 </p>
211 </p>
212 %endif
212 %endif
213
213
214 </div>
214 </div>
215 </%def>
215 </%def>
216
216
217 <%def name="repo_menu(active=None)">
217 <%def name="repo_menu(active=None)">
218 <%
218 <%
219 def is_active(selected):
219 def is_active(selected):
220 if selected == active:
220 if selected == active:
221 return "active"
221 return "active"
222 %>
222 %>
223
223
224 <!--- CONTEXT BAR -->
224 <!--- CONTEXT BAR -->
225 <div id="context-bar">
225 <div id="context-bar">
226 <div class="wrapper">
226 <div class="wrapper">
227 <ul id="context-pages" class="horizontal-list navigation">
227 <ul id="context-pages" class="horizontal-list navigation">
228 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
228 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
229 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
229 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
230 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
230 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
231 <li class="${is_active('compare')}">
231 <li class="${is_active('compare')}">
232 <a class="menulink" href="${h.url('compare_home',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a>
232 <a class="menulink" href="${h.url('compare_home',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a>
233 </li>
233 </li>
234 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
234 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
235 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
235 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
236 <li class="${is_active('showpullrequest')}">
236 <li class="${is_active('showpullrequest')}">
237 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
237 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
238 %if c.repository_pull_requests:
238 %if c.repository_pull_requests:
239 <span class="pr_notifications">${c.repository_pull_requests}</span>
239 <span class="pr_notifications">${c.repository_pull_requests}</span>
240 %endif
240 %endif
241 <div class="menulabel">${_('Pull Requests')}</div>
241 <div class="menulabel">${_('Pull Requests')}</div>
242 </a>
242 </a>
243 </li>
243 </li>
244 %endif
244 %endif
245 <li class="${is_active('options')}">
245 <li class="${is_active('options')}">
246 <a class="menulink dropdown">
246 <a class="menulink dropdown">
247 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
247 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
248 </a>
248 </a>
249 <ul class="submenu">
249 <ul class="submenu">
250 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
250 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
251 <li><a href="${h.route_path('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
251 <li><a href="${h.route_path('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
252 %endif
252 %endif
253 %if c.rhodecode_db_repo.fork:
253 %if c.rhodecode_db_repo.fork:
254 <li><a href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1], target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1], merge=1)}">
254 <li><a href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1], target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1], merge=1)}">
255 ${_('Compare fork')}</a></li>
255 ${_('Compare fork')}</a></li>
256 %endif
256 %endif
257
257
258 <li><a href="${h.route_path('search_repo',repo_name=c.repo_name)}">${_('Search')}</a></li>
258 <li><a href="${h.route_path('search_repo',repo_name=c.repo_name)}">${_('Search')}</a></li>
259
259
260 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
260 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
261 %if c.rhodecode_db_repo.locked[0]:
261 %if c.rhodecode_db_repo.locked[0]:
262 <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
262 <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
263 %else:
263 %else:
264 <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
264 <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
265 %endif
265 %endif
266 %endif
266 %endif
267 %if c.rhodecode_user.username != h.DEFAULT_USER:
267 %if c.rhodecode_user.username != h.DEFAULT_USER:
268 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
268 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
269 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
269 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
270 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
270 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
271 %endif
271 %endif
272 %endif
272 %endif
273 </ul>
273 </ul>
274 </li>
274 </li>
275 </ul>
275 </ul>
276 </div>
276 </div>
277 <div class="clear"></div>
277 <div class="clear"></div>
278 </div>
278 </div>
279 <!--- END CONTEXT BAR -->
279 <!--- END CONTEXT BAR -->
280
280
281 </%def>
281 </%def>
282
282
283 <%def name="usermenu(active=False)">
283 <%def name="usermenu(active=False)">
284 ## USER MENU
284 ## USER MENU
285 <li id="quick_login_li" class="${'active' if active else ''}">
285 <li id="quick_login_li" class="${'active' if active else ''}">
286 <a id="quick_login_link" class="menulink childs">
286 <a id="quick_login_link" class="menulink childs">
287 ${gravatar(c.rhodecode_user.email, 20)}
287 ${gravatar(c.rhodecode_user.email, 20)}
288 <span class="user">
288 <span class="user">
289 %if c.rhodecode_user.username != h.DEFAULT_USER:
289 %if c.rhodecode_user.username != h.DEFAULT_USER:
290 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
290 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
291 %else:
291 %else:
292 <span>${_('Sign in')}</span>
292 <span>${_('Sign in')}</span>
293 %endif
293 %endif
294 </span>
294 </span>
295 </a>
295 </a>
296
296
297 <div class="user-menu submenu">
297 <div class="user-menu submenu">
298 <div id="quick_login">
298 <div id="quick_login">
299 %if c.rhodecode_user.username == h.DEFAULT_USER:
299 %if c.rhodecode_user.username == h.DEFAULT_USER:
300 <h4>${_('Sign in to your account')}</h4>
300 <h4>${_('Sign in to your account')}</h4>
301 ${h.form(h.route_path('login', _query={'came_from': h.url.current()}), needs_csrf_token=False)}
301 ${h.form(h.route_path('login', _query={'came_from': h.url.current()}), needs_csrf_token=False)}
302 <div class="form form-vertical">
302 <div class="form form-vertical">
303 <div class="fields">
303 <div class="fields">
304 <div class="field">
304 <div class="field">
305 <div class="label">
305 <div class="label">
306 <label for="username">${_('Username')}:</label>
306 <label for="username">${_('Username')}:</label>
307 </div>
307 </div>
308 <div class="input">
308 <div class="input">
309 ${h.text('username',class_='focus',tabindex=1)}
309 ${h.text('username',class_='focus',tabindex=1)}
310 </div>
310 </div>
311
311
312 </div>
312 </div>
313 <div class="field">
313 <div class="field">
314 <div class="label">
314 <div class="label">
315 <label for="password">${_('Password')}:</label>
315 <label for="password">${_('Password')}:</label>
316 %if h.HasPermissionAny('hg.password_reset.enabled')():
316 %if h.HasPermissionAny('hg.password_reset.enabled')():
317 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'), class_='pwd_reset')}</span>
317 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'), class_='pwd_reset')}</span>
318 %endif
318 %endif
319 </div>
319 </div>
320 <div class="input">
320 <div class="input">
321 ${h.password('password',class_='focus',tabindex=2)}
321 ${h.password('password',class_='focus',tabindex=2)}
322 </div>
322 </div>
323 </div>
323 </div>
324 <div class="buttons">
324 <div class="buttons">
325 <div class="register">
325 <div class="register">
326 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
326 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
327 ${h.link_to(_("Don't have an account?"),h.route_path('register'))} <br/>
327 ${h.link_to(_("Don't have an account?"),h.route_path('register'))} <br/>
328 %endif
328 %endif
329 ${h.link_to(_("Using external auth? Sign In here."),h.route_path('login'))}
329 ${h.link_to(_("Using external auth? Sign In here."),h.route_path('login'))}
330 </div>
330 </div>
331 <div class="submit">
331 <div class="submit">
332 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
332 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
333 </div>
333 </div>
334 </div>
334 </div>
335 </div>
335 </div>
336 </div>
336 </div>
337 ${h.end_form()}
337 ${h.end_form()}
338 %else:
338 %else:
339 <div class="">
339 <div class="">
340 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
340 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
341 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
341 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
342 <div class="email">${c.rhodecode_user.email}</div>
342 <div class="email">${c.rhodecode_user.email}</div>
343 </div>
343 </div>
344 <div class="">
344 <div class="">
345 <ol class="links">
345 <ol class="links">
346 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
346 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
347 % if c.rhodecode_user.personal_repo_group:
347 % if c.rhodecode_user.personal_repo_group:
348 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
348 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
349 % endif
349 % endif
350 <li class="logout">
350 <li class="logout">
351 ${h.secure_form(h.route_path('logout'), request=request)}
351 ${h.secure_form(h.route_path('logout'), request=request)}
352 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
352 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
353 ${h.end_form()}
353 ${h.end_form()}
354 </li>
354 </li>
355 </ol>
355 </ol>
356 </div>
356 </div>
357 %endif
357 %endif
358 </div>
358 </div>
359 </div>
359 </div>
360 %if c.rhodecode_user.username != h.DEFAULT_USER:
360 %if c.rhodecode_user.username != h.DEFAULT_USER:
361 <div class="pill_container">
361 <div class="pill_container">
362 <a class="menu_link_notifications ${'empty' if c.unread_notifications == 0 else ''}" href="${h.route_path('notifications_show_all')}">${c.unread_notifications}</a>
362 <a class="menu_link_notifications ${'empty' if c.unread_notifications == 0 else ''}" href="${h.route_path('notifications_show_all')}">${c.unread_notifications}</a>
363 </div>
363 </div>
364 % endif
364 % endif
365 </li>
365 </li>
366 </%def>
366 </%def>
367
367
368 <%def name="menu_items(active=None)">
368 <%def name="menu_items(active=None)">
369 <%
369 <%
370 def is_active(selected):
370 def is_active(selected):
371 if selected == active:
371 if selected == active:
372 return "active"
372 return "active"
373 return ""
373 return ""
374 %>
374 %>
375 <ul id="quick" class="main_nav navigation horizontal-list">
375 <ul id="quick" class="main_nav navigation horizontal-list">
376 <!-- repo switcher -->
376 <!-- repo switcher -->
377 <li class="${is_active('repositories')} repo_switcher_li has_select2">
377 <li class="${is_active('repositories')} repo_switcher_li has_select2">
378 <input id="repo_switcher" name="repo_switcher" type="hidden">
378 <input id="repo_switcher" name="repo_switcher" type="hidden">
379 </li>
379 </li>
380
380
381 ## ROOT MENU
381 ## ROOT MENU
382 %if c.rhodecode_user.username != h.DEFAULT_USER:
382 %if c.rhodecode_user.username != h.DEFAULT_USER:
383 <li class="${is_active('journal')}">
383 <li class="${is_active('journal')}">
384 <a class="menulink" title="${_('Show activity journal')}" href="${h.url('journal')}">
384 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
385 <div class="menulabel">${_('Journal')}</div>
385 <div class="menulabel">${_('Journal')}</div>
386 </a>
386 </a>
387 </li>
387 </li>
388 %else:
388 %else:
389 <li class="${is_active('journal')}">
389 <li class="${is_active('journal')}">
390 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.url('public_journal')}">
390 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
391 <div class="menulabel">${_('Public journal')}</div>
391 <div class="menulabel">${_('Public journal')}</div>
392 </a>
392 </a>
393 </li>
393 </li>
394 %endif
394 %endif
395 <li class="${is_active('gists')}">
395 <li class="${is_active('gists')}">
396 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
396 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
397 <div class="menulabel">${_('Gists')}</div>
397 <div class="menulabel">${_('Gists')}</div>
398 </a>
398 </a>
399 </li>
399 </li>
400 <li class="${is_active('search')}">
400 <li class="${is_active('search')}">
401 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.route_path('search')}">
401 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.route_path('search')}">
402 <div class="menulabel">${_('Search')}</div>
402 <div class="menulabel">${_('Search')}</div>
403 </a>
403 </a>
404 </li>
404 </li>
405 % if h.HasPermissionAll('hg.admin')('access admin main page'):
405 % if h.HasPermissionAll('hg.admin')('access admin main page'):
406 <li class="${is_active('admin')}">
406 <li class="${is_active('admin')}">
407 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
407 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
408 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
408 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
409 </a>
409 </a>
410 ${admin_menu()}
410 ${admin_menu()}
411 </li>
411 </li>
412 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
412 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
413 <li class="${is_active('admin')}">
413 <li class="${is_active('admin')}">
414 <a class="menulink childs" title="${_('Delegated Admin settings')}">
414 <a class="menulink childs" title="${_('Delegated Admin settings')}">
415 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
415 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
416 </a>
416 </a>
417 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
417 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
418 c.rhodecode_user.repository_groups_admin,
418 c.rhodecode_user.repository_groups_admin,
419 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
419 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
420 </li>
420 </li>
421 % endif
421 % endif
422 % if c.debug_style:
422 % if c.debug_style:
423 <li class="${is_active('debug_style')}">
423 <li class="${is_active('debug_style')}">
424 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
424 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
425 <div class="menulabel">${_('Style')}</div>
425 <div class="menulabel">${_('Style')}</div>
426 </a>
426 </a>
427 </li>
427 </li>
428 % endif
428 % endif
429 ## render extra user menu
429 ## render extra user menu
430 ${usermenu(active=(active=='my_account'))}
430 ${usermenu(active=(active=='my_account'))}
431 </ul>
431 </ul>
432
432
433 <script type="text/javascript">
433 <script type="text/javascript">
434 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
434 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
435
435
436 /*format the look of items in the list*/
436 /*format the look of items in the list*/
437 var format = function(state, escapeMarkup){
437 var format = function(state, escapeMarkup){
438 if (!state.id){
438 if (!state.id){
439 return state.text; // optgroup
439 return state.text; // optgroup
440 }
440 }
441 var obj_dict = state.obj;
441 var obj_dict = state.obj;
442 var tmpl = '';
442 var tmpl = '';
443
443
444 if(obj_dict && state.type == 'repo'){
444 if(obj_dict && state.type == 'repo'){
445 if(obj_dict['repo_type'] === 'hg'){
445 if(obj_dict['repo_type'] === 'hg'){
446 tmpl += '<i class="icon-hg"></i> ';
446 tmpl += '<i class="icon-hg"></i> ';
447 }
447 }
448 else if(obj_dict['repo_type'] === 'git'){
448 else if(obj_dict['repo_type'] === 'git'){
449 tmpl += '<i class="icon-git"></i> ';
449 tmpl += '<i class="icon-git"></i> ';
450 }
450 }
451 else if(obj_dict['repo_type'] === 'svn'){
451 else if(obj_dict['repo_type'] === 'svn'){
452 tmpl += '<i class="icon-svn"></i> ';
452 tmpl += '<i class="icon-svn"></i> ';
453 }
453 }
454 if(obj_dict['private']){
454 if(obj_dict['private']){
455 tmpl += '<i class="icon-lock" ></i> ';
455 tmpl += '<i class="icon-lock" ></i> ';
456 }
456 }
457 else if(visual_show_public_icon){
457 else if(visual_show_public_icon){
458 tmpl += '<i class="icon-unlock-alt"></i> ';
458 tmpl += '<i class="icon-unlock-alt"></i> ';
459 }
459 }
460 }
460 }
461 if(obj_dict && state.type == 'commit') {
461 if(obj_dict && state.type == 'commit') {
462 tmpl += '<i class="icon-tag"></i>';
462 tmpl += '<i class="icon-tag"></i>';
463 }
463 }
464 if(obj_dict && state.type == 'group'){
464 if(obj_dict && state.type == 'group'){
465 tmpl += '<i class="icon-folder-close"></i> ';
465 tmpl += '<i class="icon-folder-close"></i> ';
466 }
466 }
467 tmpl += escapeMarkup(state.text);
467 tmpl += escapeMarkup(state.text);
468 return tmpl;
468 return tmpl;
469 };
469 };
470
470
471 var formatResult = function(result, container, query, escapeMarkup) {
471 var formatResult = function(result, container, query, escapeMarkup) {
472 return format(result, escapeMarkup);
472 return format(result, escapeMarkup);
473 };
473 };
474
474
475 var formatSelection = function(data, container, escapeMarkup) {
475 var formatSelection = function(data, container, escapeMarkup) {
476 return format(data, escapeMarkup);
476 return format(data, escapeMarkup);
477 };
477 };
478
478
479 $("#repo_switcher").select2({
479 $("#repo_switcher").select2({
480 cachedDataSource: {},
480 cachedDataSource: {},
481 minimumInputLength: 2,
481 minimumInputLength: 2,
482 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
482 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
483 dropdownAutoWidth: true,
483 dropdownAutoWidth: true,
484 formatResult: formatResult,
484 formatResult: formatResult,
485 formatSelection: formatSelection,
485 formatSelection: formatSelection,
486 containerCssClass: "repo-switcher",
486 containerCssClass: "repo-switcher",
487 dropdownCssClass: "repo-switcher-dropdown",
487 dropdownCssClass: "repo-switcher-dropdown",
488 escapeMarkup: function(m){
488 escapeMarkup: function(m){
489 // don't escape our custom placeholder
489 // don't escape our custom placeholder
490 if(m.substr(0,23) == '<div class="menulabel">'){
490 if(m.substr(0,23) == '<div class="menulabel">'){
491 return m;
491 return m;
492 }
492 }
493
493
494 return Select2.util.escapeMarkup(m);
494 return Select2.util.escapeMarkup(m);
495 },
495 },
496 query: $.debounce(250, function(query){
496 query: $.debounce(250, function(query){
497 self = this;
497 self = this;
498 var cacheKey = query.term;
498 var cacheKey = query.term;
499 var cachedData = self.cachedDataSource[cacheKey];
499 var cachedData = self.cachedDataSource[cacheKey];
500
500
501 if (cachedData) {
501 if (cachedData) {
502 query.callback({results: cachedData.results});
502 query.callback({results: cachedData.results});
503 } else {
503 } else {
504 $.ajax({
504 $.ajax({
505 url: pyroutes.url('goto_switcher_data'),
505 url: pyroutes.url('goto_switcher_data'),
506 data: {'query': query.term},
506 data: {'query': query.term},
507 dataType: 'json',
507 dataType: 'json',
508 type: 'GET',
508 type: 'GET',
509 success: function(data) {
509 success: function(data) {
510 self.cachedDataSource[cacheKey] = data;
510 self.cachedDataSource[cacheKey] = data;
511 query.callback({results: data.results});
511 query.callback({results: data.results});
512 },
512 },
513 error: function(data, textStatus, errorThrown) {
513 error: function(data, textStatus, errorThrown) {
514 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
514 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
515 }
515 }
516 })
516 })
517 }
517 }
518 })
518 })
519 });
519 });
520
520
521 $("#repo_switcher").on('select2-selecting', function(e){
521 $("#repo_switcher").on('select2-selecting', function(e){
522 e.preventDefault();
522 e.preventDefault();
523 window.location = e.choice.url;
523 window.location = e.choice.url;
524 });
524 });
525
525
526 </script>
526 </script>
527 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
527 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
528 </%def>
528 </%def>
529
529
530 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
530 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
531 <div class="modal-dialog">
531 <div class="modal-dialog">
532 <div class="modal-content">
532 <div class="modal-content">
533 <div class="modal-header">
533 <div class="modal-header">
534 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
534 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
535 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
535 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
536 </div>
536 </div>
537 <div class="modal-body">
537 <div class="modal-body">
538 <div class="block-left">
538 <div class="block-left">
539 <table class="keyboard-mappings">
539 <table class="keyboard-mappings">
540 <tbody>
540 <tbody>
541 <tr>
541 <tr>
542 <th></th>
542 <th></th>
543 <th>${_('Site-wide shortcuts')}</th>
543 <th>${_('Site-wide shortcuts')}</th>
544 </tr>
544 </tr>
545 <%
545 <%
546 elems = [
546 elems = [
547 ('/', 'Open quick search box'),
547 ('/', 'Open quick search box'),
548 ('g h', 'Goto home page'),
548 ('g h', 'Goto home page'),
549 ('g g', 'Goto my private gists page'),
549 ('g g', 'Goto my private gists page'),
550 ('g G', 'Goto my public gists page'),
550 ('g G', 'Goto my public gists page'),
551 ('n r', 'New repository page'),
551 ('n r', 'New repository page'),
552 ('n g', 'New gist page'),
552 ('n g', 'New gist page'),
553 ]
553 ]
554 %>
554 %>
555 %for key, desc in elems:
555 %for key, desc in elems:
556 <tr>
556 <tr>
557 <td class="keys">
557 <td class="keys">
558 <span class="key tag">${key}</span>
558 <span class="key tag">${key}</span>
559 </td>
559 </td>
560 <td>${desc}</td>
560 <td>${desc}</td>
561 </tr>
561 </tr>
562 %endfor
562 %endfor
563 </tbody>
563 </tbody>
564 </table>
564 </table>
565 </div>
565 </div>
566 <div class="block-left">
566 <div class="block-left">
567 <table class="keyboard-mappings">
567 <table class="keyboard-mappings">
568 <tbody>
568 <tbody>
569 <tr>
569 <tr>
570 <th></th>
570 <th></th>
571 <th>${_('Repositories')}</th>
571 <th>${_('Repositories')}</th>
572 </tr>
572 </tr>
573 <%
573 <%
574 elems = [
574 elems = [
575 ('g s', 'Goto summary page'),
575 ('g s', 'Goto summary page'),
576 ('g c', 'Goto changelog page'),
576 ('g c', 'Goto changelog page'),
577 ('g f', 'Goto files page'),
577 ('g f', 'Goto files page'),
578 ('g F', 'Goto files page with file search activated'),
578 ('g F', 'Goto files page with file search activated'),
579 ('g p', 'Goto pull requests page'),
579 ('g p', 'Goto pull requests page'),
580 ('g o', 'Goto repository settings'),
580 ('g o', 'Goto repository settings'),
581 ('g O', 'Goto repository permissions settings'),
581 ('g O', 'Goto repository permissions settings'),
582 ]
582 ]
583 %>
583 %>
584 %for key, desc in elems:
584 %for key, desc in elems:
585 <tr>
585 <tr>
586 <td class="keys">
586 <td class="keys">
587 <span class="key tag">${key}</span>
587 <span class="key tag">${key}</span>
588 </td>
588 </td>
589 <td>${desc}</td>
589 <td>${desc}</td>
590 </tr>
590 </tr>
591 %endfor
591 %endfor
592 </tbody>
592 </tbody>
593 </table>
593 </table>
594 </div>
594 </div>
595 </div>
595 </div>
596 <div class="modal-footer">
596 <div class="modal-footer">
597 </div>
597 </div>
598 </div><!-- /.modal-content -->
598 </div><!-- /.modal-content -->
599 </div><!-- /.modal-dialog -->
599 </div><!-- /.modal-dialog -->
600 </div><!-- /.modal -->
600 </div><!-- /.modal -->
@@ -1,54 +1,56 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.mako"/>
2 <%inherit file="/base/base.mako"/>
3 <%def name="title()">
3 <%def name="title()">
4 ${_('Journal')}
4 ${_('Journal')}
5 %if c.rhodecode_name:
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
7 %endif
8 </%def>
8 </%def>
9
9 <%def name="breadcrumbs()">
10 <%def name="breadcrumbs()">
10 <h1 class="block-left">
11 <h1 class="block-left">
11 ${h.form(None, id_="filter_form", method="get")}
12 ${h.form(None, id_="filter_form", method="get")}
12 <input class="q_filter_box ${'' if c.search_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.search_term}" placeholder="${_('quick filter...')}"/>
13 <input class="q_filter_box ${'' if c.search_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.search_term}" placeholder="${_('quick filter...')}"/>
13 <input type='submit' value="${_('Filter')}" class="btn" />
14 <input type='submit' value="${_('Filter')}" class="btn" />
14 ${_('Journal')} - ${ungettext('%s entry', '%s entries', c.journal_pager.item_count) % (c.journal_pager.item_count)}
15 ${_('Journal')} - ${_ungettext('%s entry', '%s entries', c.journal_pager.item_count) % (c.journal_pager.item_count)}
15 ${h.end_form()}
16 ${h.end_form()}
16 </h1>
17 </h1>
17 <p class="tooltip filterexample" title="${h.tooltip(h.journal_filter_help(c.pyramid_request))}">${_('Example Queries')}</p>
18 <p class="tooltip filterexample" title="${h.tooltip(h.journal_filter_help(c.pyramid_request))}">${_('Example Queries')}</p>
18 </%def>
19 </%def>
19 <%def name="menu_bar_nav()">
20 <%def name="menu_bar_nav()">
20 ${self.menu_items(active='journal')}
21 ${self.menu_items(active='journal')}
21 </%def>
22 </%def>
22 <%def name="head_extra()">
23 <%def name="head_extra()">
23 <link href="${h.url('journal_atom', auth_token=c.rhodecode_user.feed_token)}" rel="alternate" title="${_('ATOM journal feed')}" type="application/atom+xml" />
24 <link href="${h.route_path('journal_atom', _query=dict(auth_token=c.rhodecode_user.feed_token))}" rel="alternate" title="${_('ATOM journal feed')}" type="application/atom+xml" />
24 <link href="${h.url('journal_rss', auth_token=c.rhodecode_user.feed_token)}" rel="alternate" title="${_('RSS journal feed')}" type="application/rss+xml" />
25 <link href="${h.route_path('journal_rss', _query=dict(auth_token=c.rhodecode_user.feed_token))}" rel="alternate" title="${_('RSS journal feed')}" type="application/rss+xml" />
25 </%def>
26 </%def>
27
26 <%def name="main()">
28 <%def name="main()">
27
29
28 <div class="box">
30 <div class="box">
29 <!-- box / title -->
31 <!-- box / title -->
30 <div class="title journal">
32 <div class="title journal">
31 ${self.breadcrumbs()}
33 ${self.breadcrumbs()}
32 <ul class="links icon-only-links block-right">
34 <ul class="links icon-only-links block-right">
33 <li>
35 <li>
34 <span><a id="refresh" href="${h.url('journal')}"><i class="icon-refresh"></i></a></span>
36 <span><a id="refresh" href="${h.route_path('journal')}"><i class="icon-refresh"></i></a></span>
35 </li>
37 </li>
36 <li>
38 <li>
37 <span><a href="${h.url('journal_atom', auth_token=c.rhodecode_user.feed_token)}"><i class="icon-rss-sign"></i></a></span>
39 <span><a href="${h.route_path('journal_atom', _query=dict(auth_token=c.rhodecode_user.feed_token))}"><i class="icon-rss-sign"></i></a></span>
38 </li>
40 </li>
39 </ul>
41 </ul>
40 </div>
42 </div>
41 <div id="journal">${c.journal_data}</div>
43 <div id="journal">${c.journal_data|n}</div>
42 </div>
44 </div>
43
45
44 <script type="text/javascript">
46 <script type="text/javascript">
45
47
46 $('#j_filter').autoGrowInput();
48 $('#j_filter').autoGrowInput();
47 $(document).on('pjax:success',function(){
49 $(document).on('pjax:success',function(){
48 show_more_event();
50 show_more_event();
49 });
51 });
50 $(document).pjax('#refresh', '#journal',
52 $(document).pjax('#refresh', '#journal',
51 {url: "${h.url.current(filter=c.search_term)}", push: false});
53 {url: "${request.current_route_path(_query=dict(filter=c.search_term))}", push: false});
52
54
53 </script>
55 </script>
54 </%def>
56 </%def>
@@ -1,37 +1,43 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.mako"/>
2 <%inherit file="/base/base.mako"/>
3 <%def name="title()">
3 <%def name="title()">
4 ${_('Public Journal')}
4 ${_('Public Journal')}
5 %if c.rhodecode_name:
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
7 %endif
8 </%def>
8 </%def>
9
9 <%def name="breadcrumbs()">
10 <%def name="breadcrumbs()">
10 ${h.branding(c.rhodecode_name)}
11 <h1 class="block-left">
12 ${_('Public Journal')} - ${_ungettext('%s entry', '%s entries', c.journal_pager.item_count) % (c.journal_pager.item_count)}
13 </h1>
11 </%def>
14 </%def>
15
12 <%def name="menu_bar_nav()">
16 <%def name="menu_bar_nav()">
13 ${self.menu_items(active='journal')}
17 ${self.menu_items(active='journal')}
14 </%def>
18 </%def>
19
15 <%def name="head_extra()">
20 <%def name="head_extra()">
16 <link href="${h.url('public_journal_atom')}" rel="alternate" title="${_('ATOM public journal feed')}" type="application/atom+xml" />
21 <link href="${h.route_path('journal_public_atom')}" rel="alternate" title="${_('ATOM public journal feed')}" type="application/atom+xml" />
17 <link href="${h.url('public_journal_rss')}" rel="alternate" title="${_('RSS public journal feed')}" type="application/rss+xml" />
22 <link href="${h.route_path('journal_public_rss')}" rel="alternate" title="${_('RSS public journal feed')}" type="application/rss+xml" />
18 </%def>
23 </%def>
24
19 <%def name="main()">
25 <%def name="main()">
20
26
21 <div class="box">
27 <div class="box">
22 <!-- box / title -->
28 <!-- box / title -->
23 <div class="title">
29 <div class="title journal">
24 <h5>${_('Public Journal')}</h5>
30 ${self.breadcrumbs()}
25 <ul class="links">
31
32 <ul class="links icon-only-links block-right">
26 <li>
33 <li>
27 <span>
34 <span>
28 <a href="${h.url('public_journal_atom')}"> <i class="icon-rss-sign" ></i></a>
35 <a href="${h.route_path('journal_public_atom')}"> <i class="icon-rss-sign" ></i></a>
29 </span>
36 </span>
30 </li>
37 </li>
31 </ul>
38 </ul>
32 </div>
39 </div>
33
40 <div id="journal">${c.journal_data|n}</div>
34 <div id="journal">${c.journal_data}</div>
35 </div>
41 </div>
36
42
37 </%def>
43 </%def>
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now