##// END OF EJS Templates
core: moved goto_switcher views into pyramid.
marcink -
r1668:6a5ff1d6 default
parent child Browse files
Show More
@@ -0,0 +1,151 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 import json
22
23 import pytest
24
25 from . import assert_and_get_content
26 from rhodecode.tests import TestController, TEST_USER_ADMIN_LOGIN
27 from rhodecode.tests.fixture import Fixture
28
29 from rhodecode.lib.utils import map_groups
30 from rhodecode.model.repo import RepoModel
31 from rhodecode.model.repo_group import RepoGroupModel
32 from rhodecode.model.db import Session, Repository, RepoGroup
33
34 fixture = Fixture()
35
36
37 def route_path(name, params=None, **kwargs):
38 import urllib
39
40 base_url = {
41 'goto_switcher_data': '/_goto_data',
42 }[name].format(**kwargs)
43
44 if params:
45 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
46 return base_url
47
48
49 class TestGotoSwitcherData(TestController):
50
51 required_repos_with_groups = [
52 'abc',
53 'abc-fork',
54 'forks/abcd',
55 'abcd',
56 'abcde',
57 'a/abc',
58 'aa/abc',
59 'aaa/abc',
60 'aaaa/abc',
61 'repos_abc/aaa/abc',
62 'abc_repos/abc',
63 'abc_repos/abcd',
64 'xxx/xyz',
65 'forked-abc/a/abc'
66 ]
67
68 @pytest.fixture(autouse=True, scope='class')
69 def prepare(self, request, pylonsapp):
70 for repo_and_group in self.required_repos_with_groups:
71 # create structure of groups and return the last group
72
73 repo_group = map_groups(repo_and_group)
74
75 RepoModel()._create_repo(
76 repo_and_group, 'hg', 'test-ac', TEST_USER_ADMIN_LOGIN,
77 repo_group=getattr(repo_group, 'group_id', None))
78
79 Session().commit()
80
81 request.addfinalizer(self.cleanup)
82
83 def cleanup(self):
84 # first delete all repos
85 for repo_and_groups in self.required_repos_with_groups:
86 repo = Repository.get_by_repo_name(repo_and_groups)
87 if repo:
88 RepoModel().delete(repo)
89 Session().commit()
90
91 # then delete all empty groups
92 for repo_and_groups in self.required_repos_with_groups:
93 if '/' in repo_and_groups:
94 r_group = repo_and_groups.rsplit('/', 1)[0]
95 repo_group = RepoGroup.get_by_group_name(r_group)
96 if not repo_group:
97 continue
98 parents = repo_group.parents
99 RepoGroupModel().delete(repo_group, force_delete=True)
100 Session().commit()
101
102 for el in reversed(parents):
103 RepoGroupModel().delete(el, force_delete=True)
104 Session().commit()
105
106 def test_returns_list_of_repos_and_groups(self, xhr_header):
107 self.log_user()
108
109 response = self.app.get(
110 route_path('goto_switcher_data'),
111 extra_environ=xhr_header, status=200)
112 result = json.loads(response.body)['results']
113
114 repos, groups, commits = assert_and_get_content(result)
115
116 assert len(repos) == len(Repository.get_all())
117 assert len(groups) == len(RepoGroup.get_all())
118 assert len(commits) == 0
119
120 def test_returns_list_of_repos_and_groups_filtered(self, xhr_header):
121 self.log_user()
122
123 response = self.app.get(
124 route_path('goto_switcher_data'),
125 params={'query': 'abc'},
126 extra_environ=xhr_header, status=200)
127 result = json.loads(response.body)['results']
128
129 repos, groups, commits = assert_and_get_content(result)
130
131 assert len(repos) == 13
132 assert len(groups) == 5
133 assert len(commits) == 0
134
135 def test_returns_list_of_properly_sorted_and_filtered(self, xhr_header):
136 self.log_user()
137
138 response = self.app.get(
139 route_path('goto_switcher_data'),
140 params={'query': 'abc'},
141 extra_environ=xhr_header, status=200)
142 result = json.loads(response.body)['results']
143
144 repos, groups, commits = assert_and_get_content(result)
145
146 test_repos = [x['text'] for x in repos[:4]]
147 assert ['abc', 'abcd', 'a/abc', 'abcde'] == test_repos
148
149 test_groups = [x['text'] for x in groups[:4]]
150 assert ['abc_repos', 'repos_abc',
151 'forked-abc', 'forked-abc/a'] == test_groups
@@ -1,37 +1,41 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-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 def includeme(config):
22 def includeme(config):
23
23
24 config.add_route(
24 config.add_route(
25 name='user_autocomplete_data',
25 name='user_autocomplete_data',
26 pattern='/_users')
26 pattern='/_users')
27
27
28 config.add_route(
28 config.add_route(
29 name='user_group_autocomplete_data',
29 name='user_group_autocomplete_data',
30 pattern='/_user_groups')
30 pattern='/_user_groups')
31
31
32 config.add_route(
32 config.add_route(
33 name='repo_list_data',
33 name='repo_list_data',
34 pattern='/_repos')
34 pattern='/_repos')
35
35
36 config.add_route(
37 name='goto_switcher_data',
38 pattern='/_goto_data')
39
36 # Scan module for configuration decorators.
40 # Scan module for configuration decorators.
37 config.scan()
41 config.scan()
@@ -1,138 +1,237 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-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 re
21 import logging
22 import logging
22
23
23 from pyramid.view import view_config
24 from pyramid.view import view_config
24
25
25 from rhodecode.apps._base import BaseAppView
26 from rhodecode.apps._base import BaseAppView
26 from rhodecode.lib import helpers as h
27 from rhodecode.lib import helpers as h
27 from rhodecode.lib.auth import LoginRequired, NotAnonymous
28 from rhodecode.lib.auth import LoginRequired, NotAnonymous
29 from rhodecode.lib.index import searcher_from_config
28 from rhodecode.lib.utils2 import safe_unicode, str2bool
30 from rhodecode.lib.utils2 import safe_unicode, str2bool
29 from rhodecode.model.db import func, Repository
31 from rhodecode.model.db import func, Repository, RepoGroup
30 from rhodecode.model.repo import RepoModel
32 from rhodecode.model.repo import RepoModel
31 from rhodecode.model.scm import ScmModel
33 from rhodecode.model.scm import ScmModel
32
34
33
35
34 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
35
37
36
38
37 class HomeView(BaseAppView):
39 class HomeView(BaseAppView):
38
40
39 def load_default_context(self):
41 def load_default_context(self):
40 c = self._get_local_tmpl_context()
42 c = self._get_local_tmpl_context()
41 c.user = c.auth_user.get_instance()
43 c.user = c.auth_user.get_instance()
42 self._register_global_c(c)
44 self._register_global_c(c)
43 return c
45 return c
44
46
45 @LoginRequired()
47 @LoginRequired()
46 @view_config(
48 @view_config(
47 route_name='user_autocomplete_data', request_method='GET',
49 route_name='user_autocomplete_data', request_method='GET',
48 renderer='json_ext', xhr=True)
50 renderer='json_ext', xhr=True)
49 def user_autocomplete_data(self):
51 def user_autocomplete_data(self):
50 query = self.request.GET.get('query')
52 query = self.request.GET.get('query')
51 active = str2bool(self.request.GET.get('active') or True)
53 active = str2bool(self.request.GET.get('active') or True)
52 include_groups = str2bool(self.request.GET.get('user_groups'))
54 include_groups = str2bool(self.request.GET.get('user_groups'))
53
55
54 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
56 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
55 query, active, include_groups)
57 query, active, include_groups)
56
58
57 repo_model = RepoModel()
59 repo_model = RepoModel()
58 _users = repo_model.get_users(
60 _users = repo_model.get_users(
59 name_contains=query, only_active=active)
61 name_contains=query, only_active=active)
60
62
61 if include_groups:
63 if include_groups:
62 # extend with user groups
64 # extend with user groups
63 _user_groups = repo_model.get_user_groups(
65 _user_groups = repo_model.get_user_groups(
64 name_contains=query, only_active=active)
66 name_contains=query, only_active=active)
65 _users = _users + _user_groups
67 _users = _users + _user_groups
66
68
67 return {'suggestions': _users}
69 return {'suggestions': _users}
68
70
69 @LoginRequired()
71 @LoginRequired()
70 @NotAnonymous()
72 @NotAnonymous()
71 @view_config(
73 @view_config(
72 route_name='user_group_autocomplete_data', request_method='GET',
74 route_name='user_group_autocomplete_data', request_method='GET',
73 renderer='json_ext', xhr=True)
75 renderer='json_ext', xhr=True)
74 def user_group_autocomplete_data(self):
76 def user_group_autocomplete_data(self):
75 query = self.request.GET.get('query')
77 query = self.request.GET.get('query')
76 active = str2bool(self.request.GET.get('active') or True)
78 active = str2bool(self.request.GET.get('active') or True)
77 log.debug('generating user group list, query:%s, active:%s',
79 log.debug('generating user group list, query:%s, active:%s',
78 query, active)
80 query, active)
79
81
80 repo_model = RepoModel()
82 repo_model = RepoModel()
81 _user_groups = repo_model.get_user_groups(
83 _user_groups = repo_model.get_user_groups(
82 name_contains=query, only_active=active)
84 name_contains=query, only_active=active)
83 _user_groups = _user_groups
85 _user_groups = _user_groups
84
86
85 return {'suggestions': _user_groups}
87 return {'suggestions': _user_groups}
86
88
87 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
89 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
88 query = Repository.query()\
90 query = Repository.query()\
89 .order_by(func.length(Repository.repo_name))\
91 .order_by(func.length(Repository.repo_name))\
90 .order_by(Repository.repo_name)
92 .order_by(Repository.repo_name)
91
93
92 if repo_type:
94 if repo_type:
93 query = query.filter(Repository.repo_type == repo_type)
95 query = query.filter(Repository.repo_type == repo_type)
94
96
95 if name_contains:
97 if name_contains:
96 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
98 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
97 query = query.filter(
99 query = query.filter(
98 Repository.repo_name.ilike(ilike_expression))
100 Repository.repo_name.ilike(ilike_expression))
99 query = query.limit(limit)
101 query = query.limit(limit)
100
102
101 all_repos = query.all()
103 all_repos = query.all()
102 # permission checks are inside this function
104 # permission checks are inside this function
103 repo_iter = ScmModel().get_repos(all_repos)
105 repo_iter = ScmModel().get_repos(all_repos)
104 return [
106 return [
105 {
107 {
106 'id': obj['name'],
108 'id': obj['name'],
107 'text': obj['name'],
109 'text': obj['name'],
108 'type': 'repo',
110 'type': 'repo',
109 'obj': obj['dbrepo'],
111 'obj': obj['dbrepo'],
110 'url': h.url('summary_home', repo_name=obj['name'])
112 'url': h.url('summary_home', repo_name=obj['name'])
111 }
113 }
112 for obj in repo_iter]
114 for obj in repo_iter]
113
115
116 def _get_repo_group_list(self, name_contains=None, limit=20):
117 query = RepoGroup.query()\
118 .order_by(func.length(RepoGroup.group_name))\
119 .order_by(RepoGroup.group_name)
120
121 if name_contains:
122 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
123 query = query.filter(
124 RepoGroup.group_name.ilike(ilike_expression))
125 query = query.limit(limit)
126
127 all_groups = query.all()
128 repo_groups_iter = ScmModel().get_repo_groups(all_groups)
129 return [
130 {
131 'id': obj.group_name,
132 'text': obj.group_name,
133 'type': 'group',
134 'obj': {},
135 'url': h.url('repo_group_home', group_name=obj.group_name)
136 }
137 for obj in repo_groups_iter]
138
139 def _get_hash_commit_list(self, auth_user, hash_starts_with=None):
140 if not hash_starts_with or len(hash_starts_with) < 3:
141 return []
142
143 commit_hashes = re.compile('([0-9a-f]{2,40})').findall(hash_starts_with)
144
145 if len(commit_hashes) != 1:
146 return []
147
148 commit_hash_prefix = commit_hashes[0]
149
150 searcher = searcher_from_config(self.request.registry.settings)
151 result = searcher.search(
152 'commit_id:%s*' % commit_hash_prefix, 'commit', auth_user,
153 raise_on_exc=False)
154
155 return [
156 {
157 'id': entry['commit_id'],
158 'text': entry['commit_id'],
159 'type': 'commit',
160 'obj': {'repo': entry['repository']},
161 'url': h.url('changeset_home',
162 repo_name=entry['repository'],
163 revision=entry['commit_id'])
164 }
165 for entry in result['results']]
166
114 @LoginRequired()
167 @LoginRequired()
115 @view_config(
168 @view_config(
116 route_name='repo_list_data', request_method='GET',
169 route_name='repo_list_data', request_method='GET',
117 renderer='json_ext', xhr=True)
170 renderer='json_ext', xhr=True)
118 def repo_list_data(self):
171 def repo_list_data(self):
119 _ = self.request.translate
172 _ = self.request.translate
120
173
121 query = self.request.GET.get('query')
174 query = self.request.GET.get('query')
122 repo_type = self.request.GET.get('repo_type')
175 repo_type = self.request.GET.get('repo_type')
123 log.debug('generating repo list, query:%s, repo_type:%s',
176 log.debug('generating repo list, query:%s, repo_type:%s',
124 query, repo_type)
177 query, repo_type)
125
178
126 res = []
179 res = []
127 repos = self._get_repo_list(query, repo_type=repo_type)
180 repos = self._get_repo_list(query, repo_type=repo_type)
128 if repos:
181 if repos:
129 res.append({
182 res.append({
130 'text': _('Repositories'),
183 'text': _('Repositories'),
131 'children': repos
184 'children': repos
132 })
185 })
133
186
134 data = {
187 data = {
135 'more': False,
188 'more': False,
136 'results': res
189 'results': res
137 }
190 }
138 return data
191 return data
192
193 @LoginRequired()
194 @view_config(
195 route_name='goto_switcher_data', request_method='GET',
196 renderer='json_ext', xhr=True)
197 def goto_switcher_data(self):
198 c = self.load_default_context()
199
200 _ = self.request.translate
201
202 query = self.request.GET.get('query')
203 log.debug('generating goto switcher list, query %s', query)
204
205 res = []
206 repo_groups = self._get_repo_group_list(query)
207 if repo_groups:
208 res.append({
209 'text': _('Groups'),
210 'children': repo_groups
211 })
212
213 repos = self._get_repo_list(query)
214 if repos:
215 res.append({
216 'text': _('Repositories'),
217 'children': repos
218 })
219
220 commits = self._get_hash_commit_list(c.auth_user, query)
221 if commits:
222 unique_repos = {}
223 for commit in commits:
224 unique_repos.setdefault(commit['obj']['repo'], []
225 ).append(commit)
226
227 for repo in unique_repos:
228 res.append({
229 'text': _('Commits in %(repo)s') % {'repo': repo},
230 'children': unique_repos[repo]
231 })
232
233 data = {
234 'more': False,
235 'results': res
236 }
237 return data
@@ -1,1146 +1,1144 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 from rhodecode.config import routing_links
35 from rhodecode.config import routing_links
36
36
37 # prefix for non repository related links needs to be prefixed with `/`
37 # prefix for non repository related links needs to be prefixed with `/`
38 ADMIN_PREFIX = '/_admin'
38 ADMIN_PREFIX = '/_admin'
39 STATIC_FILE_PREFIX = '/_static'
39 STATIC_FILE_PREFIX = '/_static'
40
40
41 # Default requirements for URL parts
41 # Default requirements for URL parts
42 URL_NAME_REQUIREMENTS = {
42 URL_NAME_REQUIREMENTS = {
43 # group name can have a slash in them, but they must not end with a slash
43 # group name can have a slash in them, but they must not end with a slash
44 'group_name': r'.*?[^/]',
44 'group_name': r'.*?[^/]',
45 'repo_group_name': r'.*?[^/]',
45 'repo_group_name': r'.*?[^/]',
46 # repo names can have a slash in them, but they must not end with a slash
46 # repo names can have a slash in them, but they must not end with a slash
47 'repo_name': r'.*?[^/]',
47 'repo_name': r'.*?[^/]',
48 # file path eats up everything at the end
48 # file path eats up everything at the end
49 'f_path': r'.*',
49 'f_path': r'.*',
50 # reference types
50 # reference types
51 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
51 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
52 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
52 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
53 }
53 }
54
54
55
55
56 def add_route_requirements(route_path, requirements):
56 def add_route_requirements(route_path, requirements):
57 """
57 """
58 Adds regex requirements to pyramid routes using a mapping dict
58 Adds regex requirements to pyramid routes using a mapping dict
59
59
60 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
60 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
61 '/{action}/{id:\d+}'
61 '/{action}/{id:\d+}'
62
62
63 """
63 """
64 for key, regex in requirements.items():
64 for key, regex in requirements.items():
65 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
65 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
66 return route_path
66 return route_path
67
67
68
68
69 class JSRoutesMapper(Mapper):
69 class JSRoutesMapper(Mapper):
70 """
70 """
71 Wrapper for routes.Mapper to make pyroutes compatible url definitions
71 Wrapper for routes.Mapper to make pyroutes compatible url definitions
72 """
72 """
73 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
73 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
74 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
74 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
75 def __init__(self, *args, **kw):
75 def __init__(self, *args, **kw):
76 super(JSRoutesMapper, self).__init__(*args, **kw)
76 super(JSRoutesMapper, self).__init__(*args, **kw)
77 self._jsroutes = []
77 self._jsroutes = []
78
78
79 def connect(self, *args, **kw):
79 def connect(self, *args, **kw):
80 """
80 """
81 Wrapper for connect to take an extra argument jsroute=True
81 Wrapper for connect to take an extra argument jsroute=True
82
82
83 :param jsroute: boolean, if True will add the route to the pyroutes list
83 :param jsroute: boolean, if True will add the route to the pyroutes list
84 """
84 """
85 if kw.pop('jsroute', False):
85 if kw.pop('jsroute', False):
86 if not self._named_route_regex.match(args[0]):
86 if not self._named_route_regex.match(args[0]):
87 raise Exception('only named routes can be added to pyroutes')
87 raise Exception('only named routes can be added to pyroutes')
88 self._jsroutes.append(args[0])
88 self._jsroutes.append(args[0])
89
89
90 super(JSRoutesMapper, self).connect(*args, **kw)
90 super(JSRoutesMapper, self).connect(*args, **kw)
91
91
92 def _extract_route_information(self, route):
92 def _extract_route_information(self, route):
93 """
93 """
94 Convert a route into tuple(name, path, args), eg:
94 Convert a route into tuple(name, path, args), eg:
95 ('show_user', '/profile/%(username)s', ['username'])
95 ('show_user', '/profile/%(username)s', ['username'])
96 """
96 """
97 routepath = route.routepath
97 routepath = route.routepath
98 def replace(matchobj):
98 def replace(matchobj):
99 if matchobj.group(1):
99 if matchobj.group(1):
100 return "%%(%s)s" % matchobj.group(1).split(':')[0]
100 return "%%(%s)s" % matchobj.group(1).split(':')[0]
101 else:
101 else:
102 return "%%(%s)s" % matchobj.group(2)
102 return "%%(%s)s" % matchobj.group(2)
103
103
104 routepath = self._argument_prog.sub(replace, routepath)
104 routepath = self._argument_prog.sub(replace, routepath)
105 return (
105 return (
106 route.name,
106 route.name,
107 routepath,
107 routepath,
108 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
108 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
109 for arg in self._argument_prog.findall(route.routepath)]
109 for arg in self._argument_prog.findall(route.routepath)]
110 )
110 )
111
111
112 def jsroutes(self):
112 def jsroutes(self):
113 """
113 """
114 Return a list of pyroutes.js compatible routes
114 Return a list of pyroutes.js compatible routes
115 """
115 """
116 for route_name in self._jsroutes:
116 for route_name in self._jsroutes:
117 yield self._extract_route_information(self._routenames[route_name])
117 yield self._extract_route_information(self._routenames[route_name])
118
118
119
119
120 def make_map(config):
120 def make_map(config):
121 """Create, configure and return the routes Mapper"""
121 """Create, configure and return the routes Mapper"""
122 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
122 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
123 always_scan=config['debug'])
123 always_scan=config['debug'])
124 rmap.minimization = False
124 rmap.minimization = False
125 rmap.explicit = False
125 rmap.explicit = False
126
126
127 from rhodecode.lib.utils2 import str2bool
127 from rhodecode.lib.utils2 import str2bool
128 from rhodecode.model import repo, repo_group
128 from rhodecode.model import repo, repo_group
129
129
130 def check_repo(environ, match_dict):
130 def check_repo(environ, match_dict):
131 """
131 """
132 check for valid repository for proper 404 handling
132 check for valid repository for proper 404 handling
133
133
134 :param environ:
134 :param environ:
135 :param match_dict:
135 :param match_dict:
136 """
136 """
137 repo_name = match_dict.get('repo_name')
137 repo_name = match_dict.get('repo_name')
138
138
139 if match_dict.get('f_path'):
139 if match_dict.get('f_path'):
140 # fix for multiple initial slashes that causes errors
140 # fix for multiple initial slashes that causes errors
141 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
141 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
142 repo_model = repo.RepoModel()
142 repo_model = repo.RepoModel()
143 by_name_match = repo_model.get_by_repo_name(repo_name)
143 by_name_match = repo_model.get_by_repo_name(repo_name)
144 # if we match quickly from database, short circuit the operation,
144 # if we match quickly from database, short circuit the operation,
145 # and validate repo based on the type.
145 # and validate repo based on the type.
146 if by_name_match:
146 if by_name_match:
147 return True
147 return True
148
148
149 by_id_match = repo_model.get_repo_by_id(repo_name)
149 by_id_match = repo_model.get_repo_by_id(repo_name)
150 if by_id_match:
150 if by_id_match:
151 repo_name = by_id_match.repo_name
151 repo_name = by_id_match.repo_name
152 match_dict['repo_name'] = repo_name
152 match_dict['repo_name'] = repo_name
153 return True
153 return True
154
154
155 return False
155 return False
156
156
157 def check_group(environ, match_dict):
157 def check_group(environ, match_dict):
158 """
158 """
159 check for valid repository group path for proper 404 handling
159 check for valid repository group path for proper 404 handling
160
160
161 :param environ:
161 :param environ:
162 :param match_dict:
162 :param match_dict:
163 """
163 """
164 repo_group_name = match_dict.get('group_name')
164 repo_group_name = match_dict.get('group_name')
165 repo_group_model = repo_group.RepoGroupModel()
165 repo_group_model = repo_group.RepoGroupModel()
166 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
166 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
167 if by_name_match:
167 if by_name_match:
168 return True
168 return True
169
169
170 return False
170 return False
171
171
172 def check_user_group(environ, match_dict):
172 def check_user_group(environ, match_dict):
173 """
173 """
174 check for valid user group for proper 404 handling
174 check for valid user group for proper 404 handling
175
175
176 :param environ:
176 :param environ:
177 :param match_dict:
177 :param match_dict:
178 """
178 """
179 return True
179 return True
180
180
181 def check_int(environ, match_dict):
181 def check_int(environ, match_dict):
182 return match_dict.get('id').isdigit()
182 return match_dict.get('id').isdigit()
183
183
184
184
185 #==========================================================================
185 #==========================================================================
186 # CUSTOM ROUTES HERE
186 # CUSTOM ROUTES HERE
187 #==========================================================================
187 #==========================================================================
188
188
189 # MAIN PAGE
189 # MAIN PAGE
190 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
190 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
191 rmap.connect('goto_switcher_data', '/_goto_data', controller='home',
192 action='goto_switcher_data')
193
191
194 # TODO: johbo: Static links, to be replaced by our redirection mechanism
192 # TODO: johbo: Static links, to be replaced by our redirection mechanism
195 rmap.connect('rst_help',
193 rmap.connect('rst_help',
196 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
194 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
197 _static=True)
195 _static=True)
198 rmap.connect('markdown_help',
196 rmap.connect('markdown_help',
199 'http://daringfireball.net/projects/markdown/syntax',
197 'http://daringfireball.net/projects/markdown/syntax',
200 _static=True)
198 _static=True)
201 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
199 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
202 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
200 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
203 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
201 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
204 # TODO: anderson - making this a static link since redirect won't play
202 # TODO: anderson - making this a static link since redirect won't play
205 # nice with POST requests
203 # nice with POST requests
206 rmap.connect('enterprise_license_convert_from_old',
204 rmap.connect('enterprise_license_convert_from_old',
207 'https://rhodecode.com/u/license-upgrade',
205 'https://rhodecode.com/u/license-upgrade',
208 _static=True)
206 _static=True)
209
207
210 routing_links.connect_redirection_links(rmap)
208 routing_links.connect_redirection_links(rmap)
211
209
212 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
210 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
213 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
211 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
214
212
215 # ADMIN REPOSITORY ROUTES
213 # ADMIN REPOSITORY ROUTES
216 with rmap.submapper(path_prefix=ADMIN_PREFIX,
214 with rmap.submapper(path_prefix=ADMIN_PREFIX,
217 controller='admin/repos') as m:
215 controller='admin/repos') as m:
218 m.connect('repos', '/repos',
216 m.connect('repos', '/repos',
219 action='create', conditions={'method': ['POST']})
217 action='create', conditions={'method': ['POST']})
220 m.connect('repos', '/repos',
218 m.connect('repos', '/repos',
221 action='index', conditions={'method': ['GET']})
219 action='index', conditions={'method': ['GET']})
222 m.connect('new_repo', '/create_repository', jsroute=True,
220 m.connect('new_repo', '/create_repository', jsroute=True,
223 action='create_repository', conditions={'method': ['GET']})
221 action='create_repository', conditions={'method': ['GET']})
224 m.connect('/repos/{repo_name}',
222 m.connect('/repos/{repo_name}',
225 action='update', conditions={'method': ['PUT'],
223 action='update', conditions={'method': ['PUT'],
226 'function': check_repo},
224 'function': check_repo},
227 requirements=URL_NAME_REQUIREMENTS)
225 requirements=URL_NAME_REQUIREMENTS)
228 m.connect('delete_repo', '/repos/{repo_name}',
226 m.connect('delete_repo', '/repos/{repo_name}',
229 action='delete', conditions={'method': ['DELETE']},
227 action='delete', conditions={'method': ['DELETE']},
230 requirements=URL_NAME_REQUIREMENTS)
228 requirements=URL_NAME_REQUIREMENTS)
231 m.connect('repo', '/repos/{repo_name}',
229 m.connect('repo', '/repos/{repo_name}',
232 action='show', conditions={'method': ['GET'],
230 action='show', conditions={'method': ['GET'],
233 'function': check_repo},
231 'function': check_repo},
234 requirements=URL_NAME_REQUIREMENTS)
232 requirements=URL_NAME_REQUIREMENTS)
235
233
236 # ADMIN REPOSITORY GROUPS ROUTES
234 # ADMIN REPOSITORY GROUPS ROUTES
237 with rmap.submapper(path_prefix=ADMIN_PREFIX,
235 with rmap.submapper(path_prefix=ADMIN_PREFIX,
238 controller='admin/repo_groups') as m:
236 controller='admin/repo_groups') as m:
239 m.connect('repo_groups', '/repo_groups',
237 m.connect('repo_groups', '/repo_groups',
240 action='create', conditions={'method': ['POST']})
238 action='create', conditions={'method': ['POST']})
241 m.connect('repo_groups', '/repo_groups',
239 m.connect('repo_groups', '/repo_groups',
242 action='index', conditions={'method': ['GET']})
240 action='index', conditions={'method': ['GET']})
243 m.connect('new_repo_group', '/repo_groups/new',
241 m.connect('new_repo_group', '/repo_groups/new',
244 action='new', conditions={'method': ['GET']})
242 action='new', conditions={'method': ['GET']})
245 m.connect('update_repo_group', '/repo_groups/{group_name}',
243 m.connect('update_repo_group', '/repo_groups/{group_name}',
246 action='update', conditions={'method': ['PUT'],
244 action='update', conditions={'method': ['PUT'],
247 'function': check_group},
245 'function': check_group},
248 requirements=URL_NAME_REQUIREMENTS)
246 requirements=URL_NAME_REQUIREMENTS)
249
247
250 # EXTRAS REPO GROUP ROUTES
248 # EXTRAS REPO GROUP ROUTES
251 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
249 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
252 action='edit',
250 action='edit',
253 conditions={'method': ['GET'], 'function': check_group},
251 conditions={'method': ['GET'], 'function': check_group},
254 requirements=URL_NAME_REQUIREMENTS)
252 requirements=URL_NAME_REQUIREMENTS)
255 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
253 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
256 action='edit',
254 action='edit',
257 conditions={'method': ['PUT'], 'function': check_group},
255 conditions={'method': ['PUT'], 'function': check_group},
258 requirements=URL_NAME_REQUIREMENTS)
256 requirements=URL_NAME_REQUIREMENTS)
259
257
260 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
258 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
261 action='edit_repo_group_advanced',
259 action='edit_repo_group_advanced',
262 conditions={'method': ['GET'], 'function': check_group},
260 conditions={'method': ['GET'], 'function': check_group},
263 requirements=URL_NAME_REQUIREMENTS)
261 requirements=URL_NAME_REQUIREMENTS)
264 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
262 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
265 action='edit_repo_group_advanced',
263 action='edit_repo_group_advanced',
266 conditions={'method': ['PUT'], 'function': check_group},
264 conditions={'method': ['PUT'], 'function': check_group},
267 requirements=URL_NAME_REQUIREMENTS)
265 requirements=URL_NAME_REQUIREMENTS)
268
266
269 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
267 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
270 action='edit_repo_group_perms',
268 action='edit_repo_group_perms',
271 conditions={'method': ['GET'], 'function': check_group},
269 conditions={'method': ['GET'], 'function': check_group},
272 requirements=URL_NAME_REQUIREMENTS)
270 requirements=URL_NAME_REQUIREMENTS)
273 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
271 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
274 action='update_perms',
272 action='update_perms',
275 conditions={'method': ['PUT'], 'function': check_group},
273 conditions={'method': ['PUT'], 'function': check_group},
276 requirements=URL_NAME_REQUIREMENTS)
274 requirements=URL_NAME_REQUIREMENTS)
277
275
278 m.connect('delete_repo_group', '/repo_groups/{group_name}',
276 m.connect('delete_repo_group', '/repo_groups/{group_name}',
279 action='delete', conditions={'method': ['DELETE'],
277 action='delete', conditions={'method': ['DELETE'],
280 'function': check_group},
278 'function': check_group},
281 requirements=URL_NAME_REQUIREMENTS)
279 requirements=URL_NAME_REQUIREMENTS)
282
280
283 # ADMIN USER ROUTES
281 # ADMIN USER ROUTES
284 with rmap.submapper(path_prefix=ADMIN_PREFIX,
282 with rmap.submapper(path_prefix=ADMIN_PREFIX,
285 controller='admin/users') as m:
283 controller='admin/users') as m:
286 m.connect('users', '/users',
284 m.connect('users', '/users',
287 action='create', conditions={'method': ['POST']})
285 action='create', conditions={'method': ['POST']})
288 m.connect('new_user', '/users/new',
286 m.connect('new_user', '/users/new',
289 action='new', conditions={'method': ['GET']})
287 action='new', conditions={'method': ['GET']})
290 m.connect('update_user', '/users/{user_id}',
288 m.connect('update_user', '/users/{user_id}',
291 action='update', conditions={'method': ['PUT']})
289 action='update', conditions={'method': ['PUT']})
292 m.connect('delete_user', '/users/{user_id}',
290 m.connect('delete_user', '/users/{user_id}',
293 action='delete', conditions={'method': ['DELETE']})
291 action='delete', conditions={'method': ['DELETE']})
294 m.connect('edit_user', '/users/{user_id}/edit',
292 m.connect('edit_user', '/users/{user_id}/edit',
295 action='edit', conditions={'method': ['GET']}, jsroute=True)
293 action='edit', conditions={'method': ['GET']}, jsroute=True)
296 m.connect('user', '/users/{user_id}',
294 m.connect('user', '/users/{user_id}',
297 action='show', conditions={'method': ['GET']})
295 action='show', conditions={'method': ['GET']})
298 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
296 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
299 action='reset_password', conditions={'method': ['POST']})
297 action='reset_password', conditions={'method': ['POST']})
300 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
298 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
301 action='create_personal_repo_group', conditions={'method': ['POST']})
299 action='create_personal_repo_group', conditions={'method': ['POST']})
302
300
303 # EXTRAS USER ROUTES
301 # EXTRAS USER ROUTES
304 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
302 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
305 action='edit_advanced', conditions={'method': ['GET']})
303 action='edit_advanced', conditions={'method': ['GET']})
306 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
304 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
307 action='update_advanced', conditions={'method': ['PUT']})
305 action='update_advanced', conditions={'method': ['PUT']})
308
306
309 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
307 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
310 action='edit_global_perms', conditions={'method': ['GET']})
308 action='edit_global_perms', conditions={'method': ['GET']})
311 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
309 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
312 action='update_global_perms', conditions={'method': ['PUT']})
310 action='update_global_perms', conditions={'method': ['PUT']})
313
311
314 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
312 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
315 action='edit_perms_summary', conditions={'method': ['GET']})
313 action='edit_perms_summary', conditions={'method': ['GET']})
316
314
317 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
315 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
318 action='edit_emails', conditions={'method': ['GET']})
316 action='edit_emails', conditions={'method': ['GET']})
319 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
317 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
320 action='add_email', conditions={'method': ['PUT']})
318 action='add_email', conditions={'method': ['PUT']})
321 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
319 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
322 action='delete_email', conditions={'method': ['DELETE']})
320 action='delete_email', conditions={'method': ['DELETE']})
323
321
324 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
322 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
325 action='edit_ips', conditions={'method': ['GET']})
323 action='edit_ips', conditions={'method': ['GET']})
326 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
324 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
327 action='add_ip', conditions={'method': ['PUT']})
325 action='add_ip', conditions={'method': ['PUT']})
328 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
326 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
329 action='delete_ip', conditions={'method': ['DELETE']})
327 action='delete_ip', conditions={'method': ['DELETE']})
330
328
331 # ADMIN USER GROUPS REST ROUTES
329 # ADMIN USER GROUPS REST ROUTES
332 with rmap.submapper(path_prefix=ADMIN_PREFIX,
330 with rmap.submapper(path_prefix=ADMIN_PREFIX,
333 controller='admin/user_groups') as m:
331 controller='admin/user_groups') as m:
334 m.connect('users_groups', '/user_groups',
332 m.connect('users_groups', '/user_groups',
335 action='create', conditions={'method': ['POST']})
333 action='create', conditions={'method': ['POST']})
336 m.connect('users_groups', '/user_groups',
334 m.connect('users_groups', '/user_groups',
337 action='index', conditions={'method': ['GET']})
335 action='index', conditions={'method': ['GET']})
338 m.connect('new_users_group', '/user_groups/new',
336 m.connect('new_users_group', '/user_groups/new',
339 action='new', conditions={'method': ['GET']})
337 action='new', conditions={'method': ['GET']})
340 m.connect('update_users_group', '/user_groups/{user_group_id}',
338 m.connect('update_users_group', '/user_groups/{user_group_id}',
341 action='update', conditions={'method': ['PUT']})
339 action='update', conditions={'method': ['PUT']})
342 m.connect('delete_users_group', '/user_groups/{user_group_id}',
340 m.connect('delete_users_group', '/user_groups/{user_group_id}',
343 action='delete', conditions={'method': ['DELETE']})
341 action='delete', conditions={'method': ['DELETE']})
344 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
342 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
345 action='edit', conditions={'method': ['GET']},
343 action='edit', conditions={'method': ['GET']},
346 function=check_user_group)
344 function=check_user_group)
347
345
348 # EXTRAS USER GROUP ROUTES
346 # EXTRAS USER GROUP ROUTES
349 m.connect('edit_user_group_global_perms',
347 m.connect('edit_user_group_global_perms',
350 '/user_groups/{user_group_id}/edit/global_permissions',
348 '/user_groups/{user_group_id}/edit/global_permissions',
351 action='edit_global_perms', conditions={'method': ['GET']})
349 action='edit_global_perms', conditions={'method': ['GET']})
352 m.connect('edit_user_group_global_perms',
350 m.connect('edit_user_group_global_perms',
353 '/user_groups/{user_group_id}/edit/global_permissions',
351 '/user_groups/{user_group_id}/edit/global_permissions',
354 action='update_global_perms', conditions={'method': ['PUT']})
352 action='update_global_perms', conditions={'method': ['PUT']})
355 m.connect('edit_user_group_perms_summary',
353 m.connect('edit_user_group_perms_summary',
356 '/user_groups/{user_group_id}/edit/permissions_summary',
354 '/user_groups/{user_group_id}/edit/permissions_summary',
357 action='edit_perms_summary', conditions={'method': ['GET']})
355 action='edit_perms_summary', conditions={'method': ['GET']})
358
356
359 m.connect('edit_user_group_perms',
357 m.connect('edit_user_group_perms',
360 '/user_groups/{user_group_id}/edit/permissions',
358 '/user_groups/{user_group_id}/edit/permissions',
361 action='edit_perms', conditions={'method': ['GET']})
359 action='edit_perms', conditions={'method': ['GET']})
362 m.connect('edit_user_group_perms',
360 m.connect('edit_user_group_perms',
363 '/user_groups/{user_group_id}/edit/permissions',
361 '/user_groups/{user_group_id}/edit/permissions',
364 action='update_perms', conditions={'method': ['PUT']})
362 action='update_perms', conditions={'method': ['PUT']})
365
363
366 m.connect('edit_user_group_advanced',
364 m.connect('edit_user_group_advanced',
367 '/user_groups/{user_group_id}/edit/advanced',
365 '/user_groups/{user_group_id}/edit/advanced',
368 action='edit_advanced', conditions={'method': ['GET']})
366 action='edit_advanced', conditions={'method': ['GET']})
369
367
370 m.connect('edit_user_group_advanced_sync',
368 m.connect('edit_user_group_advanced_sync',
371 '/user_groups/{user_group_id}/edit/advanced/sync',
369 '/user_groups/{user_group_id}/edit/advanced/sync',
372 action='edit_advanced_set_synchronization', conditions={'method': ['POST']})
370 action='edit_advanced_set_synchronization', conditions={'method': ['POST']})
373
371
374 m.connect('edit_user_group_members',
372 m.connect('edit_user_group_members',
375 '/user_groups/{user_group_id}/edit/members', jsroute=True,
373 '/user_groups/{user_group_id}/edit/members', jsroute=True,
376 action='user_group_members', conditions={'method': ['GET']})
374 action='user_group_members', conditions={'method': ['GET']})
377
375
378 # ADMIN PERMISSIONS ROUTES
376 # ADMIN PERMISSIONS ROUTES
379 with rmap.submapper(path_prefix=ADMIN_PREFIX,
377 with rmap.submapper(path_prefix=ADMIN_PREFIX,
380 controller='admin/permissions') as m:
378 controller='admin/permissions') as m:
381 m.connect('admin_permissions_application', '/permissions/application',
379 m.connect('admin_permissions_application', '/permissions/application',
382 action='permission_application_update', conditions={'method': ['POST']})
380 action='permission_application_update', conditions={'method': ['POST']})
383 m.connect('admin_permissions_application', '/permissions/application',
381 m.connect('admin_permissions_application', '/permissions/application',
384 action='permission_application', conditions={'method': ['GET']})
382 action='permission_application', conditions={'method': ['GET']})
385
383
386 m.connect('admin_permissions_global', '/permissions/global',
384 m.connect('admin_permissions_global', '/permissions/global',
387 action='permission_global_update', conditions={'method': ['POST']})
385 action='permission_global_update', conditions={'method': ['POST']})
388 m.connect('admin_permissions_global', '/permissions/global',
386 m.connect('admin_permissions_global', '/permissions/global',
389 action='permission_global', conditions={'method': ['GET']})
387 action='permission_global', conditions={'method': ['GET']})
390
388
391 m.connect('admin_permissions_object', '/permissions/object',
389 m.connect('admin_permissions_object', '/permissions/object',
392 action='permission_objects_update', conditions={'method': ['POST']})
390 action='permission_objects_update', conditions={'method': ['POST']})
393 m.connect('admin_permissions_object', '/permissions/object',
391 m.connect('admin_permissions_object', '/permissions/object',
394 action='permission_objects', conditions={'method': ['GET']})
392 action='permission_objects', conditions={'method': ['GET']})
395
393
396 m.connect('admin_permissions_ips', '/permissions/ips',
394 m.connect('admin_permissions_ips', '/permissions/ips',
397 action='permission_ips', conditions={'method': ['POST']})
395 action='permission_ips', conditions={'method': ['POST']})
398 m.connect('admin_permissions_ips', '/permissions/ips',
396 m.connect('admin_permissions_ips', '/permissions/ips',
399 action='permission_ips', conditions={'method': ['GET']})
397 action='permission_ips', conditions={'method': ['GET']})
400
398
401 m.connect('admin_permissions_overview', '/permissions/overview',
399 m.connect('admin_permissions_overview', '/permissions/overview',
402 action='permission_perms', conditions={'method': ['GET']})
400 action='permission_perms', conditions={'method': ['GET']})
403
401
404 # ADMIN DEFAULTS REST ROUTES
402 # ADMIN DEFAULTS REST ROUTES
405 with rmap.submapper(path_prefix=ADMIN_PREFIX,
403 with rmap.submapper(path_prefix=ADMIN_PREFIX,
406 controller='admin/defaults') as m:
404 controller='admin/defaults') as m:
407 m.connect('admin_defaults_repositories', '/defaults/repositories',
405 m.connect('admin_defaults_repositories', '/defaults/repositories',
408 action='update_repository_defaults', conditions={'method': ['POST']})
406 action='update_repository_defaults', conditions={'method': ['POST']})
409 m.connect('admin_defaults_repositories', '/defaults/repositories',
407 m.connect('admin_defaults_repositories', '/defaults/repositories',
410 action='index', conditions={'method': ['GET']})
408 action='index', conditions={'method': ['GET']})
411
409
412 # ADMIN DEBUG STYLE ROUTES
410 # ADMIN DEBUG STYLE ROUTES
413 if str2bool(config.get('debug_style')):
411 if str2bool(config.get('debug_style')):
414 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
412 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
415 controller='debug_style') as m:
413 controller='debug_style') as m:
416 m.connect('debug_style_home', '',
414 m.connect('debug_style_home', '',
417 action='index', conditions={'method': ['GET']})
415 action='index', conditions={'method': ['GET']})
418 m.connect('debug_style_template', '/t/{t_path}',
416 m.connect('debug_style_template', '/t/{t_path}',
419 action='template', conditions={'method': ['GET']})
417 action='template', conditions={'method': ['GET']})
420
418
421 # ADMIN SETTINGS ROUTES
419 # ADMIN SETTINGS ROUTES
422 with rmap.submapper(path_prefix=ADMIN_PREFIX,
420 with rmap.submapper(path_prefix=ADMIN_PREFIX,
423 controller='admin/settings') as m:
421 controller='admin/settings') as m:
424
422
425 # default
423 # default
426 m.connect('admin_settings', '/settings',
424 m.connect('admin_settings', '/settings',
427 action='settings_global_update',
425 action='settings_global_update',
428 conditions={'method': ['POST']})
426 conditions={'method': ['POST']})
429 m.connect('admin_settings', '/settings',
427 m.connect('admin_settings', '/settings',
430 action='settings_global', conditions={'method': ['GET']})
428 action='settings_global', conditions={'method': ['GET']})
431
429
432 m.connect('admin_settings_vcs', '/settings/vcs',
430 m.connect('admin_settings_vcs', '/settings/vcs',
433 action='settings_vcs_update',
431 action='settings_vcs_update',
434 conditions={'method': ['POST']})
432 conditions={'method': ['POST']})
435 m.connect('admin_settings_vcs', '/settings/vcs',
433 m.connect('admin_settings_vcs', '/settings/vcs',
436 action='settings_vcs',
434 action='settings_vcs',
437 conditions={'method': ['GET']})
435 conditions={'method': ['GET']})
438 m.connect('admin_settings_vcs', '/settings/vcs',
436 m.connect('admin_settings_vcs', '/settings/vcs',
439 action='delete_svn_pattern',
437 action='delete_svn_pattern',
440 conditions={'method': ['DELETE']})
438 conditions={'method': ['DELETE']})
441
439
442 m.connect('admin_settings_mapping', '/settings/mapping',
440 m.connect('admin_settings_mapping', '/settings/mapping',
443 action='settings_mapping_update',
441 action='settings_mapping_update',
444 conditions={'method': ['POST']})
442 conditions={'method': ['POST']})
445 m.connect('admin_settings_mapping', '/settings/mapping',
443 m.connect('admin_settings_mapping', '/settings/mapping',
446 action='settings_mapping', conditions={'method': ['GET']})
444 action='settings_mapping', conditions={'method': ['GET']})
447
445
448 m.connect('admin_settings_global', '/settings/global',
446 m.connect('admin_settings_global', '/settings/global',
449 action='settings_global_update',
447 action='settings_global_update',
450 conditions={'method': ['POST']})
448 conditions={'method': ['POST']})
451 m.connect('admin_settings_global', '/settings/global',
449 m.connect('admin_settings_global', '/settings/global',
452 action='settings_global', conditions={'method': ['GET']})
450 action='settings_global', conditions={'method': ['GET']})
453
451
454 m.connect('admin_settings_visual', '/settings/visual',
452 m.connect('admin_settings_visual', '/settings/visual',
455 action='settings_visual_update',
453 action='settings_visual_update',
456 conditions={'method': ['POST']})
454 conditions={'method': ['POST']})
457 m.connect('admin_settings_visual', '/settings/visual',
455 m.connect('admin_settings_visual', '/settings/visual',
458 action='settings_visual', conditions={'method': ['GET']})
456 action='settings_visual', conditions={'method': ['GET']})
459
457
460 m.connect('admin_settings_issuetracker',
458 m.connect('admin_settings_issuetracker',
461 '/settings/issue-tracker', action='settings_issuetracker',
459 '/settings/issue-tracker', action='settings_issuetracker',
462 conditions={'method': ['GET']})
460 conditions={'method': ['GET']})
463 m.connect('admin_settings_issuetracker_save',
461 m.connect('admin_settings_issuetracker_save',
464 '/settings/issue-tracker/save',
462 '/settings/issue-tracker/save',
465 action='settings_issuetracker_save',
463 action='settings_issuetracker_save',
466 conditions={'method': ['POST']})
464 conditions={'method': ['POST']})
467 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
465 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
468 action='settings_issuetracker_test',
466 action='settings_issuetracker_test',
469 conditions={'method': ['POST']})
467 conditions={'method': ['POST']})
470 m.connect('admin_issuetracker_delete',
468 m.connect('admin_issuetracker_delete',
471 '/settings/issue-tracker/delete',
469 '/settings/issue-tracker/delete',
472 action='settings_issuetracker_delete',
470 action='settings_issuetracker_delete',
473 conditions={'method': ['DELETE']})
471 conditions={'method': ['DELETE']})
474
472
475 m.connect('admin_settings_email', '/settings/email',
473 m.connect('admin_settings_email', '/settings/email',
476 action='settings_email_update',
474 action='settings_email_update',
477 conditions={'method': ['POST']})
475 conditions={'method': ['POST']})
478 m.connect('admin_settings_email', '/settings/email',
476 m.connect('admin_settings_email', '/settings/email',
479 action='settings_email', conditions={'method': ['GET']})
477 action='settings_email', conditions={'method': ['GET']})
480
478
481 m.connect('admin_settings_hooks', '/settings/hooks',
479 m.connect('admin_settings_hooks', '/settings/hooks',
482 action='settings_hooks_update',
480 action='settings_hooks_update',
483 conditions={'method': ['POST', 'DELETE']})
481 conditions={'method': ['POST', 'DELETE']})
484 m.connect('admin_settings_hooks', '/settings/hooks',
482 m.connect('admin_settings_hooks', '/settings/hooks',
485 action='settings_hooks', conditions={'method': ['GET']})
483 action='settings_hooks', conditions={'method': ['GET']})
486
484
487 m.connect('admin_settings_search', '/settings/search',
485 m.connect('admin_settings_search', '/settings/search',
488 action='settings_search', conditions={'method': ['GET']})
486 action='settings_search', conditions={'method': ['GET']})
489
487
490 m.connect('admin_settings_supervisor', '/settings/supervisor',
488 m.connect('admin_settings_supervisor', '/settings/supervisor',
491 action='settings_supervisor', conditions={'method': ['GET']})
489 action='settings_supervisor', conditions={'method': ['GET']})
492 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
490 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
493 action='settings_supervisor_log', conditions={'method': ['GET']})
491 action='settings_supervisor_log', conditions={'method': ['GET']})
494
492
495 m.connect('admin_settings_labs', '/settings/labs',
493 m.connect('admin_settings_labs', '/settings/labs',
496 action='settings_labs_update',
494 action='settings_labs_update',
497 conditions={'method': ['POST']})
495 conditions={'method': ['POST']})
498 m.connect('admin_settings_labs', '/settings/labs',
496 m.connect('admin_settings_labs', '/settings/labs',
499 action='settings_labs', conditions={'method': ['GET']})
497 action='settings_labs', conditions={'method': ['GET']})
500
498
501 # ADMIN MY ACCOUNT
499 # ADMIN MY ACCOUNT
502 with rmap.submapper(path_prefix=ADMIN_PREFIX,
500 with rmap.submapper(path_prefix=ADMIN_PREFIX,
503 controller='admin/my_account') as m:
501 controller='admin/my_account') as m:
504
502
505 m.connect('my_account_edit', '/my_account/edit',
503 m.connect('my_account_edit', '/my_account/edit',
506 action='my_account_edit', conditions={'method': ['GET']})
504 action='my_account_edit', conditions={'method': ['GET']})
507 m.connect('my_account', '/my_account/update',
505 m.connect('my_account', '/my_account/update',
508 action='my_account_update', conditions={'method': ['POST']})
506 action='my_account_update', conditions={'method': ['POST']})
509
507
510 # NOTE(marcink): this needs to be kept for password force flag to be
508 # NOTE(marcink): this needs to be kept for password force flag to be
511 # handler, remove after migration to pyramid
509 # handler, remove after migration to pyramid
512 m.connect('my_account_password', '/my_account/password',
510 m.connect('my_account_password', '/my_account/password',
513 action='my_account_password', conditions={'method': ['GET']})
511 action='my_account_password', conditions={'method': ['GET']})
514
512
515 m.connect('my_account_repos', '/my_account/repos',
513 m.connect('my_account_repos', '/my_account/repos',
516 action='my_account_repos', conditions={'method': ['GET']})
514 action='my_account_repos', conditions={'method': ['GET']})
517
515
518 m.connect('my_account_watched', '/my_account/watched',
516 m.connect('my_account_watched', '/my_account/watched',
519 action='my_account_watched', conditions={'method': ['GET']})
517 action='my_account_watched', conditions={'method': ['GET']})
520
518
521 m.connect('my_account_pullrequests', '/my_account/pull_requests',
519 m.connect('my_account_pullrequests', '/my_account/pull_requests',
522 action='my_account_pullrequests', conditions={'method': ['GET']})
520 action='my_account_pullrequests', conditions={'method': ['GET']})
523
521
524 m.connect('my_account_perms', '/my_account/perms',
522 m.connect('my_account_perms', '/my_account/perms',
525 action='my_account_perms', conditions={'method': ['GET']})
523 action='my_account_perms', conditions={'method': ['GET']})
526
524
527 m.connect('my_account_emails', '/my_account/emails',
525 m.connect('my_account_emails', '/my_account/emails',
528 action='my_account_emails', conditions={'method': ['GET']})
526 action='my_account_emails', conditions={'method': ['GET']})
529 m.connect('my_account_emails', '/my_account/emails',
527 m.connect('my_account_emails', '/my_account/emails',
530 action='my_account_emails_add', conditions={'method': ['POST']})
528 action='my_account_emails_add', conditions={'method': ['POST']})
531 m.connect('my_account_emails', '/my_account/emails',
529 m.connect('my_account_emails', '/my_account/emails',
532 action='my_account_emails_delete', conditions={'method': ['DELETE']})
530 action='my_account_emails_delete', conditions={'method': ['DELETE']})
533
531
534 m.connect('my_account_notifications', '/my_account/notifications',
532 m.connect('my_account_notifications', '/my_account/notifications',
535 action='my_notifications',
533 action='my_notifications',
536 conditions={'method': ['GET']})
534 conditions={'method': ['GET']})
537 m.connect('my_account_notifications_toggle_visibility',
535 m.connect('my_account_notifications_toggle_visibility',
538 '/my_account/toggle_visibility',
536 '/my_account/toggle_visibility',
539 action='my_notifications_toggle_visibility',
537 action='my_notifications_toggle_visibility',
540 conditions={'method': ['POST']})
538 conditions={'method': ['POST']})
541 m.connect('my_account_notifications_test_channelstream',
539 m.connect('my_account_notifications_test_channelstream',
542 '/my_account/test_channelstream',
540 '/my_account/test_channelstream',
543 action='my_account_notifications_test_channelstream',
541 action='my_account_notifications_test_channelstream',
544 conditions={'method': ['POST']})
542 conditions={'method': ['POST']})
545
543
546 # NOTIFICATION REST ROUTES
544 # NOTIFICATION REST ROUTES
547 with rmap.submapper(path_prefix=ADMIN_PREFIX,
545 with rmap.submapper(path_prefix=ADMIN_PREFIX,
548 controller='admin/notifications') as m:
546 controller='admin/notifications') as m:
549 m.connect('notifications', '/notifications',
547 m.connect('notifications', '/notifications',
550 action='index', conditions={'method': ['GET']})
548 action='index', conditions={'method': ['GET']})
551 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
549 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
552 action='mark_all_read', conditions={'method': ['POST']})
550 action='mark_all_read', conditions={'method': ['POST']})
553 m.connect('/notifications/{notification_id}',
551 m.connect('/notifications/{notification_id}',
554 action='update', conditions={'method': ['PUT']})
552 action='update', conditions={'method': ['PUT']})
555 m.connect('/notifications/{notification_id}',
553 m.connect('/notifications/{notification_id}',
556 action='delete', conditions={'method': ['DELETE']})
554 action='delete', conditions={'method': ['DELETE']})
557 m.connect('notification', '/notifications/{notification_id}',
555 m.connect('notification', '/notifications/{notification_id}',
558 action='show', conditions={'method': ['GET']})
556 action='show', conditions={'method': ['GET']})
559
557
560 # ADMIN GIST
558 # ADMIN GIST
561 with rmap.submapper(path_prefix=ADMIN_PREFIX,
559 with rmap.submapper(path_prefix=ADMIN_PREFIX,
562 controller='admin/gists') as m:
560 controller='admin/gists') as m:
563 m.connect('gists', '/gists',
561 m.connect('gists', '/gists',
564 action='create', conditions={'method': ['POST']})
562 action='create', conditions={'method': ['POST']})
565 m.connect('gists', '/gists', jsroute=True,
563 m.connect('gists', '/gists', jsroute=True,
566 action='index', conditions={'method': ['GET']})
564 action='index', conditions={'method': ['GET']})
567 m.connect('new_gist', '/gists/new', jsroute=True,
565 m.connect('new_gist', '/gists/new', jsroute=True,
568 action='new', conditions={'method': ['GET']})
566 action='new', conditions={'method': ['GET']})
569
567
570 m.connect('/gists/{gist_id}',
568 m.connect('/gists/{gist_id}',
571 action='delete', conditions={'method': ['DELETE']})
569 action='delete', conditions={'method': ['DELETE']})
572 m.connect('edit_gist', '/gists/{gist_id}/edit',
570 m.connect('edit_gist', '/gists/{gist_id}/edit',
573 action='edit_form', conditions={'method': ['GET']})
571 action='edit_form', conditions={'method': ['GET']})
574 m.connect('edit_gist', '/gists/{gist_id}/edit',
572 m.connect('edit_gist', '/gists/{gist_id}/edit',
575 action='edit', conditions={'method': ['POST']})
573 action='edit', conditions={'method': ['POST']})
576 m.connect(
574 m.connect(
577 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
575 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
578 action='check_revision', conditions={'method': ['GET']})
576 action='check_revision', conditions={'method': ['GET']})
579
577
580 m.connect('gist', '/gists/{gist_id}',
578 m.connect('gist', '/gists/{gist_id}',
581 action='show', conditions={'method': ['GET']})
579 action='show', conditions={'method': ['GET']})
582 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
580 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
583 revision='tip',
581 revision='tip',
584 action='show', conditions={'method': ['GET']})
582 action='show', conditions={'method': ['GET']})
585 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
583 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
586 revision='tip',
584 revision='tip',
587 action='show', conditions={'method': ['GET']})
585 action='show', conditions={'method': ['GET']})
588 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
586 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
589 revision='tip',
587 revision='tip',
590 action='show', conditions={'method': ['GET']},
588 action='show', conditions={'method': ['GET']},
591 requirements=URL_NAME_REQUIREMENTS)
589 requirements=URL_NAME_REQUIREMENTS)
592
590
593 # ADMIN MAIN PAGES
591 # ADMIN MAIN PAGES
594 with rmap.submapper(path_prefix=ADMIN_PREFIX,
592 with rmap.submapper(path_prefix=ADMIN_PREFIX,
595 controller='admin/admin') as m:
593 controller='admin/admin') as m:
596 m.connect('admin_home', '', action='index')
594 m.connect('admin_home', '', action='index')
597 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
595 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
598 action='add_repo')
596 action='add_repo')
599 m.connect(
597 m.connect(
600 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
598 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
601 action='pull_requests')
599 action='pull_requests')
602 m.connect(
600 m.connect(
603 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
601 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
604 action='pull_requests')
602 action='pull_requests')
605 m.connect(
603 m.connect(
606 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
604 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
607 action='pull_requests')
605 action='pull_requests')
608
606
609 # USER JOURNAL
607 # USER JOURNAL
610 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
608 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
611 controller='journal', action='index')
609 controller='journal', action='index')
612 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
610 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
613 controller='journal', action='journal_rss')
611 controller='journal', action='journal_rss')
614 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
612 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
615 controller='journal', action='journal_atom')
613 controller='journal', action='journal_atom')
616
614
617 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
615 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
618 controller='journal', action='public_journal')
616 controller='journal', action='public_journal')
619
617
620 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
618 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
621 controller='journal', action='public_journal_rss')
619 controller='journal', action='public_journal_rss')
622
620
623 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
621 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
624 controller='journal', action='public_journal_rss')
622 controller='journal', action='public_journal_rss')
625
623
626 rmap.connect('public_journal_atom',
624 rmap.connect('public_journal_atom',
627 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
625 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
628 action='public_journal_atom')
626 action='public_journal_atom')
629
627
630 rmap.connect('public_journal_atom_old',
628 rmap.connect('public_journal_atom_old',
631 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
629 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
632 action='public_journal_atom')
630 action='public_journal_atom')
633
631
634 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
632 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
635 controller='journal', action='toggle_following', jsroute=True,
633 controller='journal', action='toggle_following', jsroute=True,
636 conditions={'method': ['POST']})
634 conditions={'method': ['POST']})
637
635
638 # FULL TEXT SEARCH
636 # FULL TEXT SEARCH
639 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
637 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
640 controller='search')
638 controller='search')
641 rmap.connect('search_repo_home', '/{repo_name}/search',
639 rmap.connect('search_repo_home', '/{repo_name}/search',
642 controller='search',
640 controller='search',
643 action='index',
641 action='index',
644 conditions={'function': check_repo},
642 conditions={'function': check_repo},
645 requirements=URL_NAME_REQUIREMENTS)
643 requirements=URL_NAME_REQUIREMENTS)
646
644
647 # FEEDS
645 # FEEDS
648 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
646 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
649 controller='feed', action='rss',
647 controller='feed', action='rss',
650 conditions={'function': check_repo},
648 conditions={'function': check_repo},
651 requirements=URL_NAME_REQUIREMENTS)
649 requirements=URL_NAME_REQUIREMENTS)
652
650
653 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
651 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
654 controller='feed', action='atom',
652 controller='feed', action='atom',
655 conditions={'function': check_repo},
653 conditions={'function': check_repo},
656 requirements=URL_NAME_REQUIREMENTS)
654 requirements=URL_NAME_REQUIREMENTS)
657
655
658 #==========================================================================
656 #==========================================================================
659 # REPOSITORY ROUTES
657 # REPOSITORY ROUTES
660 #==========================================================================
658 #==========================================================================
661
659
662 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
660 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
663 controller='admin/repos', action='repo_creating',
661 controller='admin/repos', action='repo_creating',
664 requirements=URL_NAME_REQUIREMENTS)
662 requirements=URL_NAME_REQUIREMENTS)
665 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
663 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
666 controller='admin/repos', action='repo_check',
664 controller='admin/repos', action='repo_check',
667 requirements=URL_NAME_REQUIREMENTS)
665 requirements=URL_NAME_REQUIREMENTS)
668
666
669 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
667 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
670 controller='summary', action='repo_stats',
668 controller='summary', action='repo_stats',
671 conditions={'function': check_repo},
669 conditions={'function': check_repo},
672 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
670 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
673
671
674 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
672 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
675 controller='summary', action='repo_refs_data',
673 controller='summary', action='repo_refs_data',
676 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
674 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
677 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
675 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
678 controller='summary', action='repo_refs_changelog_data',
676 controller='summary', action='repo_refs_changelog_data',
679 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
677 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
680 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
678 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
681 controller='summary', action='repo_default_reviewers_data',
679 controller='summary', action='repo_default_reviewers_data',
682 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
680 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
683
681
684 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
682 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
685 controller='changeset', revision='tip',
683 controller='changeset', revision='tip',
686 conditions={'function': check_repo},
684 conditions={'function': check_repo},
687 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
685 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
688 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
686 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
689 controller='changeset', revision='tip', action='changeset_children',
687 controller='changeset', revision='tip', action='changeset_children',
690 conditions={'function': check_repo},
688 conditions={'function': check_repo},
691 requirements=URL_NAME_REQUIREMENTS)
689 requirements=URL_NAME_REQUIREMENTS)
692 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
690 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
693 controller='changeset', revision='tip', action='changeset_parents',
691 controller='changeset', revision='tip', action='changeset_parents',
694 conditions={'function': check_repo},
692 conditions={'function': check_repo},
695 requirements=URL_NAME_REQUIREMENTS)
693 requirements=URL_NAME_REQUIREMENTS)
696
694
697 # repo edit options
695 # repo edit options
698 rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True,
696 rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True,
699 controller='admin/repos', action='edit',
697 controller='admin/repos', action='edit',
700 conditions={'method': ['GET'], 'function': check_repo},
698 conditions={'method': ['GET'], 'function': check_repo},
701 requirements=URL_NAME_REQUIREMENTS)
699 requirements=URL_NAME_REQUIREMENTS)
702
700
703 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
701 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
704 jsroute=True,
702 jsroute=True,
705 controller='admin/repos', action='edit_permissions',
703 controller='admin/repos', action='edit_permissions',
706 conditions={'method': ['GET'], 'function': check_repo},
704 conditions={'method': ['GET'], 'function': check_repo},
707 requirements=URL_NAME_REQUIREMENTS)
705 requirements=URL_NAME_REQUIREMENTS)
708 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
706 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
709 controller='admin/repos', action='edit_permissions_update',
707 controller='admin/repos', action='edit_permissions_update',
710 conditions={'method': ['PUT'], 'function': check_repo},
708 conditions={'method': ['PUT'], 'function': check_repo},
711 requirements=URL_NAME_REQUIREMENTS)
709 requirements=URL_NAME_REQUIREMENTS)
712
710
713 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
711 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
714 controller='admin/repos', action='edit_fields',
712 controller='admin/repos', action='edit_fields',
715 conditions={'method': ['GET'], 'function': check_repo},
713 conditions={'method': ['GET'], 'function': check_repo},
716 requirements=URL_NAME_REQUIREMENTS)
714 requirements=URL_NAME_REQUIREMENTS)
717 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
715 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
718 controller='admin/repos', action='create_repo_field',
716 controller='admin/repos', action='create_repo_field',
719 conditions={'method': ['PUT'], 'function': check_repo},
717 conditions={'method': ['PUT'], 'function': check_repo},
720 requirements=URL_NAME_REQUIREMENTS)
718 requirements=URL_NAME_REQUIREMENTS)
721 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
719 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
722 controller='admin/repos', action='delete_repo_field',
720 controller='admin/repos', action='delete_repo_field',
723 conditions={'method': ['DELETE'], 'function': check_repo},
721 conditions={'method': ['DELETE'], 'function': check_repo},
724 requirements=URL_NAME_REQUIREMENTS)
722 requirements=URL_NAME_REQUIREMENTS)
725
723
726 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
724 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
727 controller='admin/repos', action='edit_advanced',
725 controller='admin/repos', action='edit_advanced',
728 conditions={'method': ['GET'], 'function': check_repo},
726 conditions={'method': ['GET'], 'function': check_repo},
729 requirements=URL_NAME_REQUIREMENTS)
727 requirements=URL_NAME_REQUIREMENTS)
730
728
731 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
729 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
732 controller='admin/repos', action='edit_advanced_locking',
730 controller='admin/repos', action='edit_advanced_locking',
733 conditions={'method': ['PUT'], 'function': check_repo},
731 conditions={'method': ['PUT'], 'function': check_repo},
734 requirements=URL_NAME_REQUIREMENTS)
732 requirements=URL_NAME_REQUIREMENTS)
735 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
733 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
736 controller='admin/repos', action='toggle_locking',
734 controller='admin/repos', action='toggle_locking',
737 conditions={'method': ['GET'], 'function': check_repo},
735 conditions={'method': ['GET'], 'function': check_repo},
738 requirements=URL_NAME_REQUIREMENTS)
736 requirements=URL_NAME_REQUIREMENTS)
739
737
740 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
738 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
741 controller='admin/repos', action='edit_advanced_journal',
739 controller='admin/repos', action='edit_advanced_journal',
742 conditions={'method': ['PUT'], 'function': check_repo},
740 conditions={'method': ['PUT'], 'function': check_repo},
743 requirements=URL_NAME_REQUIREMENTS)
741 requirements=URL_NAME_REQUIREMENTS)
744
742
745 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
743 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
746 controller='admin/repos', action='edit_advanced_fork',
744 controller='admin/repos', action='edit_advanced_fork',
747 conditions={'method': ['PUT'], 'function': check_repo},
745 conditions={'method': ['PUT'], 'function': check_repo},
748 requirements=URL_NAME_REQUIREMENTS)
746 requirements=URL_NAME_REQUIREMENTS)
749
747
750 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
748 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
751 controller='admin/repos', action='edit_caches_form',
749 controller='admin/repos', action='edit_caches_form',
752 conditions={'method': ['GET'], 'function': check_repo},
750 conditions={'method': ['GET'], 'function': check_repo},
753 requirements=URL_NAME_REQUIREMENTS)
751 requirements=URL_NAME_REQUIREMENTS)
754 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
752 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
755 controller='admin/repos', action='edit_caches',
753 controller='admin/repos', action='edit_caches',
756 conditions={'method': ['PUT'], 'function': check_repo},
754 conditions={'method': ['PUT'], 'function': check_repo},
757 requirements=URL_NAME_REQUIREMENTS)
755 requirements=URL_NAME_REQUIREMENTS)
758
756
759 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
757 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
760 controller='admin/repos', action='edit_remote_form',
758 controller='admin/repos', action='edit_remote_form',
761 conditions={'method': ['GET'], 'function': check_repo},
759 conditions={'method': ['GET'], 'function': check_repo},
762 requirements=URL_NAME_REQUIREMENTS)
760 requirements=URL_NAME_REQUIREMENTS)
763 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
761 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
764 controller='admin/repos', action='edit_remote',
762 controller='admin/repos', action='edit_remote',
765 conditions={'method': ['PUT'], 'function': check_repo},
763 conditions={'method': ['PUT'], 'function': check_repo},
766 requirements=URL_NAME_REQUIREMENTS)
764 requirements=URL_NAME_REQUIREMENTS)
767
765
768 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
766 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
769 controller='admin/repos', action='edit_statistics_form',
767 controller='admin/repos', action='edit_statistics_form',
770 conditions={'method': ['GET'], 'function': check_repo},
768 conditions={'method': ['GET'], 'function': check_repo},
771 requirements=URL_NAME_REQUIREMENTS)
769 requirements=URL_NAME_REQUIREMENTS)
772 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
770 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
773 controller='admin/repos', action='edit_statistics',
771 controller='admin/repos', action='edit_statistics',
774 conditions={'method': ['PUT'], 'function': check_repo},
772 conditions={'method': ['PUT'], 'function': check_repo},
775 requirements=URL_NAME_REQUIREMENTS)
773 requirements=URL_NAME_REQUIREMENTS)
776 rmap.connect('repo_settings_issuetracker',
774 rmap.connect('repo_settings_issuetracker',
777 '/{repo_name}/settings/issue-tracker',
775 '/{repo_name}/settings/issue-tracker',
778 controller='admin/repos', action='repo_issuetracker',
776 controller='admin/repos', action='repo_issuetracker',
779 conditions={'method': ['GET'], 'function': check_repo},
777 conditions={'method': ['GET'], 'function': check_repo},
780 requirements=URL_NAME_REQUIREMENTS)
778 requirements=URL_NAME_REQUIREMENTS)
781 rmap.connect('repo_issuetracker_test',
779 rmap.connect('repo_issuetracker_test',
782 '/{repo_name}/settings/issue-tracker/test',
780 '/{repo_name}/settings/issue-tracker/test',
783 controller='admin/repos', action='repo_issuetracker_test',
781 controller='admin/repos', action='repo_issuetracker_test',
784 conditions={'method': ['POST'], 'function': check_repo},
782 conditions={'method': ['POST'], 'function': check_repo},
785 requirements=URL_NAME_REQUIREMENTS)
783 requirements=URL_NAME_REQUIREMENTS)
786 rmap.connect('repo_issuetracker_delete',
784 rmap.connect('repo_issuetracker_delete',
787 '/{repo_name}/settings/issue-tracker/delete',
785 '/{repo_name}/settings/issue-tracker/delete',
788 controller='admin/repos', action='repo_issuetracker_delete',
786 controller='admin/repos', action='repo_issuetracker_delete',
789 conditions={'method': ['DELETE'], 'function': check_repo},
787 conditions={'method': ['DELETE'], 'function': check_repo},
790 requirements=URL_NAME_REQUIREMENTS)
788 requirements=URL_NAME_REQUIREMENTS)
791 rmap.connect('repo_issuetracker_save',
789 rmap.connect('repo_issuetracker_save',
792 '/{repo_name}/settings/issue-tracker/save',
790 '/{repo_name}/settings/issue-tracker/save',
793 controller='admin/repos', action='repo_issuetracker_save',
791 controller='admin/repos', action='repo_issuetracker_save',
794 conditions={'method': ['POST'], 'function': check_repo},
792 conditions={'method': ['POST'], 'function': check_repo},
795 requirements=URL_NAME_REQUIREMENTS)
793 requirements=URL_NAME_REQUIREMENTS)
796 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
794 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
797 controller='admin/repos', action='repo_settings_vcs_update',
795 controller='admin/repos', action='repo_settings_vcs_update',
798 conditions={'method': ['POST'], 'function': check_repo},
796 conditions={'method': ['POST'], 'function': check_repo},
799 requirements=URL_NAME_REQUIREMENTS)
797 requirements=URL_NAME_REQUIREMENTS)
800 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
798 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
801 controller='admin/repos', action='repo_settings_vcs',
799 controller='admin/repos', action='repo_settings_vcs',
802 conditions={'method': ['GET'], 'function': check_repo},
800 conditions={'method': ['GET'], 'function': check_repo},
803 requirements=URL_NAME_REQUIREMENTS)
801 requirements=URL_NAME_REQUIREMENTS)
804 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
802 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
805 controller='admin/repos', action='repo_delete_svn_pattern',
803 controller='admin/repos', action='repo_delete_svn_pattern',
806 conditions={'method': ['DELETE'], 'function': check_repo},
804 conditions={'method': ['DELETE'], 'function': check_repo},
807 requirements=URL_NAME_REQUIREMENTS)
805 requirements=URL_NAME_REQUIREMENTS)
808 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
806 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
809 controller='admin/repos', action='repo_settings_pullrequest',
807 controller='admin/repos', action='repo_settings_pullrequest',
810 conditions={'method': ['GET', 'POST'], 'function': check_repo},
808 conditions={'method': ['GET', 'POST'], 'function': check_repo},
811 requirements=URL_NAME_REQUIREMENTS)
809 requirements=URL_NAME_REQUIREMENTS)
812
810
813 # still working url for backward compat.
811 # still working url for backward compat.
814 rmap.connect('raw_changeset_home_depraced',
812 rmap.connect('raw_changeset_home_depraced',
815 '/{repo_name}/raw-changeset/{revision}',
813 '/{repo_name}/raw-changeset/{revision}',
816 controller='changeset', action='changeset_raw',
814 controller='changeset', action='changeset_raw',
817 revision='tip', conditions={'function': check_repo},
815 revision='tip', conditions={'function': check_repo},
818 requirements=URL_NAME_REQUIREMENTS)
816 requirements=URL_NAME_REQUIREMENTS)
819
817
820 # new URLs
818 # new URLs
821 rmap.connect('changeset_raw_home',
819 rmap.connect('changeset_raw_home',
822 '/{repo_name}/changeset-diff/{revision}',
820 '/{repo_name}/changeset-diff/{revision}',
823 controller='changeset', action='changeset_raw',
821 controller='changeset', action='changeset_raw',
824 revision='tip', conditions={'function': check_repo},
822 revision='tip', conditions={'function': check_repo},
825 requirements=URL_NAME_REQUIREMENTS)
823 requirements=URL_NAME_REQUIREMENTS)
826
824
827 rmap.connect('changeset_patch_home',
825 rmap.connect('changeset_patch_home',
828 '/{repo_name}/changeset-patch/{revision}',
826 '/{repo_name}/changeset-patch/{revision}',
829 controller='changeset', action='changeset_patch',
827 controller='changeset', action='changeset_patch',
830 revision='tip', conditions={'function': check_repo},
828 revision='tip', conditions={'function': check_repo},
831 requirements=URL_NAME_REQUIREMENTS)
829 requirements=URL_NAME_REQUIREMENTS)
832
830
833 rmap.connect('changeset_download_home',
831 rmap.connect('changeset_download_home',
834 '/{repo_name}/changeset-download/{revision}',
832 '/{repo_name}/changeset-download/{revision}',
835 controller='changeset', action='changeset_download',
833 controller='changeset', action='changeset_download',
836 revision='tip', conditions={'function': check_repo},
834 revision='tip', conditions={'function': check_repo},
837 requirements=URL_NAME_REQUIREMENTS)
835 requirements=URL_NAME_REQUIREMENTS)
838
836
839 rmap.connect('changeset_comment',
837 rmap.connect('changeset_comment',
840 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
838 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
841 controller='changeset', revision='tip', action='comment',
839 controller='changeset', revision='tip', action='comment',
842 conditions={'function': check_repo},
840 conditions={'function': check_repo},
843 requirements=URL_NAME_REQUIREMENTS)
841 requirements=URL_NAME_REQUIREMENTS)
844
842
845 rmap.connect('changeset_comment_preview',
843 rmap.connect('changeset_comment_preview',
846 '/{repo_name}/changeset/comment/preview', jsroute=True,
844 '/{repo_name}/changeset/comment/preview', jsroute=True,
847 controller='changeset', action='preview_comment',
845 controller='changeset', action='preview_comment',
848 conditions={'function': check_repo, 'method': ['POST']},
846 conditions={'function': check_repo, 'method': ['POST']},
849 requirements=URL_NAME_REQUIREMENTS)
847 requirements=URL_NAME_REQUIREMENTS)
850
848
851 rmap.connect('changeset_comment_delete',
849 rmap.connect('changeset_comment_delete',
852 '/{repo_name}/changeset/comment/{comment_id}/delete',
850 '/{repo_name}/changeset/comment/{comment_id}/delete',
853 controller='changeset', action='delete_comment',
851 controller='changeset', action='delete_comment',
854 conditions={'function': check_repo, 'method': ['DELETE']},
852 conditions={'function': check_repo, 'method': ['DELETE']},
855 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
853 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
856
854
857 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
855 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
858 controller='changeset', action='changeset_info',
856 controller='changeset', action='changeset_info',
859 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
857 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
860
858
861 rmap.connect('compare_home',
859 rmap.connect('compare_home',
862 '/{repo_name}/compare',
860 '/{repo_name}/compare',
863 controller='compare', action='index',
861 controller='compare', action='index',
864 conditions={'function': check_repo},
862 conditions={'function': check_repo},
865 requirements=URL_NAME_REQUIREMENTS)
863 requirements=URL_NAME_REQUIREMENTS)
866
864
867 rmap.connect('compare_url',
865 rmap.connect('compare_url',
868 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
866 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
869 controller='compare', action='compare',
867 controller='compare', action='compare',
870 conditions={'function': check_repo},
868 conditions={'function': check_repo},
871 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
869 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
872
870
873 rmap.connect('pullrequest_home',
871 rmap.connect('pullrequest_home',
874 '/{repo_name}/pull-request/new', controller='pullrequests',
872 '/{repo_name}/pull-request/new', controller='pullrequests',
875 action='index', conditions={'function': check_repo,
873 action='index', conditions={'function': check_repo,
876 'method': ['GET']},
874 'method': ['GET']},
877 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
875 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
878
876
879 rmap.connect('pullrequest',
877 rmap.connect('pullrequest',
880 '/{repo_name}/pull-request/new', controller='pullrequests',
878 '/{repo_name}/pull-request/new', controller='pullrequests',
881 action='create', conditions={'function': check_repo,
879 action='create', conditions={'function': check_repo,
882 'method': ['POST']},
880 'method': ['POST']},
883 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
881 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
884
882
885 rmap.connect('pullrequest_repo_refs',
883 rmap.connect('pullrequest_repo_refs',
886 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
884 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
887 controller='pullrequests',
885 controller='pullrequests',
888 action='get_repo_refs',
886 action='get_repo_refs',
889 conditions={'function': check_repo, 'method': ['GET']},
887 conditions={'function': check_repo, 'method': ['GET']},
890 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
888 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
891
889
892 rmap.connect('pullrequest_repo_destinations',
890 rmap.connect('pullrequest_repo_destinations',
893 '/{repo_name}/pull-request/repo-destinations',
891 '/{repo_name}/pull-request/repo-destinations',
894 controller='pullrequests',
892 controller='pullrequests',
895 action='get_repo_destinations',
893 action='get_repo_destinations',
896 conditions={'function': check_repo, 'method': ['GET']},
894 conditions={'function': check_repo, 'method': ['GET']},
897 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
895 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
898
896
899 rmap.connect('pullrequest_show',
897 rmap.connect('pullrequest_show',
900 '/{repo_name}/pull-request/{pull_request_id}',
898 '/{repo_name}/pull-request/{pull_request_id}',
901 controller='pullrequests',
899 controller='pullrequests',
902 action='show', conditions={'function': check_repo,
900 action='show', conditions={'function': check_repo,
903 'method': ['GET']},
901 'method': ['GET']},
904 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
902 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
905
903
906 rmap.connect('pullrequest_update',
904 rmap.connect('pullrequest_update',
907 '/{repo_name}/pull-request/{pull_request_id}',
905 '/{repo_name}/pull-request/{pull_request_id}',
908 controller='pullrequests',
906 controller='pullrequests',
909 action='update', conditions={'function': check_repo,
907 action='update', conditions={'function': check_repo,
910 'method': ['PUT']},
908 'method': ['PUT']},
911 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
909 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
912
910
913 rmap.connect('pullrequest_merge',
911 rmap.connect('pullrequest_merge',
914 '/{repo_name}/pull-request/{pull_request_id}',
912 '/{repo_name}/pull-request/{pull_request_id}',
915 controller='pullrequests',
913 controller='pullrequests',
916 action='merge', conditions={'function': check_repo,
914 action='merge', conditions={'function': check_repo,
917 'method': ['POST']},
915 'method': ['POST']},
918 requirements=URL_NAME_REQUIREMENTS)
916 requirements=URL_NAME_REQUIREMENTS)
919
917
920 rmap.connect('pullrequest_delete',
918 rmap.connect('pullrequest_delete',
921 '/{repo_name}/pull-request/{pull_request_id}',
919 '/{repo_name}/pull-request/{pull_request_id}',
922 controller='pullrequests',
920 controller='pullrequests',
923 action='delete', conditions={'function': check_repo,
921 action='delete', conditions={'function': check_repo,
924 'method': ['DELETE']},
922 'method': ['DELETE']},
925 requirements=URL_NAME_REQUIREMENTS)
923 requirements=URL_NAME_REQUIREMENTS)
926
924
927 rmap.connect('pullrequest_show_all',
925 rmap.connect('pullrequest_show_all',
928 '/{repo_name}/pull-request',
926 '/{repo_name}/pull-request',
929 controller='pullrequests',
927 controller='pullrequests',
930 action='show_all', conditions={'function': check_repo,
928 action='show_all', conditions={'function': check_repo,
931 'method': ['GET']},
929 'method': ['GET']},
932 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
930 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
933
931
934 rmap.connect('pullrequest_comment',
932 rmap.connect('pullrequest_comment',
935 '/{repo_name}/pull-request-comment/{pull_request_id}',
933 '/{repo_name}/pull-request-comment/{pull_request_id}',
936 controller='pullrequests',
934 controller='pullrequests',
937 action='comment', conditions={'function': check_repo,
935 action='comment', conditions={'function': check_repo,
938 'method': ['POST']},
936 'method': ['POST']},
939 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
937 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
940
938
941 rmap.connect('pullrequest_comment_delete',
939 rmap.connect('pullrequest_comment_delete',
942 '/{repo_name}/pull-request-comment/{comment_id}/delete',
940 '/{repo_name}/pull-request-comment/{comment_id}/delete',
943 controller='pullrequests', action='delete_comment',
941 controller='pullrequests', action='delete_comment',
944 conditions={'function': check_repo, 'method': ['DELETE']},
942 conditions={'function': check_repo, 'method': ['DELETE']},
945 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
943 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
946
944
947 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
945 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
948 controller='summary', conditions={'function': check_repo},
946 controller='summary', conditions={'function': check_repo},
949 requirements=URL_NAME_REQUIREMENTS)
947 requirements=URL_NAME_REQUIREMENTS)
950
948
951 rmap.connect('branches_home', '/{repo_name}/branches',
949 rmap.connect('branches_home', '/{repo_name}/branches',
952 controller='branches', conditions={'function': check_repo},
950 controller='branches', conditions={'function': check_repo},
953 requirements=URL_NAME_REQUIREMENTS)
951 requirements=URL_NAME_REQUIREMENTS)
954
952
955 rmap.connect('tags_home', '/{repo_name}/tags',
953 rmap.connect('tags_home', '/{repo_name}/tags',
956 controller='tags', conditions={'function': check_repo},
954 controller='tags', conditions={'function': check_repo},
957 requirements=URL_NAME_REQUIREMENTS)
955 requirements=URL_NAME_REQUIREMENTS)
958
956
959 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
957 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
960 controller='bookmarks', conditions={'function': check_repo},
958 controller='bookmarks', conditions={'function': check_repo},
961 requirements=URL_NAME_REQUIREMENTS)
959 requirements=URL_NAME_REQUIREMENTS)
962
960
963 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
961 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
964 controller='changelog', conditions={'function': check_repo},
962 controller='changelog', conditions={'function': check_repo},
965 requirements=URL_NAME_REQUIREMENTS)
963 requirements=URL_NAME_REQUIREMENTS)
966
964
967 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
965 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
968 controller='changelog', action='changelog_summary',
966 controller='changelog', action='changelog_summary',
969 conditions={'function': check_repo},
967 conditions={'function': check_repo},
970 requirements=URL_NAME_REQUIREMENTS)
968 requirements=URL_NAME_REQUIREMENTS)
971
969
972 rmap.connect('changelog_file_home',
970 rmap.connect('changelog_file_home',
973 '/{repo_name}/changelog/{revision}/{f_path}',
971 '/{repo_name}/changelog/{revision}/{f_path}',
974 controller='changelog', f_path=None,
972 controller='changelog', f_path=None,
975 conditions={'function': check_repo},
973 conditions={'function': check_repo},
976 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
974 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
977
975
978 rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
976 rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
979 controller='changelog', action='changelog_elements',
977 controller='changelog', action='changelog_elements',
980 conditions={'function': check_repo},
978 conditions={'function': check_repo},
981 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
979 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
982
980
983 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
981 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
984 controller='files', revision='tip', f_path='',
982 controller='files', revision='tip', f_path='',
985 conditions={'function': check_repo},
983 conditions={'function': check_repo},
986 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
984 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
987
985
988 rmap.connect('files_home_simple_catchrev',
986 rmap.connect('files_home_simple_catchrev',
989 '/{repo_name}/files/{revision}',
987 '/{repo_name}/files/{revision}',
990 controller='files', revision='tip', f_path='',
988 controller='files', revision='tip', f_path='',
991 conditions={'function': check_repo},
989 conditions={'function': check_repo},
992 requirements=URL_NAME_REQUIREMENTS)
990 requirements=URL_NAME_REQUIREMENTS)
993
991
994 rmap.connect('files_home_simple_catchall',
992 rmap.connect('files_home_simple_catchall',
995 '/{repo_name}/files',
993 '/{repo_name}/files',
996 controller='files', revision='tip', f_path='',
994 controller='files', revision='tip', f_path='',
997 conditions={'function': check_repo},
995 conditions={'function': check_repo},
998 requirements=URL_NAME_REQUIREMENTS)
996 requirements=URL_NAME_REQUIREMENTS)
999
997
1000 rmap.connect('files_history_home',
998 rmap.connect('files_history_home',
1001 '/{repo_name}/history/{revision}/{f_path}',
999 '/{repo_name}/history/{revision}/{f_path}',
1002 controller='files', action='history', revision='tip', f_path='',
1000 controller='files', action='history', revision='tip', f_path='',
1003 conditions={'function': check_repo},
1001 conditions={'function': check_repo},
1004 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1002 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1005
1003
1006 rmap.connect('files_authors_home',
1004 rmap.connect('files_authors_home',
1007 '/{repo_name}/authors/{revision}/{f_path}',
1005 '/{repo_name}/authors/{revision}/{f_path}',
1008 controller='files', action='authors', revision='tip', f_path='',
1006 controller='files', action='authors', revision='tip', f_path='',
1009 conditions={'function': check_repo},
1007 conditions={'function': check_repo},
1010 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1008 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1011
1009
1012 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
1010 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
1013 controller='files', action='diff', f_path='',
1011 controller='files', action='diff', f_path='',
1014 conditions={'function': check_repo},
1012 conditions={'function': check_repo},
1015 requirements=URL_NAME_REQUIREMENTS)
1013 requirements=URL_NAME_REQUIREMENTS)
1016
1014
1017 rmap.connect('files_diff_2way_home',
1015 rmap.connect('files_diff_2way_home',
1018 '/{repo_name}/diff-2way/{f_path}',
1016 '/{repo_name}/diff-2way/{f_path}',
1019 controller='files', action='diff_2way', f_path='',
1017 controller='files', action='diff_2way', f_path='',
1020 conditions={'function': check_repo},
1018 conditions={'function': check_repo},
1021 requirements=URL_NAME_REQUIREMENTS)
1019 requirements=URL_NAME_REQUIREMENTS)
1022
1020
1023 rmap.connect('files_rawfile_home',
1021 rmap.connect('files_rawfile_home',
1024 '/{repo_name}/rawfile/{revision}/{f_path}',
1022 '/{repo_name}/rawfile/{revision}/{f_path}',
1025 controller='files', action='rawfile', revision='tip',
1023 controller='files', action='rawfile', revision='tip',
1026 f_path='', conditions={'function': check_repo},
1024 f_path='', conditions={'function': check_repo},
1027 requirements=URL_NAME_REQUIREMENTS)
1025 requirements=URL_NAME_REQUIREMENTS)
1028
1026
1029 rmap.connect('files_raw_home',
1027 rmap.connect('files_raw_home',
1030 '/{repo_name}/raw/{revision}/{f_path}',
1028 '/{repo_name}/raw/{revision}/{f_path}',
1031 controller='files', action='raw', revision='tip', f_path='',
1029 controller='files', action='raw', revision='tip', f_path='',
1032 conditions={'function': check_repo},
1030 conditions={'function': check_repo},
1033 requirements=URL_NAME_REQUIREMENTS)
1031 requirements=URL_NAME_REQUIREMENTS)
1034
1032
1035 rmap.connect('files_render_home',
1033 rmap.connect('files_render_home',
1036 '/{repo_name}/render/{revision}/{f_path}',
1034 '/{repo_name}/render/{revision}/{f_path}',
1037 controller='files', action='index', revision='tip', f_path='',
1035 controller='files', action='index', revision='tip', f_path='',
1038 rendered=True, conditions={'function': check_repo},
1036 rendered=True, conditions={'function': check_repo},
1039 requirements=URL_NAME_REQUIREMENTS)
1037 requirements=URL_NAME_REQUIREMENTS)
1040
1038
1041 rmap.connect('files_annotate_home',
1039 rmap.connect('files_annotate_home',
1042 '/{repo_name}/annotate/{revision}/{f_path}',
1040 '/{repo_name}/annotate/{revision}/{f_path}',
1043 controller='files', action='index', revision='tip',
1041 controller='files', action='index', revision='tip',
1044 f_path='', annotate=True, conditions={'function': check_repo},
1042 f_path='', annotate=True, conditions={'function': check_repo},
1045 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1043 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1046
1044
1047 rmap.connect('files_annotate_previous',
1045 rmap.connect('files_annotate_previous',
1048 '/{repo_name}/annotate-previous/{revision}/{f_path}',
1046 '/{repo_name}/annotate-previous/{revision}/{f_path}',
1049 controller='files', action='annotate_previous', revision='tip',
1047 controller='files', action='annotate_previous', revision='tip',
1050 f_path='', annotate=True, conditions={'function': check_repo},
1048 f_path='', annotate=True, conditions={'function': check_repo},
1051 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1049 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1052
1050
1053 rmap.connect('files_edit',
1051 rmap.connect('files_edit',
1054 '/{repo_name}/edit/{revision}/{f_path}',
1052 '/{repo_name}/edit/{revision}/{f_path}',
1055 controller='files', action='edit', revision='tip',
1053 controller='files', action='edit', revision='tip',
1056 f_path='',
1054 f_path='',
1057 conditions={'function': check_repo, 'method': ['POST']},
1055 conditions={'function': check_repo, 'method': ['POST']},
1058 requirements=URL_NAME_REQUIREMENTS)
1056 requirements=URL_NAME_REQUIREMENTS)
1059
1057
1060 rmap.connect('files_edit_home',
1058 rmap.connect('files_edit_home',
1061 '/{repo_name}/edit/{revision}/{f_path}',
1059 '/{repo_name}/edit/{revision}/{f_path}',
1062 controller='files', action='edit_home', revision='tip',
1060 controller='files', action='edit_home', revision='tip',
1063 f_path='', conditions={'function': check_repo},
1061 f_path='', conditions={'function': check_repo},
1064 requirements=URL_NAME_REQUIREMENTS)
1062 requirements=URL_NAME_REQUIREMENTS)
1065
1063
1066 rmap.connect('files_add',
1064 rmap.connect('files_add',
1067 '/{repo_name}/add/{revision}/{f_path}',
1065 '/{repo_name}/add/{revision}/{f_path}',
1068 controller='files', action='add', revision='tip',
1066 controller='files', action='add', revision='tip',
1069 f_path='',
1067 f_path='',
1070 conditions={'function': check_repo, 'method': ['POST']},
1068 conditions={'function': check_repo, 'method': ['POST']},
1071 requirements=URL_NAME_REQUIREMENTS)
1069 requirements=URL_NAME_REQUIREMENTS)
1072
1070
1073 rmap.connect('files_add_home',
1071 rmap.connect('files_add_home',
1074 '/{repo_name}/add/{revision}/{f_path}',
1072 '/{repo_name}/add/{revision}/{f_path}',
1075 controller='files', action='add_home', revision='tip',
1073 controller='files', action='add_home', revision='tip',
1076 f_path='', conditions={'function': check_repo},
1074 f_path='', conditions={'function': check_repo},
1077 requirements=URL_NAME_REQUIREMENTS)
1075 requirements=URL_NAME_REQUIREMENTS)
1078
1076
1079 rmap.connect('files_delete',
1077 rmap.connect('files_delete',
1080 '/{repo_name}/delete/{revision}/{f_path}',
1078 '/{repo_name}/delete/{revision}/{f_path}',
1081 controller='files', action='delete', revision='tip',
1079 controller='files', action='delete', revision='tip',
1082 f_path='',
1080 f_path='',
1083 conditions={'function': check_repo, 'method': ['POST']},
1081 conditions={'function': check_repo, 'method': ['POST']},
1084 requirements=URL_NAME_REQUIREMENTS)
1082 requirements=URL_NAME_REQUIREMENTS)
1085
1083
1086 rmap.connect('files_delete_home',
1084 rmap.connect('files_delete_home',
1087 '/{repo_name}/delete/{revision}/{f_path}',
1085 '/{repo_name}/delete/{revision}/{f_path}',
1088 controller='files', action='delete_home', revision='tip',
1086 controller='files', action='delete_home', revision='tip',
1089 f_path='', conditions={'function': check_repo},
1087 f_path='', conditions={'function': check_repo},
1090 requirements=URL_NAME_REQUIREMENTS)
1088 requirements=URL_NAME_REQUIREMENTS)
1091
1089
1092 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1090 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1093 controller='files', action='archivefile',
1091 controller='files', action='archivefile',
1094 conditions={'function': check_repo},
1092 conditions={'function': check_repo},
1095 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1093 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1096
1094
1097 rmap.connect('files_nodelist_home',
1095 rmap.connect('files_nodelist_home',
1098 '/{repo_name}/nodelist/{revision}/{f_path}',
1096 '/{repo_name}/nodelist/{revision}/{f_path}',
1099 controller='files', action='nodelist',
1097 controller='files', action='nodelist',
1100 conditions={'function': check_repo},
1098 conditions={'function': check_repo},
1101 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1099 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1102
1100
1103 rmap.connect('files_nodetree_full',
1101 rmap.connect('files_nodetree_full',
1104 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1102 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1105 controller='files', action='nodetree_full',
1103 controller='files', action='nodetree_full',
1106 conditions={'function': check_repo},
1104 conditions={'function': check_repo},
1107 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1105 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1108
1106
1109 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1107 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1110 controller='forks', action='fork_create',
1108 controller='forks', action='fork_create',
1111 conditions={'function': check_repo, 'method': ['POST']},
1109 conditions={'function': check_repo, 'method': ['POST']},
1112 requirements=URL_NAME_REQUIREMENTS)
1110 requirements=URL_NAME_REQUIREMENTS)
1113
1111
1114 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1112 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1115 controller='forks', action='fork',
1113 controller='forks', action='fork',
1116 conditions={'function': check_repo},
1114 conditions={'function': check_repo},
1117 requirements=URL_NAME_REQUIREMENTS)
1115 requirements=URL_NAME_REQUIREMENTS)
1118
1116
1119 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1117 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1120 controller='forks', action='forks',
1118 controller='forks', action='forks',
1121 conditions={'function': check_repo},
1119 conditions={'function': check_repo},
1122 requirements=URL_NAME_REQUIREMENTS)
1120 requirements=URL_NAME_REQUIREMENTS)
1123
1121
1124 # must be here for proper group/repo catching pattern
1122 # must be here for proper group/repo catching pattern
1125 _connect_with_slash(
1123 _connect_with_slash(
1126 rmap, 'repo_group_home', '/{group_name}',
1124 rmap, 'repo_group_home', '/{group_name}',
1127 controller='home', action='index_repo_group',
1125 controller='home', action='index_repo_group',
1128 conditions={'function': check_group},
1126 conditions={'function': check_group},
1129 requirements=URL_NAME_REQUIREMENTS)
1127 requirements=URL_NAME_REQUIREMENTS)
1130
1128
1131 # catch all, at the end
1129 # catch all, at the end
1132 _connect_with_slash(
1130 _connect_with_slash(
1133 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1131 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1134 controller='summary', action='index',
1132 controller='summary', action='index',
1135 conditions={'function': check_repo},
1133 conditions={'function': check_repo},
1136 requirements=URL_NAME_REQUIREMENTS)
1134 requirements=URL_NAME_REQUIREMENTS)
1137
1135
1138 return rmap
1136 return rmap
1139
1137
1140
1138
1141 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1139 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1142 """
1140 """
1143 Connect a route with an optional trailing slash in `path`.
1141 Connect a route with an optional trailing slash in `path`.
1144 """
1142 """
1145 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1143 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1146 mapper.connect(name, path, *args, **kwargs)
1144 mapper.connect(name, path, *args, **kwargs)
@@ -1,235 +1,110 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 Home controller for RhodeCode Enterprise
22 Home controller for RhodeCode Enterprise
23 """
23 """
24
24
25 import logging
25 import logging
26 import time
26 import time
27 import re
28
27
29 from pylons import tmpl_context as c, request, url, config
28 from pylons import tmpl_context as c
30 from pylons.i18n.translation import _
31 from sqlalchemy.sql import func
32
29
33 from rhodecode.lib.auth import (
30 from rhodecode.lib.auth import (
34 LoginRequired, HasPermissionAllDecorator, AuthUser,
31 LoginRequired, HasPermissionAllDecorator,
35 HasRepoGroupPermissionAnyDecorator, XHRRequired)
32 HasRepoGroupPermissionAnyDecorator)
36 from rhodecode.lib.base import BaseController, render
33 from rhodecode.lib.base import BaseController, render
37 from rhodecode.lib.index import searcher_from_config
34
38 from rhodecode.lib.ext_json import json
35 from rhodecode.lib.ext_json import json
39 from rhodecode.lib.utils import jsonify
40 from rhodecode.lib.utils2 import safe_unicode, str2bool
41 from rhodecode.model.db import Repository, RepoGroup
36 from rhodecode.model.db import Repository, RepoGroup
42 from rhodecode.model.repo import RepoModel
37 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.repo_group import RepoGroupModel
38 from rhodecode.model.repo_group import RepoGroupModel
44 from rhodecode.model.scm import RepoList, RepoGroupList
39 from rhodecode.model.scm import RepoList, RepoGroupList
45
40
46
41
47 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
48
43
49
44
50 class HomeController(BaseController):
45 class HomeController(BaseController):
51 def __before__(self):
46 def __before__(self):
52 super(HomeController, self).__before__()
47 super(HomeController, self).__before__()
53
48
54 def ping(self):
49 def ping(self):
55 """
50 """
56 Ping, doesn't require login, good for checking out the platform
51 Ping, doesn't require login, good for checking out the platform
57 """
52 """
58 instance_id = getattr(c, 'rhodecode_instanceid', '')
53 instance_id = getattr(c, 'rhodecode_instanceid', '')
59 return 'pong[%s] => %s' % (instance_id, self.ip_addr,)
54 return 'pong[%s] => %s' % (instance_id, self.ip_addr,)
60
55
61 @LoginRequired()
56 @LoginRequired()
62 @HasPermissionAllDecorator('hg.admin')
57 @HasPermissionAllDecorator('hg.admin')
63 def error_test(self):
58 def error_test(self):
64 """
59 """
65 Test exception handling and emails on errors
60 Test exception handling and emails on errors
66 """
61 """
67 class TestException(Exception):
62 class TestException(Exception):
68 pass
63 pass
69
64
70 msg = ('RhodeCode Enterprise %s test exception. Generation time: %s'
65 msg = ('RhodeCode Enterprise %s test exception. Generation time: %s'
71 % (c.rhodecode_name, time.time()))
66 % (c.rhodecode_name, time.time()))
72 raise TestException(msg)
67 raise TestException(msg)
73
68
74 def _get_groups_and_repos(self, repo_group_id=None):
69 def _get_groups_and_repos(self, repo_group_id=None):
75 # repo groups groups
70 # repo groups groups
76 repo_group_list = RepoGroup.get_all_repo_groups(group_id=repo_group_id)
71 repo_group_list = RepoGroup.get_all_repo_groups(group_id=repo_group_id)
77 _perms = ['group.read', 'group.write', 'group.admin']
72 _perms = ['group.read', 'group.write', 'group.admin']
78 repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms)
73 repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms)
79 repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
74 repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
80 repo_group_list=repo_group_list_acl, admin=False)
75 repo_group_list=repo_group_list_acl, admin=False)
81
76
82 # repositories
77 # repositories
83 repo_list = Repository.get_all_repos(group_id=repo_group_id)
78 repo_list = Repository.get_all_repos(group_id=repo_group_id)
84 _perms = ['repository.read', 'repository.write', 'repository.admin']
79 _perms = ['repository.read', 'repository.write', 'repository.admin']
85 repo_list_acl = RepoList(repo_list, perm_set=_perms)
80 repo_list_acl = RepoList(repo_list, perm_set=_perms)
86 repo_data = RepoModel().get_repos_as_dict(
81 repo_data = RepoModel().get_repos_as_dict(
87 repo_list=repo_list_acl, admin=False)
82 repo_list=repo_list_acl, admin=False)
88
83
89 return repo_data, repo_group_data
84 return repo_data, repo_group_data
90
85
91 @LoginRequired()
86 @LoginRequired()
92 def index(self):
87 def index(self):
93 c.repo_group = None
88 c.repo_group = None
94
89
95 repo_data, repo_group_data = self._get_groups_and_repos()
90 repo_data, repo_group_data = self._get_groups_and_repos()
96 # json used to render the grids
91 # json used to render the grids
97 c.repos_data = json.dumps(repo_data)
92 c.repos_data = json.dumps(repo_data)
98 c.repo_groups_data = json.dumps(repo_group_data)
93 c.repo_groups_data = json.dumps(repo_group_data)
99
94
100 return render('/index.mako')
95 return render('/index.mako')
101
96
102 @LoginRequired()
97 @LoginRequired()
103 @HasRepoGroupPermissionAnyDecorator('group.read', 'group.write',
98 @HasRepoGroupPermissionAnyDecorator('group.read', 'group.write',
104 'group.admin')
99 'group.admin')
105 def index_repo_group(self, group_name):
100 def index_repo_group(self, group_name):
106 """GET /repo_group_name: Show a specific item"""
101 """GET /repo_group_name: Show a specific item"""
107 c.repo_group = RepoGroupModel()._get_repo_group(group_name)
102 c.repo_group = RepoGroupModel()._get_repo_group(group_name)
108 repo_data, repo_group_data = self._get_groups_and_repos(
103 repo_data, repo_group_data = self._get_groups_and_repos(
109 c.repo_group.group_id)
104 c.repo_group.group_id)
110
105
111 # json used to render the grids
106 # json used to render the grids
112 c.repos_data = json.dumps(repo_data)
107 c.repos_data = json.dumps(repo_data)
113 c.repo_groups_data = json.dumps(repo_group_data)
108 c.repo_groups_data = json.dumps(repo_group_data)
114
109
115 return render('index_repo_group.mako')
110 return render('index_repo_group.mako')
116
117 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
118 query = Repository.query()\
119 .order_by(func.length(Repository.repo_name))\
120 .order_by(Repository.repo_name)
121
122 if repo_type:
123 query = query.filter(Repository.repo_type == repo_type)
124
125 if name_contains:
126 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
127 query = query.filter(
128 Repository.repo_name.ilike(ilike_expression))
129 query = query.limit(limit)
130
131 all_repos = query.all()
132 repo_iter = self.scm_model.get_repos(all_repos)
133 return [
134 {
135 'id': obj['name'],
136 'text': obj['name'],
137 'type': 'repo',
138 'obj': obj['dbrepo'],
139 'url': url('summary_home', repo_name=obj['name'])
140 }
141 for obj in repo_iter]
142
143 def _get_repo_group_list(self, name_contains=None, limit=20):
144 query = RepoGroup.query()\
145 .order_by(func.length(RepoGroup.group_name))\
146 .order_by(RepoGroup.group_name)
147
148 if name_contains:
149 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
150 query = query.filter(
151 RepoGroup.group_name.ilike(ilike_expression))
152 query = query.limit(limit)
153
154 all_groups = query.all()
155 repo_groups_iter = self.scm_model.get_repo_groups(all_groups)
156 return [
157 {
158 'id': obj.group_name,
159 'text': obj.group_name,
160 'type': 'group',
161 'obj': {},
162 'url': url('repo_group_home', group_name=obj.group_name)
163 }
164 for obj in repo_groups_iter]
165
166 def _get_hash_commit_list(self, hash_starts_with=None, limit=20):
167 if not hash_starts_with or len(hash_starts_with) < 3:
168 return []
169
170 commit_hashes = re.compile('([0-9a-f]{2,40})').findall(hash_starts_with)
171
172 if len(commit_hashes) != 1:
173 return []
174
175 commit_hash_prefix = commit_hashes[0]
176
177 auth_user = AuthUser(
178 user_id=c.rhodecode_user.user_id, ip_addr=self.ip_addr)
179 searcher = searcher_from_config(config)
180 result = searcher.search(
181 'commit_id:%s*' % commit_hash_prefix, 'commit', auth_user,
182 raise_on_exc=False)
183
184 return [
185 {
186 'id': entry['commit_id'],
187 'text': entry['commit_id'],
188 'type': 'commit',
189 'obj': {'repo': entry['repository']},
190 'url': url('changeset_home',
191 repo_name=entry['repository'],
192 revision=entry['commit_id'])
193 }
194 for entry in result['results']]
195
196 @LoginRequired()
197 @XHRRequired()
198 @jsonify
199 def goto_switcher_data(self):
200 query = request.GET.get('query')
201 log.debug('generating goto switcher list, query %s', query)
202
203 res = []
204 repo_groups = self._get_repo_group_list(query)
205 if repo_groups:
206 res.append({
207 'text': _('Groups'),
208 'children': repo_groups
209 })
210
211 repos = self._get_repo_list(query)
212 if repos:
213 res.append({
214 'text': _('Repositories'),
215 'children': repos
216 })
217
218 commits = self._get_hash_commit_list(query)
219 if commits:
220 unique_repos = {}
221 for commit in commits:
222 unique_repos.setdefault(commit['obj']['repo'], []
223 ).append(commit)
224
225 for repo in unique_repos:
226 res.append({
227 'text': _('Commits in %(repo)s') % {'repo': repo},
228 'children': unique_repos[repo]
229 })
230
231 data = {
232 'more': False,
233 'results': res
234 }
235 return data
@@ -1,112 +1,113 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('home', '/', []);
15 pyroutes.register('home', '/', []);
16 pyroutes.register('new_repo', '/_admin/create_repository', []);
16 pyroutes.register('new_repo', '/_admin/create_repository', []);
17 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
17 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
18 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
18 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
19 pyroutes.register('gists', '/_admin/gists', []);
19 pyroutes.register('gists', '/_admin/gists', []);
20 pyroutes.register('new_gist', '/_admin/gists/new', []);
20 pyroutes.register('new_gist', '/_admin/gists/new', []);
21 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
21 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
22 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
22 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
23 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
23 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
24 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
24 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
25 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
25 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
26 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
26 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
27 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
27 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
28 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
28 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
29 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
29 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
30 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
30 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
31 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
31 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
32 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
32 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
33 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']);
33 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']);
34 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
34 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
35 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
35 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
36 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
36 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
37 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
37 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
38 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
38 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
39 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
39 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
40 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
40 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
41 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
41 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
42 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
42 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
43 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
43 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
44 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
44 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
45 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
45 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
46 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
46 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
50 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
50 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
51 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
51 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
52 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
52 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
53 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
53 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
54 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
54 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
55 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
55 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
56 pyroutes.register('favicon', '/favicon.ico', []);
56 pyroutes.register('favicon', '/favicon.ico', []);
57 pyroutes.register('robots', '/robots.txt', []);
57 pyroutes.register('robots', '/robots.txt', []);
58 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
58 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
59 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
59 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
60 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
60 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
61 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
61 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
62 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
62 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
63 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
63 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
64 pyroutes.register('repo_group_integrations_home', '%(repo_group_name)s/settings/integrations', ['repo_group_name']);
64 pyroutes.register('repo_group_integrations_home', '%(repo_group_name)s/settings/integrations', ['repo_group_name']);
65 pyroutes.register('repo_group_integrations_list', '%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
65 pyroutes.register('repo_group_integrations_list', '%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
66 pyroutes.register('repo_group_integrations_new', '%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
66 pyroutes.register('repo_group_integrations_new', '%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
67 pyroutes.register('repo_group_integrations_create', '%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
67 pyroutes.register('repo_group_integrations_create', '%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
68 pyroutes.register('repo_group_integrations_edit', '%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
68 pyroutes.register('repo_group_integrations_edit', '%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
69 pyroutes.register('repo_integrations_home', '%(repo_name)s/settings/integrations', ['repo_name']);
69 pyroutes.register('repo_integrations_home', '%(repo_name)s/settings/integrations', ['repo_name']);
70 pyroutes.register('repo_integrations_list', '%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
70 pyroutes.register('repo_integrations_list', '%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
71 pyroutes.register('repo_integrations_new', '%(repo_name)s/settings/integrations/new', ['repo_name']);
71 pyroutes.register('repo_integrations_new', '%(repo_name)s/settings/integrations/new', ['repo_name']);
72 pyroutes.register('repo_integrations_create', '%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
72 pyroutes.register('repo_integrations_create', '%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
73 pyroutes.register('repo_integrations_edit', '%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
73 pyroutes.register('repo_integrations_edit', '%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
74 pyroutes.register('admin_settings_open_source', '_admin/settings/open_source', []);
74 pyroutes.register('admin_settings_open_source', '_admin/settings/open_source', []);
75 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '_admin/settings/vcs/svn_generate_cfg', []);
75 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '_admin/settings/vcs/svn_generate_cfg', []);
76 pyroutes.register('admin_settings_system', '_admin/settings/system', []);
76 pyroutes.register('admin_settings_system', '_admin/settings/system', []);
77 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
77 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
78 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
78 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
79 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
79 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
80 pyroutes.register('users', '_admin/users', []);
80 pyroutes.register('users', '_admin/users', []);
81 pyroutes.register('users_data', '_admin/users_data', []);
81 pyroutes.register('users_data', '_admin/users_data', []);
82 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
82 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
83 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
83 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
84 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
84 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
85 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
85 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
86 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
86 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
87 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
87 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
88 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
88 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
89 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
89 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
90 pyroutes.register('channelstream_proxy', '/_channelstream', []);
90 pyroutes.register('channelstream_proxy', '/_channelstream', []);
91 pyroutes.register('login', '/_admin/login', []);
91 pyroutes.register('login', '/_admin/login', []);
92 pyroutes.register('logout', '/_admin/logout', []);
92 pyroutes.register('logout', '/_admin/logout', []);
93 pyroutes.register('register', '/_admin/register', []);
93 pyroutes.register('register', '/_admin/register', []);
94 pyroutes.register('reset_password', '/_admin/password_reset', []);
94 pyroutes.register('reset_password', '/_admin/password_reset', []);
95 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
95 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
96 pyroutes.register('user_autocomplete_data', '/_users', []);
96 pyroutes.register('user_autocomplete_data', '/_users', []);
97 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
97 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
98 pyroutes.register('repo_list_data', '/_repos', []);
98 pyroutes.register('repo_list_data', '/_repos', []);
99 pyroutes.register('goto_switcher_data', '/_goto_data', []);
99 pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']);
100 pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']);
100 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']);
101 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']);
101 pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']);
102 pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']);
102 pyroutes.register('strip_check', '/%(repo_name)s/strip_check', ['repo_name']);
103 pyroutes.register('strip_check', '/%(repo_name)s/strip_check', ['repo_name']);
103 pyroutes.register('strip_execute', '/%(repo_name)s/strip_execute', ['repo_name']);
104 pyroutes.register('strip_execute', '/%(repo_name)s/strip_execute', ['repo_name']);
104 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
105 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
105 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
106 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
106 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
107 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
107 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
108 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
108 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
109 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
109 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
110 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
110 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
111 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
111 pyroutes.register('apiv2', '/_admin/api', []);
112 pyroutes.register('apiv2', '/_admin/api', []);
112 }
113 }
@@ -1,601 +1,601 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.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
10 <a href="${h.url('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.url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
44 &copy; 2010-${h.datetime.today().year}, <a href="${h.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.url('admin_home')}">${_('Admin journal')}</a></li>
75 <li><a href="${h.url('admin_home')}">${_('Admin journal')}</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="${title}">
93 <dd title="${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.author_string(email)}">
137 <div class="rc-user tooltip" title="${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.url('summary_home',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
189 <a href="${h.url('summary_home',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.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
228 <li class="${is_active('summary')}"><a class="menulink" href="${h.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
229 <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
229 <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
230 <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li>
230 <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li>
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.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}">
237 <a class="menulink" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('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" href="#" class="dropdown"><div class="menulabel">${_('Options')} <div class="show_more"></div></div></a>
246 <a class="menulink" href="#" class="dropdown"><div class="menulabel">${_('Options')} <div class="show_more"></div></div></a>
247 <ul class="submenu">
247 <ul class="submenu">
248 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
248 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
249 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
249 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
250 %endif
250 %endif
251 %if c.rhodecode_db_repo.fork:
251 %if c.rhodecode_db_repo.fork:
252 <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)}">
252 <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)}">
253 ${_('Compare fork')}</a></li>
253 ${_('Compare fork')}</a></li>
254 %endif
254 %endif
255
255
256 <li><a href="${h.url('search_repo_home',repo_name=c.repo_name)}">${_('Search')}</a></li>
256 <li><a href="${h.url('search_repo_home',repo_name=c.repo_name)}">${_('Search')}</a></li>
257
257
258 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
258 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
259 %if c.rhodecode_db_repo.locked[0]:
259 %if c.rhodecode_db_repo.locked[0]:
260 <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
260 <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
261 %else:
261 %else:
262 <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
262 <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
263 %endif
263 %endif
264 %endif
264 %endif
265 %if c.rhodecode_user.username != h.DEFAULT_USER:
265 %if c.rhodecode_user.username != h.DEFAULT_USER:
266 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
266 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
267 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
267 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
268 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
268 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
269 %endif
269 %endif
270 %endif
270 %endif
271 </ul>
271 </ul>
272 </li>
272 </li>
273 </ul>
273 </ul>
274 </div>
274 </div>
275 <div class="clear"></div>
275 <div class="clear"></div>
276 </div>
276 </div>
277 <!--- END CONTEXT BAR -->
277 <!--- END CONTEXT BAR -->
278
278
279 </%def>
279 </%def>
280
280
281 <%def name="usermenu(active=False)">
281 <%def name="usermenu(active=False)">
282 ## USER MENU
282 ## USER MENU
283 <li id="quick_login_li" class="${'active' if active else ''}">
283 <li id="quick_login_li" class="${'active' if active else ''}">
284 <a id="quick_login_link" class="menulink childs">
284 <a id="quick_login_link" class="menulink childs">
285 ${gravatar(c.rhodecode_user.email, 20)}
285 ${gravatar(c.rhodecode_user.email, 20)}
286 <span class="user">
286 <span class="user">
287 %if c.rhodecode_user.username != h.DEFAULT_USER:
287 %if c.rhodecode_user.username != h.DEFAULT_USER:
288 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
288 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
289 %else:
289 %else:
290 <span>${_('Sign in')}</span>
290 <span>${_('Sign in')}</span>
291 %endif
291 %endif
292 </span>
292 </span>
293 </a>
293 </a>
294
294
295 <div class="user-menu submenu">
295 <div class="user-menu submenu">
296 <div id="quick_login">
296 <div id="quick_login">
297 %if c.rhodecode_user.username == h.DEFAULT_USER:
297 %if c.rhodecode_user.username == h.DEFAULT_USER:
298 <h4>${_('Sign in to your account')}</h4>
298 <h4>${_('Sign in to your account')}</h4>
299 ${h.form(h.route_path('login', _query={'came_from': h.url.current()}), needs_csrf_token=False)}
299 ${h.form(h.route_path('login', _query={'came_from': h.url.current()}), needs_csrf_token=False)}
300 <div class="form form-vertical">
300 <div class="form form-vertical">
301 <div class="fields">
301 <div class="fields">
302 <div class="field">
302 <div class="field">
303 <div class="label">
303 <div class="label">
304 <label for="username">${_('Username')}:</label>
304 <label for="username">${_('Username')}:</label>
305 </div>
305 </div>
306 <div class="input">
306 <div class="input">
307 ${h.text('username',class_='focus',tabindex=1)}
307 ${h.text('username',class_='focus',tabindex=1)}
308 </div>
308 </div>
309
309
310 </div>
310 </div>
311 <div class="field">
311 <div class="field">
312 <div class="label">
312 <div class="label">
313 <label for="password">${_('Password')}:</label>
313 <label for="password">${_('Password')}:</label>
314 %if h.HasPermissionAny('hg.password_reset.enabled')():
314 %if h.HasPermissionAny('hg.password_reset.enabled')():
315 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'), class_='pwd_reset')}</span>
315 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'), class_='pwd_reset')}</span>
316 %endif
316 %endif
317 </div>
317 </div>
318 <div class="input">
318 <div class="input">
319 ${h.password('password',class_='focus',tabindex=2)}
319 ${h.password('password',class_='focus',tabindex=2)}
320 </div>
320 </div>
321 </div>
321 </div>
322 <div class="buttons">
322 <div class="buttons">
323 <div class="register">
323 <div class="register">
324 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
324 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
325 ${h.link_to(_("Don't have an account ?"),h.route_path('register'))}
325 ${h.link_to(_("Don't have an account ?"),h.route_path('register'))}
326 %endif
326 %endif
327 </div>
327 </div>
328 <div class="submit">
328 <div class="submit">
329 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
329 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
330 </div>
330 </div>
331 </div>
331 </div>
332 </div>
332 </div>
333 </div>
333 </div>
334 ${h.end_form()}
334 ${h.end_form()}
335 %else:
335 %else:
336 <div class="">
336 <div class="">
337 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
337 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
338 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
338 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
339 <div class="email">${c.rhodecode_user.email}</div>
339 <div class="email">${c.rhodecode_user.email}</div>
340 </div>
340 </div>
341 <div class="">
341 <div class="">
342 <ol class="links">
342 <ol class="links">
343 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
343 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
344 % if c.rhodecode_user.personal_repo_group:
344 % if c.rhodecode_user.personal_repo_group:
345 <li>${h.link_to(_(u'My personal group'), h.url('repo_group_home', group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
345 <li>${h.link_to(_(u'My personal group'), h.url('repo_group_home', group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
346 % endif
346 % endif
347 <li class="logout">
347 <li class="logout">
348 ${h.secure_form(h.route_path('logout'))}
348 ${h.secure_form(h.route_path('logout'))}
349 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
349 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
350 ${h.end_form()}
350 ${h.end_form()}
351 </li>
351 </li>
352 </ol>
352 </ol>
353 </div>
353 </div>
354 %endif
354 %endif
355 </div>
355 </div>
356 </div>
356 </div>
357 %if c.rhodecode_user.username != h.DEFAULT_USER:
357 %if c.rhodecode_user.username != h.DEFAULT_USER:
358 <div class="pill_container">
358 <div class="pill_container">
359 % if c.unread_notifications == 0:
359 % if c.unread_notifications == 0:
360 <a class="menu_link_notifications empty" href="${h.url('notifications')}">${c.unread_notifications}</a>
360 <a class="menu_link_notifications empty" href="${h.url('notifications')}">${c.unread_notifications}</a>
361 % else:
361 % else:
362 <a class="menu_link_notifications" href="${h.url('notifications')}">${c.unread_notifications}</a>
362 <a class="menu_link_notifications" href="${h.url('notifications')}">${c.unread_notifications}</a>
363 % endif
363 % endif
364 </div>
364 </div>
365 % endif
365 % endif
366 </li>
366 </li>
367 </%def>
367 </%def>
368
368
369 <%def name="menu_items(active=None)">
369 <%def name="menu_items(active=None)">
370 <%
370 <%
371 def is_active(selected):
371 def is_active(selected):
372 if selected == active:
372 if selected == active:
373 return "active"
373 return "active"
374 return ""
374 return ""
375 %>
375 %>
376 <ul id="quick" class="main_nav navigation horizontal-list">
376 <ul id="quick" class="main_nav navigation horizontal-list">
377 <!-- repo switcher -->
377 <!-- repo switcher -->
378 <li class="${is_active('repositories')} repo_switcher_li has_select2">
378 <li class="${is_active('repositories')} repo_switcher_li has_select2">
379 <input id="repo_switcher" name="repo_switcher" type="hidden">
379 <input id="repo_switcher" name="repo_switcher" type="hidden">
380 </li>
380 </li>
381
381
382 ## ROOT MENU
382 ## ROOT MENU
383 %if c.rhodecode_user.username != h.DEFAULT_USER:
383 %if c.rhodecode_user.username != h.DEFAULT_USER:
384 <li class="${is_active('journal')}">
384 <li class="${is_active('journal')}">
385 <a class="menulink" title="${_('Show activity journal')}" href="${h.url('journal')}">
385 <a class="menulink" title="${_('Show activity journal')}" href="${h.url('journal')}">
386 <div class="menulabel">${_('Journal')}</div>
386 <div class="menulabel">${_('Journal')}</div>
387 </a>
387 </a>
388 </li>
388 </li>
389 %else:
389 %else:
390 <li class="${is_active('journal')}">
390 <li class="${is_active('journal')}">
391 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.url('public_journal')}">
391 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.url('public_journal')}">
392 <div class="menulabel">${_('Public journal')}</div>
392 <div class="menulabel">${_('Public journal')}</div>
393 </a>
393 </a>
394 </li>
394 </li>
395 %endif
395 %endif
396 <li class="${is_active('gists')}">
396 <li class="${is_active('gists')}">
397 <a class="menulink childs" title="${_('Show Gists')}" href="${h.url('gists')}">
397 <a class="menulink childs" title="${_('Show Gists')}" href="${h.url('gists')}">
398 <div class="menulabel">${_('Gists')}</div>
398 <div class="menulabel">${_('Gists')}</div>
399 </a>
399 </a>
400 </li>
400 </li>
401 <li class="${is_active('search')}">
401 <li class="${is_active('search')}">
402 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.url('search')}">
402 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.url('search')}">
403 <div class="menulabel">${_('Search')}</div>
403 <div class="menulabel">${_('Search')}</div>
404 </a>
404 </a>
405 </li>
405 </li>
406 % if h.HasPermissionAll('hg.admin')('access admin main page'):
406 % if h.HasPermissionAll('hg.admin')('access admin main page'):
407 <li class="${is_active('admin')}">
407 <li class="${is_active('admin')}">
408 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
408 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
409 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
409 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
410 </a>
410 </a>
411 ${admin_menu()}
411 ${admin_menu()}
412 </li>
412 </li>
413 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
413 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
414 <li class="${is_active('admin')}">
414 <li class="${is_active('admin')}">
415 <a class="menulink childs" title="${_('Delegated Admin settings')}">
415 <a class="menulink childs" title="${_('Delegated Admin settings')}">
416 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
416 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
417 </a>
417 </a>
418 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
418 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
419 c.rhodecode_user.repository_groups_admin,
419 c.rhodecode_user.repository_groups_admin,
420 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
420 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
421 </li>
421 </li>
422 % endif
422 % endif
423 % if c.debug_style:
423 % if c.debug_style:
424 <li class="${is_active('debug_style')}">
424 <li class="${is_active('debug_style')}">
425 <a class="menulink" title="${_('Style')}" href="${h.url('debug_style_home')}">
425 <a class="menulink" title="${_('Style')}" href="${h.url('debug_style_home')}">
426 <div class="menulabel">${_('Style')}</div>
426 <div class="menulabel">${_('Style')}</div>
427 </a>
427 </a>
428 </li>
428 </li>
429 % endif
429 % endif
430 ## render extra user menu
430 ## render extra user menu
431 ${usermenu(active=(active=='my_account'))}
431 ${usermenu(active=(active=='my_account'))}
432 </ul>
432 </ul>
433
433
434 <script type="text/javascript">
434 <script type="text/javascript">
435 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
435 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
436
436
437 /*format the look of items in the list*/
437 /*format the look of items in the list*/
438 var format = function(state, escapeMarkup){
438 var format = function(state, escapeMarkup){
439 if (!state.id){
439 if (!state.id){
440 return state.text; // optgroup
440 return state.text; // optgroup
441 }
441 }
442 var obj_dict = state.obj;
442 var obj_dict = state.obj;
443 var tmpl = '';
443 var tmpl = '';
444
444
445 if(obj_dict && state.type == 'repo'){
445 if(obj_dict && state.type == 'repo'){
446 if(obj_dict['repo_type'] === 'hg'){
446 if(obj_dict['repo_type'] === 'hg'){
447 tmpl += '<i class="icon-hg"></i> ';
447 tmpl += '<i class="icon-hg"></i> ';
448 }
448 }
449 else if(obj_dict['repo_type'] === 'git'){
449 else if(obj_dict['repo_type'] === 'git'){
450 tmpl += '<i class="icon-git"></i> ';
450 tmpl += '<i class="icon-git"></i> ';
451 }
451 }
452 else if(obj_dict['repo_type'] === 'svn'){
452 else if(obj_dict['repo_type'] === 'svn'){
453 tmpl += '<i class="icon-svn"></i> ';
453 tmpl += '<i class="icon-svn"></i> ';
454 }
454 }
455 if(obj_dict['private']){
455 if(obj_dict['private']){
456 tmpl += '<i class="icon-lock" ></i> ';
456 tmpl += '<i class="icon-lock" ></i> ';
457 }
457 }
458 else if(visual_show_public_icon){
458 else if(visual_show_public_icon){
459 tmpl += '<i class="icon-unlock-alt"></i> ';
459 tmpl += '<i class="icon-unlock-alt"></i> ';
460 }
460 }
461 }
461 }
462 if(obj_dict && state.type == 'commit') {
462 if(obj_dict && state.type == 'commit') {
463 tmpl += '<i class="icon-tag"></i>';
463 tmpl += '<i class="icon-tag"></i>';
464 }
464 }
465 if(obj_dict && state.type == 'group'){
465 if(obj_dict && state.type == 'group'){
466 tmpl += '<i class="icon-folder-close"></i> ';
466 tmpl += '<i class="icon-folder-close"></i> ';
467 }
467 }
468 tmpl += escapeMarkup(state.text);
468 tmpl += escapeMarkup(state.text);
469 return tmpl;
469 return tmpl;
470 };
470 };
471
471
472 var formatResult = function(result, container, query, escapeMarkup) {
472 var formatResult = function(result, container, query, escapeMarkup) {
473 return format(result, escapeMarkup);
473 return format(result, escapeMarkup);
474 };
474 };
475
475
476 var formatSelection = function(data, container, escapeMarkup) {
476 var formatSelection = function(data, container, escapeMarkup) {
477 return format(data, escapeMarkup);
477 return format(data, escapeMarkup);
478 };
478 };
479
479
480 $("#repo_switcher").select2({
480 $("#repo_switcher").select2({
481 cachedDataSource: {},
481 cachedDataSource: {},
482 minimumInputLength: 2,
482 minimumInputLength: 2,
483 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
483 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
484 dropdownAutoWidth: true,
484 dropdownAutoWidth: true,
485 formatResult: formatResult,
485 formatResult: formatResult,
486 formatSelection: formatSelection,
486 formatSelection: formatSelection,
487 containerCssClass: "repo-switcher",
487 containerCssClass: "repo-switcher",
488 dropdownCssClass: "repo-switcher-dropdown",
488 dropdownCssClass: "repo-switcher-dropdown",
489 escapeMarkup: function(m){
489 escapeMarkup: function(m){
490 // don't escape our custom placeholder
490 // don't escape our custom placeholder
491 if(m.substr(0,23) == '<div class="menulabel">'){
491 if(m.substr(0,23) == '<div class="menulabel">'){
492 return m;
492 return m;
493 }
493 }
494
494
495 return Select2.util.escapeMarkup(m);
495 return Select2.util.escapeMarkup(m);
496 },
496 },
497 query: $.debounce(250, function(query){
497 query: $.debounce(250, function(query){
498 self = this;
498 self = this;
499 var cacheKey = query.term;
499 var cacheKey = query.term;
500 var cachedData = self.cachedDataSource[cacheKey];
500 var cachedData = self.cachedDataSource[cacheKey];
501
501
502 if (cachedData) {
502 if (cachedData) {
503 query.callback({results: cachedData.results});
503 query.callback({results: cachedData.results});
504 } else {
504 } else {
505 $.ajax({
505 $.ajax({
506 url: "${h.url('goto_switcher_data')}",
506 url: pyroutes.url('goto_switcher_data'),
507 data: {'query': query.term},
507 data: {'query': query.term},
508 dataType: 'json',
508 dataType: 'json',
509 type: 'GET',
509 type: 'GET',
510 success: function(data) {
510 success: function(data) {
511 self.cachedDataSource[cacheKey] = data;
511 self.cachedDataSource[cacheKey] = data;
512 query.callback({results: data.results});
512 query.callback({results: data.results});
513 },
513 },
514 error: function(data, textStatus, errorThrown) {
514 error: function(data, textStatus, errorThrown) {
515 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
515 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
516 }
516 }
517 })
517 })
518 }
518 }
519 })
519 })
520 });
520 });
521
521
522 $("#repo_switcher").on('select2-selecting', function(e){
522 $("#repo_switcher").on('select2-selecting', function(e){
523 e.preventDefault();
523 e.preventDefault();
524 window.location = e.choice.url;
524 window.location = e.choice.url;
525 });
525 });
526
526
527 </script>
527 </script>
528 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
528 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
529 </%def>
529 </%def>
530
530
531 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
531 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
532 <div class="modal-dialog">
532 <div class="modal-dialog">
533 <div class="modal-content">
533 <div class="modal-content">
534 <div class="modal-header">
534 <div class="modal-header">
535 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
535 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
536 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
536 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
537 </div>
537 </div>
538 <div class="modal-body">
538 <div class="modal-body">
539 <div class="block-left">
539 <div class="block-left">
540 <table class="keyboard-mappings">
540 <table class="keyboard-mappings">
541 <tbody>
541 <tbody>
542 <tr>
542 <tr>
543 <th></th>
543 <th></th>
544 <th>${_('Site-wide shortcuts')}</th>
544 <th>${_('Site-wide shortcuts')}</th>
545 </tr>
545 </tr>
546 <%
546 <%
547 elems = [
547 elems = [
548 ('/', 'Open quick search box'),
548 ('/', 'Open quick search box'),
549 ('g h', 'Goto home page'),
549 ('g h', 'Goto home page'),
550 ('g g', 'Goto my private gists page'),
550 ('g g', 'Goto my private gists page'),
551 ('g G', 'Goto my public gists page'),
551 ('g G', 'Goto my public gists page'),
552 ('n r', 'New repository page'),
552 ('n r', 'New repository page'),
553 ('n g', 'New gist page'),
553 ('n g', 'New gist page'),
554 ]
554 ]
555 %>
555 %>
556 %for key, desc in elems:
556 %for key, desc in elems:
557 <tr>
557 <tr>
558 <td class="keys">
558 <td class="keys">
559 <span class="key tag">${key}</span>
559 <span class="key tag">${key}</span>
560 </td>
560 </td>
561 <td>${desc}</td>
561 <td>${desc}</td>
562 </tr>
562 </tr>
563 %endfor
563 %endfor
564 </tbody>
564 </tbody>
565 </table>
565 </table>
566 </div>
566 </div>
567 <div class="block-left">
567 <div class="block-left">
568 <table class="keyboard-mappings">
568 <table class="keyboard-mappings">
569 <tbody>
569 <tbody>
570 <tr>
570 <tr>
571 <th></th>
571 <th></th>
572 <th>${_('Repositories')}</th>
572 <th>${_('Repositories')}</th>
573 </tr>
573 </tr>
574 <%
574 <%
575 elems = [
575 elems = [
576 ('g s', 'Goto summary page'),
576 ('g s', 'Goto summary page'),
577 ('g c', 'Goto changelog page'),
577 ('g c', 'Goto changelog page'),
578 ('g f', 'Goto files page'),
578 ('g f', 'Goto files page'),
579 ('g F', 'Goto files page with file search activated'),
579 ('g F', 'Goto files page with file search activated'),
580 ('g p', 'Goto pull requests page'),
580 ('g p', 'Goto pull requests page'),
581 ('g o', 'Goto repository settings'),
581 ('g o', 'Goto repository settings'),
582 ('g O', 'Goto repository permissions settings'),
582 ('g O', 'Goto repository permissions settings'),
583 ]
583 ]
584 %>
584 %>
585 %for key, desc in elems:
585 %for key, desc in elems:
586 <tr>
586 <tr>
587 <td class="keys">
587 <td class="keys">
588 <span class="key tag">${key}</span>
588 <span class="key tag">${key}</span>
589 </td>
589 </td>
590 <td>${desc}</td>
590 <td>${desc}</td>
591 </tr>
591 </tr>
592 %endfor
592 %endfor
593 </tbody>
593 </tbody>
594 </table>
594 </table>
595 </div>
595 </div>
596 </div>
596 </div>
597 <div class="modal-footer">
597 <div class="modal-footer">
598 </div>
598 </div>
599 </div><!-- /.modal-content -->
599 </div><!-- /.modal-content -->
600 </div><!-- /.modal-dialog -->
600 </div><!-- /.modal-dialog -->
601 </div><!-- /.modal -->
601 </div><!-- /.modal -->
@@ -1,257 +1,129 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 json
22
21
23 from mock import patch
24 import pytest
22 import pytest
25 from pylons import tmpl_context as c
23 from pylons import tmpl_context as c
26
24
27 import rhodecode
25 import rhodecode
28 from rhodecode.lib.utils import map_groups
26 from rhodecode.model.db import Repository, User
29 from rhodecode.model.db import Repository, User, RepoGroup
30 from rhodecode.model.meta import Session
27 from rhodecode.model.meta import Session
31 from rhodecode.model.repo import RepoModel
28 from rhodecode.model.repo import RepoModel
32 from rhodecode.model.repo_group import RepoGroupModel
29 from rhodecode.model.repo_group import RepoGroupModel
33 from rhodecode.model.settings import SettingsModel
30 from rhodecode.model.settings import SettingsModel
34 from rhodecode.tests import TestController, url, TEST_USER_ADMIN_LOGIN
31 from rhodecode.tests import TestController, url
35 from rhodecode.tests.fixture import Fixture
32 from rhodecode.tests.fixture import Fixture
36
33
37
34
38 fixture = Fixture()
35 fixture = Fixture()
39
36
40
37
41 class TestHomeController(TestController):
38 class TestHomeController(TestController):
42
39
43 def test_index(self):
40 def test_index(self):
44 self.log_user()
41 self.log_user()
45 response = self.app.get(url(controller='home', action='index'))
42 response = self.app.get(url(controller='home', action='index'))
46 # if global permission is set
43 # if global permission is set
47 response.mustcontain('Add Repository')
44 response.mustcontain('Add Repository')
48
45
49 # search for objects inside the JavaScript JSON
46 # search for objects inside the JavaScript JSON
50 for repo in Repository.getAll():
47 for repo in Repository.getAll():
51 response.mustcontain('"name_raw": "%s"' % repo.repo_name)
48 response.mustcontain('"name_raw": "%s"' % repo.repo_name)
52
49
53 def test_index_contains_statics_with_ver(self):
50 def test_index_contains_statics_with_ver(self):
54 self.log_user()
51 self.log_user()
55 response = self.app.get(url(controller='home', action='index'))
52 response = self.app.get(url(controller='home', action='index'))
56
53
57 rhodecode_version_hash = c.rhodecode_version_hash
54 rhodecode_version_hash = c.rhodecode_version_hash
58 response.mustcontain('style.css?ver={0}'.format(rhodecode_version_hash))
55 response.mustcontain('style.css?ver={0}'.format(rhodecode_version_hash))
59 response.mustcontain('rhodecode-components.js?ver={0}'.format(rhodecode_version_hash))
56 response.mustcontain('rhodecode-components.js?ver={0}'.format(rhodecode_version_hash))
60
57
61 def test_index_contains_backend_specific_details(self, backend):
58 def test_index_contains_backend_specific_details(self, backend):
62 self.log_user()
59 self.log_user()
63 response = self.app.get(url(controller='home', action='index'))
60 response = self.app.get(url(controller='home', action='index'))
64 tip = backend.repo.get_commit().raw_id
61 tip = backend.repo.get_commit().raw_id
65
62
66 # html in javascript variable:
63 # html in javascript variable:
67 response.mustcontain(r'<i class=\"icon-%s\"' % (backend.alias, ))
64 response.mustcontain(r'<i class=\"icon-%s\"' % (backend.alias, ))
68 response.mustcontain(r'href=\"/%s\"' % (backend.repo_name, ))
65 response.mustcontain(r'href=\"/%s\"' % (backend.repo_name, ))
69
66
70 response.mustcontain("""/%s/changeset/%s""" % (backend.repo_name, tip))
67 response.mustcontain("""/%s/changeset/%s""" % (backend.repo_name, tip))
71 response.mustcontain("""Added a symlink""")
68 response.mustcontain("""Added a symlink""")
72
69
73 def test_index_with_anonymous_access_disabled(self):
70 def test_index_with_anonymous_access_disabled(self):
74 with fixture.anon_access(False):
71 with fixture.anon_access(False):
75 response = self.app.get(url(controller='home', action='index'),
72 response = self.app.get(url(controller='home', action='index'),
76 status=302)
73 status=302)
77 assert 'login' in response.location
74 assert 'login' in response.location
78
75
79 def test_index_page_on_groups(self, autologin_user, repo_group):
76 def test_index_page_on_groups(self, autologin_user, repo_group):
80 response = self.app.get(url('repo_group_home', group_name='gr1'))
77 response = self.app.get(url('repo_group_home', group_name='gr1'))
81 response.mustcontain("gr1/repo_in_group")
78 response.mustcontain("gr1/repo_in_group")
82
79
83 def test_index_page_on_group_with_trailing_slash(
80 def test_index_page_on_group_with_trailing_slash(
84 self, autologin_user, repo_group):
81 self, autologin_user, repo_group):
85 response = self.app.get(url('repo_group_home', group_name='gr1') + '/')
82 response = self.app.get(url('repo_group_home', group_name='gr1') + '/')
86 response.mustcontain("gr1/repo_in_group")
83 response.mustcontain("gr1/repo_in_group")
87
84
88 @pytest.fixture(scope='class')
85 @pytest.fixture(scope='class')
89 def repo_group(self, request):
86 def repo_group(self, request):
90 gr = fixture.create_repo_group('gr1')
87 gr = fixture.create_repo_group('gr1')
91 fixture.create_repo(name='gr1/repo_in_group', repo_group=gr)
88 fixture.create_repo(name='gr1/repo_in_group', repo_group=gr)
92
89
93 @request.addfinalizer
90 @request.addfinalizer
94 def cleanup():
91 def cleanup():
95 RepoModel().delete('gr1/repo_in_group')
92 RepoModel().delete('gr1/repo_in_group')
96 RepoGroupModel().delete(repo_group='gr1', force_delete=True)
93 RepoGroupModel().delete(repo_group='gr1', force_delete=True)
97 Session().commit()
94 Session().commit()
98
95
99 def test_index_with_name_with_tags(self, autologin_user):
96 def test_index_with_name_with_tags(self, autologin_user):
100 user = User.get_by_username('test_admin')
97 user = User.get_by_username('test_admin')
101 user.name = '<img src="/image1" onload="alert(\'Hello, World!\');">'
98 user.name = '<img src="/image1" onload="alert(\'Hello, World!\');">'
102 user.lastname = (
99 user.lastname = (
103 '<img src="/image2" onload="alert(\'Hello, World!\');">')
100 '<img src="/image2" onload="alert(\'Hello, World!\');">')
104 Session().add(user)
101 Session().add(user)
105 Session().commit()
102 Session().commit()
106
103
107 response = self.app.get(url(controller='home', action='index'))
104 response = self.app.get(url(controller='home', action='index'))
108 response.mustcontain(
105 response.mustcontain(
109 '&lt;img src=&#34;/image1&#34; onload=&#34;'
106 '&lt;img src=&#34;/image1&#34; onload=&#34;'
110 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
107 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
111 response.mustcontain(
108 response.mustcontain(
112 '&lt;img src=&#34;/image2&#34; onload=&#34;'
109 '&lt;img src=&#34;/image2&#34; onload=&#34;'
113 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
110 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
114
111
115 @pytest.mark.parametrize("name, state", [
112 @pytest.mark.parametrize("name, state", [
116 ('Disabled', False),
113 ('Disabled', False),
117 ('Enabled', True),
114 ('Enabled', True),
118 ])
115 ])
119 def test_index_show_version(self, autologin_user, name, state):
116 def test_index_show_version(self, autologin_user, name, state):
120 version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__
117 version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__
121
118
122 sett = SettingsModel().create_or_update_setting(
119 sett = SettingsModel().create_or_update_setting(
123 'show_version', state, 'bool')
120 'show_version', state, 'bool')
124 Session().add(sett)
121 Session().add(sett)
125 Session().commit()
122 Session().commit()
126 SettingsModel().invalidate_settings_cache()
123 SettingsModel().invalidate_settings_cache()
127
124
128 response = self.app.get(url(controller='home', action='index'))
125 response = self.app.get(url(controller='home', action='index'))
129 if state is True:
126 if state is True:
130 response.mustcontain(version_string)
127 response.mustcontain(version_string)
131 if state is False:
128 if state is False:
132 response.mustcontain(no=[version_string])
129 response.mustcontain(no=[version_string])
133
134
135 def assert_and_get_content(result):
136 repos = []
137 groups = []
138 commits = []
139 for data in result:
140 for data_item in data['children']:
141 assert data_item['id']
142 assert data_item['text']
143 assert data_item['url']
144 if data_item['type'] == 'repo':
145 repos.append(data_item)
146 elif data_item['type'] == 'group':
147 groups.append(data_item)
148 elif data_item['type'] == 'commit':
149 commits.append(data_item)
150 else:
151 raise Exception('invalid type %s' % data_item['type'])
152
153 return repos, groups, commits
154
155
156 class TestGotoSwitcherData(TestController):
157 required_repos_with_groups = [
158 'abc',
159 'abc-fork',
160 'forks/abcd',
161 'abcd',
162 'abcde',
163 'a/abc',
164 'aa/abc',
165 'aaa/abc',
166 'aaaa/abc',
167 'repos_abc/aaa/abc',
168 'abc_repos/abc',
169 'abc_repos/abcd',
170 'xxx/xyz',
171 'forked-abc/a/abc'
172 ]
173
174 @pytest.fixture(autouse=True, scope='class')
175 def prepare(self, request, pylonsapp):
176 for repo_and_group in self.required_repos_with_groups:
177 # create structure of groups and return the last group
178
179 repo_group = map_groups(repo_and_group)
180
181 RepoModel()._create_repo(
182 repo_and_group, 'hg', 'test-ac', TEST_USER_ADMIN_LOGIN,
183 repo_group=getattr(repo_group, 'group_id', None))
184
185 Session().commit()
186
187 request.addfinalizer(self.cleanup)
188
189 def cleanup(self):
190 # first delete all repos
191 for repo_and_groups in self.required_repos_with_groups:
192 repo = Repository.get_by_repo_name(repo_and_groups)
193 if repo:
194 RepoModel().delete(repo)
195 Session().commit()
196
197 # then delete all empty groups
198 for repo_and_groups in self.required_repos_with_groups:
199 if '/' in repo_and_groups:
200 r_group = repo_and_groups.rsplit('/', 1)[0]
201 repo_group = RepoGroup.get_by_group_name(r_group)
202 if not repo_group:
203 continue
204 parents = repo_group.parents
205 RepoGroupModel().delete(repo_group, force_delete=True)
206 Session().commit()
207
208 for el in reversed(parents):
209 RepoGroupModel().delete(el, force_delete=True)
210 Session().commit()
211
212 def test_returns_list_of_repos_and_groups(self):
213 self.log_user()
214
215 response = self.app.get(
216 url(controller='home', action='goto_switcher_data'),
217 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
218 result = json.loads(response.body)['results']
219
220 repos, groups, commits = assert_and_get_content(result)
221
222 assert len(repos) == len(Repository.get_all())
223 assert len(groups) == len(RepoGroup.get_all())
224 assert len(commits) == 0
225
226 def test_returns_list_of_repos_and_groups_filtered(self):
227 self.log_user()
228
229 response = self.app.get(
230 url(controller='home', action='goto_switcher_data'),
231 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', },
232 params={'query': 'abc'}, status=200)
233 result = json.loads(response.body)['results']
234
235 repos, groups, commits = assert_and_get_content(result)
236
237 assert len(repos) == 13
238 assert len(groups) == 5
239 assert len(commits) == 0
240
241 def test_returns_list_of_properly_sorted_and_filtered(self):
242 self.log_user()
243
244 response = self.app.get(
245 url(controller='home', action='goto_switcher_data'),
246 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', },
247 params={'query': 'abc'}, status=200)
248 result = json.loads(response.body)['results']
249
250 repos, groups, commits = assert_and_get_content(result)
251
252 test_repos = [x['text'] for x in repos[:4]]
253 assert ['abc', 'abcd', 'a/abc', 'abcde'] == test_repos
254
255 test_groups = [x['text'] for x in groups[:4]]
256 assert ['abc_repos', 'repos_abc',
257 'forked-abc', 'forked-abc/a'] == test_groups
General Comments 0
You need to be logged in to leave comments. Login now