##// END OF EJS Templates
channelstream: added testing panel for live-notifications.
marcink -
r1274:2537ec98 default
parent child Browse files
Show More
@@ -1,1169 +1,1173 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 ('user_profile', '/profile/%(username)s', ['username'])
95 ('user_profile', '/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',
191 rmap.connect('goto_switcher_data', '/_goto_data', controller='home',
192 action='goto_switcher_data')
192 action='goto_switcher_data')
193 rmap.connect('repo_list_data', '/_repos', controller='home',
193 rmap.connect('repo_list_data', '/_repos', controller='home',
194 action='repo_list_data')
194 action='repo_list_data')
195
195
196 rmap.connect('user_autocomplete_data', '/_users', controller='home',
196 rmap.connect('user_autocomplete_data', '/_users', controller='home',
197 action='user_autocomplete_data', jsroute=True)
197 action='user_autocomplete_data', jsroute=True)
198 rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
198 rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
199 action='user_group_autocomplete_data', jsroute=True)
199 action='user_group_autocomplete_data', jsroute=True)
200
200
201 rmap.connect(
201 rmap.connect(
202 'user_profile', '/_profiles/{username}', controller='users',
202 'user_profile', '/_profiles/{username}', controller='users',
203 action='user_profile')
203 action='user_profile')
204
204
205 # TODO: johbo: Static links, to be replaced by our redirection mechanism
205 # TODO: johbo: Static links, to be replaced by our redirection mechanism
206 rmap.connect('rst_help',
206 rmap.connect('rst_help',
207 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
207 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
208 _static=True)
208 _static=True)
209 rmap.connect('markdown_help',
209 rmap.connect('markdown_help',
210 'http://daringfireball.net/projects/markdown/syntax',
210 'http://daringfireball.net/projects/markdown/syntax',
211 _static=True)
211 _static=True)
212 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
212 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
213 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
213 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
214 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
214 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
215 # TODO: anderson - making this a static link since redirect won't play
215 # TODO: anderson - making this a static link since redirect won't play
216 # nice with POST requests
216 # nice with POST requests
217 rmap.connect('enterprise_license_convert_from_old',
217 rmap.connect('enterprise_license_convert_from_old',
218 'https://rhodecode.com/u/license-upgrade',
218 'https://rhodecode.com/u/license-upgrade',
219 _static=True)
219 _static=True)
220
220
221 routing_links.connect_redirection_links(rmap)
221 routing_links.connect_redirection_links(rmap)
222
222
223 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
223 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
224 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
224 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
225
225
226 # ADMIN REPOSITORY ROUTES
226 # ADMIN REPOSITORY ROUTES
227 with rmap.submapper(path_prefix=ADMIN_PREFIX,
227 with rmap.submapper(path_prefix=ADMIN_PREFIX,
228 controller='admin/repos') as m:
228 controller='admin/repos') as m:
229 m.connect('repos', '/repos',
229 m.connect('repos', '/repos',
230 action='create', conditions={'method': ['POST']})
230 action='create', conditions={'method': ['POST']})
231 m.connect('repos', '/repos',
231 m.connect('repos', '/repos',
232 action='index', conditions={'method': ['GET']})
232 action='index', conditions={'method': ['GET']})
233 m.connect('new_repo', '/create_repository', jsroute=True,
233 m.connect('new_repo', '/create_repository', jsroute=True,
234 action='create_repository', conditions={'method': ['GET']})
234 action='create_repository', conditions={'method': ['GET']})
235 m.connect('/repos/{repo_name}',
235 m.connect('/repos/{repo_name}',
236 action='update', conditions={'method': ['PUT'],
236 action='update', conditions={'method': ['PUT'],
237 'function': check_repo},
237 'function': check_repo},
238 requirements=URL_NAME_REQUIREMENTS)
238 requirements=URL_NAME_REQUIREMENTS)
239 m.connect('delete_repo', '/repos/{repo_name}',
239 m.connect('delete_repo', '/repos/{repo_name}',
240 action='delete', conditions={'method': ['DELETE']},
240 action='delete', conditions={'method': ['DELETE']},
241 requirements=URL_NAME_REQUIREMENTS)
241 requirements=URL_NAME_REQUIREMENTS)
242 m.connect('repo', '/repos/{repo_name}',
242 m.connect('repo', '/repos/{repo_name}',
243 action='show', conditions={'method': ['GET'],
243 action='show', conditions={'method': ['GET'],
244 'function': check_repo},
244 'function': check_repo},
245 requirements=URL_NAME_REQUIREMENTS)
245 requirements=URL_NAME_REQUIREMENTS)
246
246
247 # ADMIN REPOSITORY GROUPS ROUTES
247 # ADMIN REPOSITORY GROUPS ROUTES
248 with rmap.submapper(path_prefix=ADMIN_PREFIX,
248 with rmap.submapper(path_prefix=ADMIN_PREFIX,
249 controller='admin/repo_groups') as m:
249 controller='admin/repo_groups') as m:
250 m.connect('repo_groups', '/repo_groups',
250 m.connect('repo_groups', '/repo_groups',
251 action='create', conditions={'method': ['POST']})
251 action='create', conditions={'method': ['POST']})
252 m.connect('repo_groups', '/repo_groups',
252 m.connect('repo_groups', '/repo_groups',
253 action='index', conditions={'method': ['GET']})
253 action='index', conditions={'method': ['GET']})
254 m.connect('new_repo_group', '/repo_groups/new',
254 m.connect('new_repo_group', '/repo_groups/new',
255 action='new', conditions={'method': ['GET']})
255 action='new', conditions={'method': ['GET']})
256 m.connect('update_repo_group', '/repo_groups/{group_name}',
256 m.connect('update_repo_group', '/repo_groups/{group_name}',
257 action='update', conditions={'method': ['PUT'],
257 action='update', conditions={'method': ['PUT'],
258 'function': check_group},
258 'function': check_group},
259 requirements=URL_NAME_REQUIREMENTS)
259 requirements=URL_NAME_REQUIREMENTS)
260
260
261 # EXTRAS REPO GROUP ROUTES
261 # EXTRAS REPO GROUP ROUTES
262 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
262 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
263 action='edit',
263 action='edit',
264 conditions={'method': ['GET'], 'function': check_group},
264 conditions={'method': ['GET'], 'function': check_group},
265 requirements=URL_NAME_REQUIREMENTS)
265 requirements=URL_NAME_REQUIREMENTS)
266 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
266 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
267 action='edit',
267 action='edit',
268 conditions={'method': ['PUT'], 'function': check_group},
268 conditions={'method': ['PUT'], 'function': check_group},
269 requirements=URL_NAME_REQUIREMENTS)
269 requirements=URL_NAME_REQUIREMENTS)
270
270
271 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
271 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
272 action='edit_repo_group_advanced',
272 action='edit_repo_group_advanced',
273 conditions={'method': ['GET'], 'function': check_group},
273 conditions={'method': ['GET'], 'function': check_group},
274 requirements=URL_NAME_REQUIREMENTS)
274 requirements=URL_NAME_REQUIREMENTS)
275 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
275 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
276 action='edit_repo_group_advanced',
276 action='edit_repo_group_advanced',
277 conditions={'method': ['PUT'], 'function': check_group},
277 conditions={'method': ['PUT'], 'function': check_group},
278 requirements=URL_NAME_REQUIREMENTS)
278 requirements=URL_NAME_REQUIREMENTS)
279
279
280 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
280 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
281 action='edit_repo_group_perms',
281 action='edit_repo_group_perms',
282 conditions={'method': ['GET'], 'function': check_group},
282 conditions={'method': ['GET'], 'function': check_group},
283 requirements=URL_NAME_REQUIREMENTS)
283 requirements=URL_NAME_REQUIREMENTS)
284 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
284 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
285 action='update_perms',
285 action='update_perms',
286 conditions={'method': ['PUT'], 'function': check_group},
286 conditions={'method': ['PUT'], 'function': check_group},
287 requirements=URL_NAME_REQUIREMENTS)
287 requirements=URL_NAME_REQUIREMENTS)
288
288
289 m.connect('delete_repo_group', '/repo_groups/{group_name}',
289 m.connect('delete_repo_group', '/repo_groups/{group_name}',
290 action='delete', conditions={'method': ['DELETE'],
290 action='delete', conditions={'method': ['DELETE'],
291 'function': check_group},
291 'function': check_group},
292 requirements=URL_NAME_REQUIREMENTS)
292 requirements=URL_NAME_REQUIREMENTS)
293
293
294 # ADMIN USER ROUTES
294 # ADMIN USER ROUTES
295 with rmap.submapper(path_prefix=ADMIN_PREFIX,
295 with rmap.submapper(path_prefix=ADMIN_PREFIX,
296 controller='admin/users') as m:
296 controller='admin/users') as m:
297 m.connect('users', '/users',
297 m.connect('users', '/users',
298 action='create', conditions={'method': ['POST']})
298 action='create', conditions={'method': ['POST']})
299 m.connect('users', '/users',
299 m.connect('users', '/users',
300 action='index', conditions={'method': ['GET']})
300 action='index', conditions={'method': ['GET']})
301 m.connect('new_user', '/users/new',
301 m.connect('new_user', '/users/new',
302 action='new', conditions={'method': ['GET']})
302 action='new', conditions={'method': ['GET']})
303 m.connect('update_user', '/users/{user_id}',
303 m.connect('update_user', '/users/{user_id}',
304 action='update', conditions={'method': ['PUT']})
304 action='update', conditions={'method': ['PUT']})
305 m.connect('delete_user', '/users/{user_id}',
305 m.connect('delete_user', '/users/{user_id}',
306 action='delete', conditions={'method': ['DELETE']})
306 action='delete', conditions={'method': ['DELETE']})
307 m.connect('edit_user', '/users/{user_id}/edit',
307 m.connect('edit_user', '/users/{user_id}/edit',
308 action='edit', conditions={'method': ['GET']}, jsroute=True)
308 action='edit', conditions={'method': ['GET']}, jsroute=True)
309 m.connect('user', '/users/{user_id}',
309 m.connect('user', '/users/{user_id}',
310 action='show', conditions={'method': ['GET']})
310 action='show', conditions={'method': ['GET']})
311 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
311 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
312 action='reset_password', conditions={'method': ['POST']})
312 action='reset_password', conditions={'method': ['POST']})
313 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
313 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
314 action='create_personal_repo_group', conditions={'method': ['POST']})
314 action='create_personal_repo_group', conditions={'method': ['POST']})
315
315
316 # EXTRAS USER ROUTES
316 # EXTRAS USER ROUTES
317 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
317 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
318 action='edit_advanced', conditions={'method': ['GET']})
318 action='edit_advanced', conditions={'method': ['GET']})
319 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
319 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
320 action='update_advanced', conditions={'method': ['PUT']})
320 action='update_advanced', conditions={'method': ['PUT']})
321
321
322 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
322 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
323 action='edit_auth_tokens', conditions={'method': ['GET']})
323 action='edit_auth_tokens', conditions={'method': ['GET']})
324 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
324 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
325 action='add_auth_token', conditions={'method': ['PUT']})
325 action='add_auth_token', conditions={'method': ['PUT']})
326 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
326 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
327 action='delete_auth_token', conditions={'method': ['DELETE']})
327 action='delete_auth_token', conditions={'method': ['DELETE']})
328
328
329 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
329 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
330 action='edit_global_perms', conditions={'method': ['GET']})
330 action='edit_global_perms', conditions={'method': ['GET']})
331 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
331 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
332 action='update_global_perms', conditions={'method': ['PUT']})
332 action='update_global_perms', conditions={'method': ['PUT']})
333
333
334 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
334 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
335 action='edit_perms_summary', conditions={'method': ['GET']})
335 action='edit_perms_summary', conditions={'method': ['GET']})
336
336
337 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
337 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
338 action='edit_emails', conditions={'method': ['GET']})
338 action='edit_emails', conditions={'method': ['GET']})
339 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
339 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
340 action='add_email', conditions={'method': ['PUT']})
340 action='add_email', conditions={'method': ['PUT']})
341 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
341 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
342 action='delete_email', conditions={'method': ['DELETE']})
342 action='delete_email', conditions={'method': ['DELETE']})
343
343
344 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
344 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
345 action='edit_ips', conditions={'method': ['GET']})
345 action='edit_ips', conditions={'method': ['GET']})
346 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
346 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
347 action='add_ip', conditions={'method': ['PUT']})
347 action='add_ip', conditions={'method': ['PUT']})
348 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
348 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
349 action='delete_ip', conditions={'method': ['DELETE']})
349 action='delete_ip', conditions={'method': ['DELETE']})
350
350
351 # ADMIN USER GROUPS REST ROUTES
351 # ADMIN USER GROUPS REST ROUTES
352 with rmap.submapper(path_prefix=ADMIN_PREFIX,
352 with rmap.submapper(path_prefix=ADMIN_PREFIX,
353 controller='admin/user_groups') as m:
353 controller='admin/user_groups') as m:
354 m.connect('users_groups', '/user_groups',
354 m.connect('users_groups', '/user_groups',
355 action='create', conditions={'method': ['POST']})
355 action='create', conditions={'method': ['POST']})
356 m.connect('users_groups', '/user_groups',
356 m.connect('users_groups', '/user_groups',
357 action='index', conditions={'method': ['GET']})
357 action='index', conditions={'method': ['GET']})
358 m.connect('new_users_group', '/user_groups/new',
358 m.connect('new_users_group', '/user_groups/new',
359 action='new', conditions={'method': ['GET']})
359 action='new', conditions={'method': ['GET']})
360 m.connect('update_users_group', '/user_groups/{user_group_id}',
360 m.connect('update_users_group', '/user_groups/{user_group_id}',
361 action='update', conditions={'method': ['PUT']})
361 action='update', conditions={'method': ['PUT']})
362 m.connect('delete_users_group', '/user_groups/{user_group_id}',
362 m.connect('delete_users_group', '/user_groups/{user_group_id}',
363 action='delete', conditions={'method': ['DELETE']})
363 action='delete', conditions={'method': ['DELETE']})
364 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
364 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
365 action='edit', conditions={'method': ['GET']},
365 action='edit', conditions={'method': ['GET']},
366 function=check_user_group)
366 function=check_user_group)
367
367
368 # EXTRAS USER GROUP ROUTES
368 # EXTRAS USER GROUP ROUTES
369 m.connect('edit_user_group_global_perms',
369 m.connect('edit_user_group_global_perms',
370 '/user_groups/{user_group_id}/edit/global_permissions',
370 '/user_groups/{user_group_id}/edit/global_permissions',
371 action='edit_global_perms', conditions={'method': ['GET']})
371 action='edit_global_perms', conditions={'method': ['GET']})
372 m.connect('edit_user_group_global_perms',
372 m.connect('edit_user_group_global_perms',
373 '/user_groups/{user_group_id}/edit/global_permissions',
373 '/user_groups/{user_group_id}/edit/global_permissions',
374 action='update_global_perms', conditions={'method': ['PUT']})
374 action='update_global_perms', conditions={'method': ['PUT']})
375 m.connect('edit_user_group_perms_summary',
375 m.connect('edit_user_group_perms_summary',
376 '/user_groups/{user_group_id}/edit/permissions_summary',
376 '/user_groups/{user_group_id}/edit/permissions_summary',
377 action='edit_perms_summary', conditions={'method': ['GET']})
377 action='edit_perms_summary', conditions={'method': ['GET']})
378
378
379 m.connect('edit_user_group_perms',
379 m.connect('edit_user_group_perms',
380 '/user_groups/{user_group_id}/edit/permissions',
380 '/user_groups/{user_group_id}/edit/permissions',
381 action='edit_perms', conditions={'method': ['GET']})
381 action='edit_perms', conditions={'method': ['GET']})
382 m.connect('edit_user_group_perms',
382 m.connect('edit_user_group_perms',
383 '/user_groups/{user_group_id}/edit/permissions',
383 '/user_groups/{user_group_id}/edit/permissions',
384 action='update_perms', conditions={'method': ['PUT']})
384 action='update_perms', conditions={'method': ['PUT']})
385
385
386 m.connect('edit_user_group_advanced',
386 m.connect('edit_user_group_advanced',
387 '/user_groups/{user_group_id}/edit/advanced',
387 '/user_groups/{user_group_id}/edit/advanced',
388 action='edit_advanced', conditions={'method': ['GET']})
388 action='edit_advanced', conditions={'method': ['GET']})
389
389
390 m.connect('edit_user_group_members',
390 m.connect('edit_user_group_members',
391 '/user_groups/{user_group_id}/edit/members', jsroute=True,
391 '/user_groups/{user_group_id}/edit/members', jsroute=True,
392 action='user_group_members', conditions={'method': ['GET']})
392 action='user_group_members', conditions={'method': ['GET']})
393
393
394 # ADMIN PERMISSIONS ROUTES
394 # ADMIN PERMISSIONS ROUTES
395 with rmap.submapper(path_prefix=ADMIN_PREFIX,
395 with rmap.submapper(path_prefix=ADMIN_PREFIX,
396 controller='admin/permissions') as m:
396 controller='admin/permissions') as m:
397 m.connect('admin_permissions_application', '/permissions/application',
397 m.connect('admin_permissions_application', '/permissions/application',
398 action='permission_application_update', conditions={'method': ['POST']})
398 action='permission_application_update', conditions={'method': ['POST']})
399 m.connect('admin_permissions_application', '/permissions/application',
399 m.connect('admin_permissions_application', '/permissions/application',
400 action='permission_application', conditions={'method': ['GET']})
400 action='permission_application', conditions={'method': ['GET']})
401
401
402 m.connect('admin_permissions_global', '/permissions/global',
402 m.connect('admin_permissions_global', '/permissions/global',
403 action='permission_global_update', conditions={'method': ['POST']})
403 action='permission_global_update', conditions={'method': ['POST']})
404 m.connect('admin_permissions_global', '/permissions/global',
404 m.connect('admin_permissions_global', '/permissions/global',
405 action='permission_global', conditions={'method': ['GET']})
405 action='permission_global', conditions={'method': ['GET']})
406
406
407 m.connect('admin_permissions_object', '/permissions/object',
407 m.connect('admin_permissions_object', '/permissions/object',
408 action='permission_objects_update', conditions={'method': ['POST']})
408 action='permission_objects_update', conditions={'method': ['POST']})
409 m.connect('admin_permissions_object', '/permissions/object',
409 m.connect('admin_permissions_object', '/permissions/object',
410 action='permission_objects', conditions={'method': ['GET']})
410 action='permission_objects', conditions={'method': ['GET']})
411
411
412 m.connect('admin_permissions_ips', '/permissions/ips',
412 m.connect('admin_permissions_ips', '/permissions/ips',
413 action='permission_ips', conditions={'method': ['POST']})
413 action='permission_ips', conditions={'method': ['POST']})
414 m.connect('admin_permissions_ips', '/permissions/ips',
414 m.connect('admin_permissions_ips', '/permissions/ips',
415 action='permission_ips', conditions={'method': ['GET']})
415 action='permission_ips', conditions={'method': ['GET']})
416
416
417 m.connect('admin_permissions_overview', '/permissions/overview',
417 m.connect('admin_permissions_overview', '/permissions/overview',
418 action='permission_perms', conditions={'method': ['GET']})
418 action='permission_perms', conditions={'method': ['GET']})
419
419
420 # ADMIN DEFAULTS REST ROUTES
420 # ADMIN DEFAULTS REST ROUTES
421 with rmap.submapper(path_prefix=ADMIN_PREFIX,
421 with rmap.submapper(path_prefix=ADMIN_PREFIX,
422 controller='admin/defaults') as m:
422 controller='admin/defaults') as m:
423 m.connect('admin_defaults_repositories', '/defaults/repositories',
423 m.connect('admin_defaults_repositories', '/defaults/repositories',
424 action='update_repository_defaults', conditions={'method': ['POST']})
424 action='update_repository_defaults', conditions={'method': ['POST']})
425 m.connect('admin_defaults_repositories', '/defaults/repositories',
425 m.connect('admin_defaults_repositories', '/defaults/repositories',
426 action='index', conditions={'method': ['GET']})
426 action='index', conditions={'method': ['GET']})
427
427
428 # ADMIN DEBUG STYLE ROUTES
428 # ADMIN DEBUG STYLE ROUTES
429 if str2bool(config.get('debug_style')):
429 if str2bool(config.get('debug_style')):
430 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
430 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
431 controller='debug_style') as m:
431 controller='debug_style') as m:
432 m.connect('debug_style_home', '',
432 m.connect('debug_style_home', '',
433 action='index', conditions={'method': ['GET']})
433 action='index', conditions={'method': ['GET']})
434 m.connect('debug_style_template', '/t/{t_path}',
434 m.connect('debug_style_template', '/t/{t_path}',
435 action='template', conditions={'method': ['GET']})
435 action='template', conditions={'method': ['GET']})
436
436
437 # ADMIN SETTINGS ROUTES
437 # ADMIN SETTINGS ROUTES
438 with rmap.submapper(path_prefix=ADMIN_PREFIX,
438 with rmap.submapper(path_prefix=ADMIN_PREFIX,
439 controller='admin/settings') as m:
439 controller='admin/settings') as m:
440
440
441 # default
441 # default
442 m.connect('admin_settings', '/settings',
442 m.connect('admin_settings', '/settings',
443 action='settings_global_update',
443 action='settings_global_update',
444 conditions={'method': ['POST']})
444 conditions={'method': ['POST']})
445 m.connect('admin_settings', '/settings',
445 m.connect('admin_settings', '/settings',
446 action='settings_global', conditions={'method': ['GET']})
446 action='settings_global', conditions={'method': ['GET']})
447
447
448 m.connect('admin_settings_vcs', '/settings/vcs',
448 m.connect('admin_settings_vcs', '/settings/vcs',
449 action='settings_vcs_update',
449 action='settings_vcs_update',
450 conditions={'method': ['POST']})
450 conditions={'method': ['POST']})
451 m.connect('admin_settings_vcs', '/settings/vcs',
451 m.connect('admin_settings_vcs', '/settings/vcs',
452 action='settings_vcs',
452 action='settings_vcs',
453 conditions={'method': ['GET']})
453 conditions={'method': ['GET']})
454 m.connect('admin_settings_vcs', '/settings/vcs',
454 m.connect('admin_settings_vcs', '/settings/vcs',
455 action='delete_svn_pattern',
455 action='delete_svn_pattern',
456 conditions={'method': ['DELETE']})
456 conditions={'method': ['DELETE']})
457
457
458 m.connect('admin_settings_mapping', '/settings/mapping',
458 m.connect('admin_settings_mapping', '/settings/mapping',
459 action='settings_mapping_update',
459 action='settings_mapping_update',
460 conditions={'method': ['POST']})
460 conditions={'method': ['POST']})
461 m.connect('admin_settings_mapping', '/settings/mapping',
461 m.connect('admin_settings_mapping', '/settings/mapping',
462 action='settings_mapping', conditions={'method': ['GET']})
462 action='settings_mapping', conditions={'method': ['GET']})
463
463
464 m.connect('admin_settings_global', '/settings/global',
464 m.connect('admin_settings_global', '/settings/global',
465 action='settings_global_update',
465 action='settings_global_update',
466 conditions={'method': ['POST']})
466 conditions={'method': ['POST']})
467 m.connect('admin_settings_global', '/settings/global',
467 m.connect('admin_settings_global', '/settings/global',
468 action='settings_global', conditions={'method': ['GET']})
468 action='settings_global', conditions={'method': ['GET']})
469
469
470 m.connect('admin_settings_visual', '/settings/visual',
470 m.connect('admin_settings_visual', '/settings/visual',
471 action='settings_visual_update',
471 action='settings_visual_update',
472 conditions={'method': ['POST']})
472 conditions={'method': ['POST']})
473 m.connect('admin_settings_visual', '/settings/visual',
473 m.connect('admin_settings_visual', '/settings/visual',
474 action='settings_visual', conditions={'method': ['GET']})
474 action='settings_visual', conditions={'method': ['GET']})
475
475
476 m.connect('admin_settings_issuetracker',
476 m.connect('admin_settings_issuetracker',
477 '/settings/issue-tracker', action='settings_issuetracker',
477 '/settings/issue-tracker', action='settings_issuetracker',
478 conditions={'method': ['GET']})
478 conditions={'method': ['GET']})
479 m.connect('admin_settings_issuetracker_save',
479 m.connect('admin_settings_issuetracker_save',
480 '/settings/issue-tracker/save',
480 '/settings/issue-tracker/save',
481 action='settings_issuetracker_save',
481 action='settings_issuetracker_save',
482 conditions={'method': ['POST']})
482 conditions={'method': ['POST']})
483 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
483 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
484 action='settings_issuetracker_test',
484 action='settings_issuetracker_test',
485 conditions={'method': ['POST']})
485 conditions={'method': ['POST']})
486 m.connect('admin_issuetracker_delete',
486 m.connect('admin_issuetracker_delete',
487 '/settings/issue-tracker/delete',
487 '/settings/issue-tracker/delete',
488 action='settings_issuetracker_delete',
488 action='settings_issuetracker_delete',
489 conditions={'method': ['DELETE']})
489 conditions={'method': ['DELETE']})
490
490
491 m.connect('admin_settings_email', '/settings/email',
491 m.connect('admin_settings_email', '/settings/email',
492 action='settings_email_update',
492 action='settings_email_update',
493 conditions={'method': ['POST']})
493 conditions={'method': ['POST']})
494 m.connect('admin_settings_email', '/settings/email',
494 m.connect('admin_settings_email', '/settings/email',
495 action='settings_email', conditions={'method': ['GET']})
495 action='settings_email', conditions={'method': ['GET']})
496
496
497 m.connect('admin_settings_hooks', '/settings/hooks',
497 m.connect('admin_settings_hooks', '/settings/hooks',
498 action='settings_hooks_update',
498 action='settings_hooks_update',
499 conditions={'method': ['POST', 'DELETE']})
499 conditions={'method': ['POST', 'DELETE']})
500 m.connect('admin_settings_hooks', '/settings/hooks',
500 m.connect('admin_settings_hooks', '/settings/hooks',
501 action='settings_hooks', conditions={'method': ['GET']})
501 action='settings_hooks', conditions={'method': ['GET']})
502
502
503 m.connect('admin_settings_search', '/settings/search',
503 m.connect('admin_settings_search', '/settings/search',
504 action='settings_search', conditions={'method': ['GET']})
504 action='settings_search', conditions={'method': ['GET']})
505
505
506 m.connect('admin_settings_system', '/settings/system',
506 m.connect('admin_settings_system', '/settings/system',
507 action='settings_system', conditions={'method': ['GET']})
507 action='settings_system', conditions={'method': ['GET']})
508
508
509 m.connect('admin_settings_system_update', '/settings/system/updates',
509 m.connect('admin_settings_system_update', '/settings/system/updates',
510 action='settings_system_update', conditions={'method': ['GET']})
510 action='settings_system_update', conditions={'method': ['GET']})
511
511
512 m.connect('admin_settings_supervisor', '/settings/supervisor',
512 m.connect('admin_settings_supervisor', '/settings/supervisor',
513 action='settings_supervisor', conditions={'method': ['GET']})
513 action='settings_supervisor', conditions={'method': ['GET']})
514 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
514 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
515 action='settings_supervisor_log', conditions={'method': ['GET']})
515 action='settings_supervisor_log', conditions={'method': ['GET']})
516
516
517 m.connect('admin_settings_labs', '/settings/labs',
517 m.connect('admin_settings_labs', '/settings/labs',
518 action='settings_labs_update',
518 action='settings_labs_update',
519 conditions={'method': ['POST']})
519 conditions={'method': ['POST']})
520 m.connect('admin_settings_labs', '/settings/labs',
520 m.connect('admin_settings_labs', '/settings/labs',
521 action='settings_labs', conditions={'method': ['GET']})
521 action='settings_labs', conditions={'method': ['GET']})
522
522
523 # ADMIN MY ACCOUNT
523 # ADMIN MY ACCOUNT
524 with rmap.submapper(path_prefix=ADMIN_PREFIX,
524 with rmap.submapper(path_prefix=ADMIN_PREFIX,
525 controller='admin/my_account') as m:
525 controller='admin/my_account') as m:
526
526
527 m.connect('my_account', '/my_account',
527 m.connect('my_account', '/my_account',
528 action='my_account', conditions={'method': ['GET']})
528 action='my_account', conditions={'method': ['GET']})
529 m.connect('my_account_edit', '/my_account/edit',
529 m.connect('my_account_edit', '/my_account/edit',
530 action='my_account_edit', conditions={'method': ['GET']})
530 action='my_account_edit', conditions={'method': ['GET']})
531 m.connect('my_account', '/my_account',
531 m.connect('my_account', '/my_account',
532 action='my_account_update', conditions={'method': ['POST']})
532 action='my_account_update', conditions={'method': ['POST']})
533
533
534 m.connect('my_account_password', '/my_account/password',
534 m.connect('my_account_password', '/my_account/password',
535 action='my_account_password', conditions={'method': ['GET', 'POST']})
535 action='my_account_password', conditions={'method': ['GET', 'POST']})
536
536
537 m.connect('my_account_repos', '/my_account/repos',
537 m.connect('my_account_repos', '/my_account/repos',
538 action='my_account_repos', conditions={'method': ['GET']})
538 action='my_account_repos', conditions={'method': ['GET']})
539
539
540 m.connect('my_account_watched', '/my_account/watched',
540 m.connect('my_account_watched', '/my_account/watched',
541 action='my_account_watched', conditions={'method': ['GET']})
541 action='my_account_watched', conditions={'method': ['GET']})
542
542
543 m.connect('my_account_pullrequests', '/my_account/pull_requests',
543 m.connect('my_account_pullrequests', '/my_account/pull_requests',
544 action='my_account_pullrequests', conditions={'method': ['GET']})
544 action='my_account_pullrequests', conditions={'method': ['GET']})
545
545
546 m.connect('my_account_perms', '/my_account/perms',
546 m.connect('my_account_perms', '/my_account/perms',
547 action='my_account_perms', conditions={'method': ['GET']})
547 action='my_account_perms', conditions={'method': ['GET']})
548
548
549 m.connect('my_account_emails', '/my_account/emails',
549 m.connect('my_account_emails', '/my_account/emails',
550 action='my_account_emails', conditions={'method': ['GET']})
550 action='my_account_emails', conditions={'method': ['GET']})
551 m.connect('my_account_emails', '/my_account/emails',
551 m.connect('my_account_emails', '/my_account/emails',
552 action='my_account_emails_add', conditions={'method': ['POST']})
552 action='my_account_emails_add', conditions={'method': ['POST']})
553 m.connect('my_account_emails', '/my_account/emails',
553 m.connect('my_account_emails', '/my_account/emails',
554 action='my_account_emails_delete', conditions={'method': ['DELETE']})
554 action='my_account_emails_delete', conditions={'method': ['DELETE']})
555
555
556 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
556 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
557 action='my_account_auth_tokens', conditions={'method': ['GET']})
557 action='my_account_auth_tokens', conditions={'method': ['GET']})
558 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
558 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
559 action='my_account_auth_tokens_add', conditions={'method': ['POST']})
559 action='my_account_auth_tokens_add', conditions={'method': ['POST']})
560 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
560 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
561 action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
561 action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
562 m.connect('my_account_notifications', '/my_account/notifications',
562 m.connect('my_account_notifications', '/my_account/notifications',
563 action='my_notifications',
563 action='my_notifications',
564 conditions={'method': ['GET']})
564 conditions={'method': ['GET']})
565 m.connect('my_account_notifications_toggle_visibility',
565 m.connect('my_account_notifications_toggle_visibility',
566 '/my_account/toggle_visibility',
566 '/my_account/toggle_visibility',
567 action='my_notifications_toggle_visibility',
567 action='my_notifications_toggle_visibility',
568 conditions={'method': ['POST']})
568 conditions={'method': ['POST']})
569 m.connect('my_account_notifications_test_channelstream',
570 '/my_account/test_channelstream',
571 action='my_account_notifications_test_channelstream',
572 conditions={'method': ['POST']})
569
573
570 # NOTIFICATION REST ROUTES
574 # NOTIFICATION REST ROUTES
571 with rmap.submapper(path_prefix=ADMIN_PREFIX,
575 with rmap.submapper(path_prefix=ADMIN_PREFIX,
572 controller='admin/notifications') as m:
576 controller='admin/notifications') as m:
573 m.connect('notifications', '/notifications',
577 m.connect('notifications', '/notifications',
574 action='index', conditions={'method': ['GET']})
578 action='index', conditions={'method': ['GET']})
575 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
579 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
576 action='mark_all_read', conditions={'method': ['POST']})
580 action='mark_all_read', conditions={'method': ['POST']})
577 m.connect('/notifications/{notification_id}',
581 m.connect('/notifications/{notification_id}',
578 action='update', conditions={'method': ['PUT']})
582 action='update', conditions={'method': ['PUT']})
579 m.connect('/notifications/{notification_id}',
583 m.connect('/notifications/{notification_id}',
580 action='delete', conditions={'method': ['DELETE']})
584 action='delete', conditions={'method': ['DELETE']})
581 m.connect('notification', '/notifications/{notification_id}',
585 m.connect('notification', '/notifications/{notification_id}',
582 action='show', conditions={'method': ['GET']})
586 action='show', conditions={'method': ['GET']})
583
587
584 # ADMIN GIST
588 # ADMIN GIST
585 with rmap.submapper(path_prefix=ADMIN_PREFIX,
589 with rmap.submapper(path_prefix=ADMIN_PREFIX,
586 controller='admin/gists') as m:
590 controller='admin/gists') as m:
587 m.connect('gists', '/gists',
591 m.connect('gists', '/gists',
588 action='create', conditions={'method': ['POST']})
592 action='create', conditions={'method': ['POST']})
589 m.connect('gists', '/gists', jsroute=True,
593 m.connect('gists', '/gists', jsroute=True,
590 action='index', conditions={'method': ['GET']})
594 action='index', conditions={'method': ['GET']})
591 m.connect('new_gist', '/gists/new', jsroute=True,
595 m.connect('new_gist', '/gists/new', jsroute=True,
592 action='new', conditions={'method': ['GET']})
596 action='new', conditions={'method': ['GET']})
593
597
594 m.connect('/gists/{gist_id}',
598 m.connect('/gists/{gist_id}',
595 action='delete', conditions={'method': ['DELETE']})
599 action='delete', conditions={'method': ['DELETE']})
596 m.connect('edit_gist', '/gists/{gist_id}/edit',
600 m.connect('edit_gist', '/gists/{gist_id}/edit',
597 action='edit_form', conditions={'method': ['GET']})
601 action='edit_form', conditions={'method': ['GET']})
598 m.connect('edit_gist', '/gists/{gist_id}/edit',
602 m.connect('edit_gist', '/gists/{gist_id}/edit',
599 action='edit', conditions={'method': ['POST']})
603 action='edit', conditions={'method': ['POST']})
600 m.connect(
604 m.connect(
601 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
605 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
602 action='check_revision', conditions={'method': ['GET']})
606 action='check_revision', conditions={'method': ['GET']})
603
607
604 m.connect('gist', '/gists/{gist_id}',
608 m.connect('gist', '/gists/{gist_id}',
605 action='show', conditions={'method': ['GET']})
609 action='show', conditions={'method': ['GET']})
606 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
610 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
607 revision='tip',
611 revision='tip',
608 action='show', conditions={'method': ['GET']})
612 action='show', conditions={'method': ['GET']})
609 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
613 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
610 revision='tip',
614 revision='tip',
611 action='show', conditions={'method': ['GET']})
615 action='show', conditions={'method': ['GET']})
612 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
616 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
613 revision='tip',
617 revision='tip',
614 action='show', conditions={'method': ['GET']},
618 action='show', conditions={'method': ['GET']},
615 requirements=URL_NAME_REQUIREMENTS)
619 requirements=URL_NAME_REQUIREMENTS)
616
620
617 # ADMIN MAIN PAGES
621 # ADMIN MAIN PAGES
618 with rmap.submapper(path_prefix=ADMIN_PREFIX,
622 with rmap.submapper(path_prefix=ADMIN_PREFIX,
619 controller='admin/admin') as m:
623 controller='admin/admin') as m:
620 m.connect('admin_home', '', action='index')
624 m.connect('admin_home', '', action='index')
621 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
625 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
622 action='add_repo')
626 action='add_repo')
623 m.connect(
627 m.connect(
624 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
628 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
625 action='pull_requests')
629 action='pull_requests')
626 m.connect(
630 m.connect(
627 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
631 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
628 action='pull_requests')
632 action='pull_requests')
629 m.connect(
633 m.connect(
630 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
634 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
631 action='pull_requests')
635 action='pull_requests')
632
636
633 # USER JOURNAL
637 # USER JOURNAL
634 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
638 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
635 controller='journal', action='index')
639 controller='journal', action='index')
636 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
640 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
637 controller='journal', action='journal_rss')
641 controller='journal', action='journal_rss')
638 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
642 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
639 controller='journal', action='journal_atom')
643 controller='journal', action='journal_atom')
640
644
641 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
645 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
642 controller='journal', action='public_journal')
646 controller='journal', action='public_journal')
643
647
644 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
648 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
645 controller='journal', action='public_journal_rss')
649 controller='journal', action='public_journal_rss')
646
650
647 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
651 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
648 controller='journal', action='public_journal_rss')
652 controller='journal', action='public_journal_rss')
649
653
650 rmap.connect('public_journal_atom',
654 rmap.connect('public_journal_atom',
651 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
655 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
652 action='public_journal_atom')
656 action='public_journal_atom')
653
657
654 rmap.connect('public_journal_atom_old',
658 rmap.connect('public_journal_atom_old',
655 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
659 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
656 action='public_journal_atom')
660 action='public_journal_atom')
657
661
658 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
662 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
659 controller='journal', action='toggle_following', jsroute=True,
663 controller='journal', action='toggle_following', jsroute=True,
660 conditions={'method': ['POST']})
664 conditions={'method': ['POST']})
661
665
662 # FULL TEXT SEARCH
666 # FULL TEXT SEARCH
663 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
667 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
664 controller='search')
668 controller='search')
665 rmap.connect('search_repo_home', '/{repo_name}/search',
669 rmap.connect('search_repo_home', '/{repo_name}/search',
666 controller='search',
670 controller='search',
667 action='index',
671 action='index',
668 conditions={'function': check_repo},
672 conditions={'function': check_repo},
669 requirements=URL_NAME_REQUIREMENTS)
673 requirements=URL_NAME_REQUIREMENTS)
670
674
671 # FEEDS
675 # FEEDS
672 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
676 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
673 controller='feed', action='rss',
677 controller='feed', action='rss',
674 conditions={'function': check_repo},
678 conditions={'function': check_repo},
675 requirements=URL_NAME_REQUIREMENTS)
679 requirements=URL_NAME_REQUIREMENTS)
676
680
677 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
681 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
678 controller='feed', action='atom',
682 controller='feed', action='atom',
679 conditions={'function': check_repo},
683 conditions={'function': check_repo},
680 requirements=URL_NAME_REQUIREMENTS)
684 requirements=URL_NAME_REQUIREMENTS)
681
685
682 #==========================================================================
686 #==========================================================================
683 # REPOSITORY ROUTES
687 # REPOSITORY ROUTES
684 #==========================================================================
688 #==========================================================================
685
689
686 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
690 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
687 controller='admin/repos', action='repo_creating',
691 controller='admin/repos', action='repo_creating',
688 requirements=URL_NAME_REQUIREMENTS)
692 requirements=URL_NAME_REQUIREMENTS)
689 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
693 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
690 controller='admin/repos', action='repo_check',
694 controller='admin/repos', action='repo_check',
691 requirements=URL_NAME_REQUIREMENTS)
695 requirements=URL_NAME_REQUIREMENTS)
692
696
693 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
697 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
694 controller='summary', action='repo_stats',
698 controller='summary', action='repo_stats',
695 conditions={'function': check_repo},
699 conditions={'function': check_repo},
696 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
700 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
697
701
698 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
702 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
699 controller='summary', action='repo_refs_data', jsroute=True,
703 controller='summary', action='repo_refs_data', jsroute=True,
700 requirements=URL_NAME_REQUIREMENTS)
704 requirements=URL_NAME_REQUIREMENTS)
701 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
705 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
702 controller='summary', action='repo_refs_changelog_data',
706 controller='summary', action='repo_refs_changelog_data',
703 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
707 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
704 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
708 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
705 controller='summary', action='repo_default_reviewers_data',
709 controller='summary', action='repo_default_reviewers_data',
706 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
710 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
707
711
708 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
712 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
709 controller='changeset', revision='tip', jsroute=True,
713 controller='changeset', revision='tip', jsroute=True,
710 conditions={'function': check_repo},
714 conditions={'function': check_repo},
711 requirements=URL_NAME_REQUIREMENTS)
715 requirements=URL_NAME_REQUIREMENTS)
712 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
716 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
713 controller='changeset', revision='tip', action='changeset_children',
717 controller='changeset', revision='tip', action='changeset_children',
714 conditions={'function': check_repo},
718 conditions={'function': check_repo},
715 requirements=URL_NAME_REQUIREMENTS)
719 requirements=URL_NAME_REQUIREMENTS)
716 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
720 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
717 controller='changeset', revision='tip', action='changeset_parents',
721 controller='changeset', revision='tip', action='changeset_parents',
718 conditions={'function': check_repo},
722 conditions={'function': check_repo},
719 requirements=URL_NAME_REQUIREMENTS)
723 requirements=URL_NAME_REQUIREMENTS)
720
724
721 # repo edit options
725 # repo edit options
722 rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True,
726 rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True,
723 controller='admin/repos', action='edit',
727 controller='admin/repos', action='edit',
724 conditions={'method': ['GET'], 'function': check_repo},
728 conditions={'method': ['GET'], 'function': check_repo},
725 requirements=URL_NAME_REQUIREMENTS)
729 requirements=URL_NAME_REQUIREMENTS)
726
730
727 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
731 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
728 jsroute=True,
732 jsroute=True,
729 controller='admin/repos', action='edit_permissions',
733 controller='admin/repos', action='edit_permissions',
730 conditions={'method': ['GET'], 'function': check_repo},
734 conditions={'method': ['GET'], 'function': check_repo},
731 requirements=URL_NAME_REQUIREMENTS)
735 requirements=URL_NAME_REQUIREMENTS)
732 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
736 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
733 controller='admin/repos', action='edit_permissions_update',
737 controller='admin/repos', action='edit_permissions_update',
734 conditions={'method': ['PUT'], 'function': check_repo},
738 conditions={'method': ['PUT'], 'function': check_repo},
735 requirements=URL_NAME_REQUIREMENTS)
739 requirements=URL_NAME_REQUIREMENTS)
736
740
737 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
741 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
738 controller='admin/repos', action='edit_fields',
742 controller='admin/repos', action='edit_fields',
739 conditions={'method': ['GET'], 'function': check_repo},
743 conditions={'method': ['GET'], 'function': check_repo},
740 requirements=URL_NAME_REQUIREMENTS)
744 requirements=URL_NAME_REQUIREMENTS)
741 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
745 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
742 controller='admin/repos', action='create_repo_field',
746 controller='admin/repos', action='create_repo_field',
743 conditions={'method': ['PUT'], 'function': check_repo},
747 conditions={'method': ['PUT'], 'function': check_repo},
744 requirements=URL_NAME_REQUIREMENTS)
748 requirements=URL_NAME_REQUIREMENTS)
745 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
749 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
746 controller='admin/repos', action='delete_repo_field',
750 controller='admin/repos', action='delete_repo_field',
747 conditions={'method': ['DELETE'], 'function': check_repo},
751 conditions={'method': ['DELETE'], 'function': check_repo},
748 requirements=URL_NAME_REQUIREMENTS)
752 requirements=URL_NAME_REQUIREMENTS)
749
753
750 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
754 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
751 controller='admin/repos', action='edit_advanced',
755 controller='admin/repos', action='edit_advanced',
752 conditions={'method': ['GET'], 'function': check_repo},
756 conditions={'method': ['GET'], 'function': check_repo},
753 requirements=URL_NAME_REQUIREMENTS)
757 requirements=URL_NAME_REQUIREMENTS)
754
758
755 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
759 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
756 controller='admin/repos', action='edit_advanced_locking',
760 controller='admin/repos', action='edit_advanced_locking',
757 conditions={'method': ['PUT'], 'function': check_repo},
761 conditions={'method': ['PUT'], 'function': check_repo},
758 requirements=URL_NAME_REQUIREMENTS)
762 requirements=URL_NAME_REQUIREMENTS)
759 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
763 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
760 controller='admin/repos', action='toggle_locking',
764 controller='admin/repos', action='toggle_locking',
761 conditions={'method': ['GET'], 'function': check_repo},
765 conditions={'method': ['GET'], 'function': check_repo},
762 requirements=URL_NAME_REQUIREMENTS)
766 requirements=URL_NAME_REQUIREMENTS)
763
767
764 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
768 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
765 controller='admin/repos', action='edit_advanced_journal',
769 controller='admin/repos', action='edit_advanced_journal',
766 conditions={'method': ['PUT'], 'function': check_repo},
770 conditions={'method': ['PUT'], 'function': check_repo},
767 requirements=URL_NAME_REQUIREMENTS)
771 requirements=URL_NAME_REQUIREMENTS)
768
772
769 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
773 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
770 controller='admin/repos', action='edit_advanced_fork',
774 controller='admin/repos', action='edit_advanced_fork',
771 conditions={'method': ['PUT'], 'function': check_repo},
775 conditions={'method': ['PUT'], 'function': check_repo},
772 requirements=URL_NAME_REQUIREMENTS)
776 requirements=URL_NAME_REQUIREMENTS)
773
777
774 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
778 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
775 controller='admin/repos', action='edit_caches_form',
779 controller='admin/repos', action='edit_caches_form',
776 conditions={'method': ['GET'], 'function': check_repo},
780 conditions={'method': ['GET'], 'function': check_repo},
777 requirements=URL_NAME_REQUIREMENTS)
781 requirements=URL_NAME_REQUIREMENTS)
778 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
782 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
779 controller='admin/repos', action='edit_caches',
783 controller='admin/repos', action='edit_caches',
780 conditions={'method': ['PUT'], 'function': check_repo},
784 conditions={'method': ['PUT'], 'function': check_repo},
781 requirements=URL_NAME_REQUIREMENTS)
785 requirements=URL_NAME_REQUIREMENTS)
782
786
783 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
787 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
784 controller='admin/repos', action='edit_remote_form',
788 controller='admin/repos', action='edit_remote_form',
785 conditions={'method': ['GET'], 'function': check_repo},
789 conditions={'method': ['GET'], 'function': check_repo},
786 requirements=URL_NAME_REQUIREMENTS)
790 requirements=URL_NAME_REQUIREMENTS)
787 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
791 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
788 controller='admin/repos', action='edit_remote',
792 controller='admin/repos', action='edit_remote',
789 conditions={'method': ['PUT'], 'function': check_repo},
793 conditions={'method': ['PUT'], 'function': check_repo},
790 requirements=URL_NAME_REQUIREMENTS)
794 requirements=URL_NAME_REQUIREMENTS)
791
795
792 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
796 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
793 controller='admin/repos', action='edit_statistics_form',
797 controller='admin/repos', action='edit_statistics_form',
794 conditions={'method': ['GET'], 'function': check_repo},
798 conditions={'method': ['GET'], 'function': check_repo},
795 requirements=URL_NAME_REQUIREMENTS)
799 requirements=URL_NAME_REQUIREMENTS)
796 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
800 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
797 controller='admin/repos', action='edit_statistics',
801 controller='admin/repos', action='edit_statistics',
798 conditions={'method': ['PUT'], 'function': check_repo},
802 conditions={'method': ['PUT'], 'function': check_repo},
799 requirements=URL_NAME_REQUIREMENTS)
803 requirements=URL_NAME_REQUIREMENTS)
800 rmap.connect('repo_settings_issuetracker',
804 rmap.connect('repo_settings_issuetracker',
801 '/{repo_name}/settings/issue-tracker',
805 '/{repo_name}/settings/issue-tracker',
802 controller='admin/repos', action='repo_issuetracker',
806 controller='admin/repos', action='repo_issuetracker',
803 conditions={'method': ['GET'], 'function': check_repo},
807 conditions={'method': ['GET'], 'function': check_repo},
804 requirements=URL_NAME_REQUIREMENTS)
808 requirements=URL_NAME_REQUIREMENTS)
805 rmap.connect('repo_issuetracker_test',
809 rmap.connect('repo_issuetracker_test',
806 '/{repo_name}/settings/issue-tracker/test',
810 '/{repo_name}/settings/issue-tracker/test',
807 controller='admin/repos', action='repo_issuetracker_test',
811 controller='admin/repos', action='repo_issuetracker_test',
808 conditions={'method': ['POST'], 'function': check_repo},
812 conditions={'method': ['POST'], 'function': check_repo},
809 requirements=URL_NAME_REQUIREMENTS)
813 requirements=URL_NAME_REQUIREMENTS)
810 rmap.connect('repo_issuetracker_delete',
814 rmap.connect('repo_issuetracker_delete',
811 '/{repo_name}/settings/issue-tracker/delete',
815 '/{repo_name}/settings/issue-tracker/delete',
812 controller='admin/repos', action='repo_issuetracker_delete',
816 controller='admin/repos', action='repo_issuetracker_delete',
813 conditions={'method': ['DELETE'], 'function': check_repo},
817 conditions={'method': ['DELETE'], 'function': check_repo},
814 requirements=URL_NAME_REQUIREMENTS)
818 requirements=URL_NAME_REQUIREMENTS)
815 rmap.connect('repo_issuetracker_save',
819 rmap.connect('repo_issuetracker_save',
816 '/{repo_name}/settings/issue-tracker/save',
820 '/{repo_name}/settings/issue-tracker/save',
817 controller='admin/repos', action='repo_issuetracker_save',
821 controller='admin/repos', action='repo_issuetracker_save',
818 conditions={'method': ['POST'], 'function': check_repo},
822 conditions={'method': ['POST'], 'function': check_repo},
819 requirements=URL_NAME_REQUIREMENTS)
823 requirements=URL_NAME_REQUIREMENTS)
820 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
824 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
821 controller='admin/repos', action='repo_settings_vcs_update',
825 controller='admin/repos', action='repo_settings_vcs_update',
822 conditions={'method': ['POST'], 'function': check_repo},
826 conditions={'method': ['POST'], 'function': check_repo},
823 requirements=URL_NAME_REQUIREMENTS)
827 requirements=URL_NAME_REQUIREMENTS)
824 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
828 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
825 controller='admin/repos', action='repo_settings_vcs',
829 controller='admin/repos', action='repo_settings_vcs',
826 conditions={'method': ['GET'], 'function': check_repo},
830 conditions={'method': ['GET'], 'function': check_repo},
827 requirements=URL_NAME_REQUIREMENTS)
831 requirements=URL_NAME_REQUIREMENTS)
828 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
832 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
829 controller='admin/repos', action='repo_delete_svn_pattern',
833 controller='admin/repos', action='repo_delete_svn_pattern',
830 conditions={'method': ['DELETE'], 'function': check_repo},
834 conditions={'method': ['DELETE'], 'function': check_repo},
831 requirements=URL_NAME_REQUIREMENTS)
835 requirements=URL_NAME_REQUIREMENTS)
832 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
836 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
833 controller='admin/repos', action='repo_settings_pullrequest',
837 controller='admin/repos', action='repo_settings_pullrequest',
834 conditions={'method': ['GET', 'POST'], 'function': check_repo},
838 conditions={'method': ['GET', 'POST'], 'function': check_repo},
835 requirements=URL_NAME_REQUIREMENTS)
839 requirements=URL_NAME_REQUIREMENTS)
836
840
837 # still working url for backward compat.
841 # still working url for backward compat.
838 rmap.connect('raw_changeset_home_depraced',
842 rmap.connect('raw_changeset_home_depraced',
839 '/{repo_name}/raw-changeset/{revision}',
843 '/{repo_name}/raw-changeset/{revision}',
840 controller='changeset', action='changeset_raw',
844 controller='changeset', action='changeset_raw',
841 revision='tip', conditions={'function': check_repo},
845 revision='tip', conditions={'function': check_repo},
842 requirements=URL_NAME_REQUIREMENTS)
846 requirements=URL_NAME_REQUIREMENTS)
843
847
844 # new URLs
848 # new URLs
845 rmap.connect('changeset_raw_home',
849 rmap.connect('changeset_raw_home',
846 '/{repo_name}/changeset-diff/{revision}',
850 '/{repo_name}/changeset-diff/{revision}',
847 controller='changeset', action='changeset_raw',
851 controller='changeset', action='changeset_raw',
848 revision='tip', conditions={'function': check_repo},
852 revision='tip', conditions={'function': check_repo},
849 requirements=URL_NAME_REQUIREMENTS)
853 requirements=URL_NAME_REQUIREMENTS)
850
854
851 rmap.connect('changeset_patch_home',
855 rmap.connect('changeset_patch_home',
852 '/{repo_name}/changeset-patch/{revision}',
856 '/{repo_name}/changeset-patch/{revision}',
853 controller='changeset', action='changeset_patch',
857 controller='changeset', action='changeset_patch',
854 revision='tip', conditions={'function': check_repo},
858 revision='tip', conditions={'function': check_repo},
855 requirements=URL_NAME_REQUIREMENTS)
859 requirements=URL_NAME_REQUIREMENTS)
856
860
857 rmap.connect('changeset_download_home',
861 rmap.connect('changeset_download_home',
858 '/{repo_name}/changeset-download/{revision}',
862 '/{repo_name}/changeset-download/{revision}',
859 controller='changeset', action='changeset_download',
863 controller='changeset', action='changeset_download',
860 revision='tip', conditions={'function': check_repo},
864 revision='tip', conditions={'function': check_repo},
861 requirements=URL_NAME_REQUIREMENTS)
865 requirements=URL_NAME_REQUIREMENTS)
862
866
863 rmap.connect('changeset_comment',
867 rmap.connect('changeset_comment',
864 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
868 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
865 controller='changeset', revision='tip', action='comment',
869 controller='changeset', revision='tip', action='comment',
866 conditions={'function': check_repo},
870 conditions={'function': check_repo},
867 requirements=URL_NAME_REQUIREMENTS)
871 requirements=URL_NAME_REQUIREMENTS)
868
872
869 rmap.connect('changeset_comment_preview',
873 rmap.connect('changeset_comment_preview',
870 '/{repo_name}/changeset/comment/preview', jsroute=True,
874 '/{repo_name}/changeset/comment/preview', jsroute=True,
871 controller='changeset', action='preview_comment',
875 controller='changeset', action='preview_comment',
872 conditions={'function': check_repo, 'method': ['POST']},
876 conditions={'function': check_repo, 'method': ['POST']},
873 requirements=URL_NAME_REQUIREMENTS)
877 requirements=URL_NAME_REQUIREMENTS)
874
878
875 rmap.connect('changeset_comment_delete',
879 rmap.connect('changeset_comment_delete',
876 '/{repo_name}/changeset/comment/{comment_id}/delete',
880 '/{repo_name}/changeset/comment/{comment_id}/delete',
877 controller='changeset', action='delete_comment',
881 controller='changeset', action='delete_comment',
878 conditions={'function': check_repo, 'method': ['DELETE']},
882 conditions={'function': check_repo, 'method': ['DELETE']},
879 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
883 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
880
884
881 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
885 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
882 controller='changeset', action='changeset_info',
886 controller='changeset', action='changeset_info',
883 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
887 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
884
888
885 rmap.connect('compare_home',
889 rmap.connect('compare_home',
886 '/{repo_name}/compare',
890 '/{repo_name}/compare',
887 controller='compare', action='index',
891 controller='compare', action='index',
888 conditions={'function': check_repo},
892 conditions={'function': check_repo},
889 requirements=URL_NAME_REQUIREMENTS)
893 requirements=URL_NAME_REQUIREMENTS)
890
894
891 rmap.connect('compare_url',
895 rmap.connect('compare_url',
892 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
896 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
893 controller='compare', action='compare',
897 controller='compare', action='compare',
894 conditions={'function': check_repo},
898 conditions={'function': check_repo},
895 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
899 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
896
900
897 rmap.connect('pullrequest_home',
901 rmap.connect('pullrequest_home',
898 '/{repo_name}/pull-request/new', controller='pullrequests',
902 '/{repo_name}/pull-request/new', controller='pullrequests',
899 action='index', conditions={'function': check_repo,
903 action='index', conditions={'function': check_repo,
900 'method': ['GET']},
904 'method': ['GET']},
901 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
905 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
902
906
903 rmap.connect('pullrequest',
907 rmap.connect('pullrequest',
904 '/{repo_name}/pull-request/new', controller='pullrequests',
908 '/{repo_name}/pull-request/new', controller='pullrequests',
905 action='create', conditions={'function': check_repo,
909 action='create', conditions={'function': check_repo,
906 'method': ['POST']},
910 'method': ['POST']},
907 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
911 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
908
912
909 rmap.connect('pullrequest_repo_refs',
913 rmap.connect('pullrequest_repo_refs',
910 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
914 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
911 controller='pullrequests',
915 controller='pullrequests',
912 action='get_repo_refs',
916 action='get_repo_refs',
913 conditions={'function': check_repo, 'method': ['GET']},
917 conditions={'function': check_repo, 'method': ['GET']},
914 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
918 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
915
919
916 rmap.connect('pullrequest_repo_destinations',
920 rmap.connect('pullrequest_repo_destinations',
917 '/{repo_name}/pull-request/repo-destinations',
921 '/{repo_name}/pull-request/repo-destinations',
918 controller='pullrequests',
922 controller='pullrequests',
919 action='get_repo_destinations',
923 action='get_repo_destinations',
920 conditions={'function': check_repo, 'method': ['GET']},
924 conditions={'function': check_repo, 'method': ['GET']},
921 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
925 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
922
926
923 rmap.connect('pullrequest_show',
927 rmap.connect('pullrequest_show',
924 '/{repo_name}/pull-request/{pull_request_id}',
928 '/{repo_name}/pull-request/{pull_request_id}',
925 controller='pullrequests',
929 controller='pullrequests',
926 action='show', conditions={'function': check_repo,
930 action='show', conditions={'function': check_repo,
927 'method': ['GET']},
931 'method': ['GET']},
928 requirements=URL_NAME_REQUIREMENTS)
932 requirements=URL_NAME_REQUIREMENTS)
929
933
930 rmap.connect('pullrequest_update',
934 rmap.connect('pullrequest_update',
931 '/{repo_name}/pull-request/{pull_request_id}',
935 '/{repo_name}/pull-request/{pull_request_id}',
932 controller='pullrequests',
936 controller='pullrequests',
933 action='update', conditions={'function': check_repo,
937 action='update', conditions={'function': check_repo,
934 'method': ['PUT']},
938 'method': ['PUT']},
935 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
939 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
936
940
937 rmap.connect('pullrequest_merge',
941 rmap.connect('pullrequest_merge',
938 '/{repo_name}/pull-request/{pull_request_id}',
942 '/{repo_name}/pull-request/{pull_request_id}',
939 controller='pullrequests',
943 controller='pullrequests',
940 action='merge', conditions={'function': check_repo,
944 action='merge', conditions={'function': check_repo,
941 'method': ['POST']},
945 'method': ['POST']},
942 requirements=URL_NAME_REQUIREMENTS)
946 requirements=URL_NAME_REQUIREMENTS)
943
947
944 rmap.connect('pullrequest_delete',
948 rmap.connect('pullrequest_delete',
945 '/{repo_name}/pull-request/{pull_request_id}',
949 '/{repo_name}/pull-request/{pull_request_id}',
946 controller='pullrequests',
950 controller='pullrequests',
947 action='delete', conditions={'function': check_repo,
951 action='delete', conditions={'function': check_repo,
948 'method': ['DELETE']},
952 'method': ['DELETE']},
949 requirements=URL_NAME_REQUIREMENTS)
953 requirements=URL_NAME_REQUIREMENTS)
950
954
951 rmap.connect('pullrequest_show_all',
955 rmap.connect('pullrequest_show_all',
952 '/{repo_name}/pull-request',
956 '/{repo_name}/pull-request',
953 controller='pullrequests',
957 controller='pullrequests',
954 action='show_all', conditions={'function': check_repo,
958 action='show_all', conditions={'function': check_repo,
955 'method': ['GET']},
959 'method': ['GET']},
956 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
960 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
957
961
958 rmap.connect('pullrequest_comment',
962 rmap.connect('pullrequest_comment',
959 '/{repo_name}/pull-request-comment/{pull_request_id}',
963 '/{repo_name}/pull-request-comment/{pull_request_id}',
960 controller='pullrequests',
964 controller='pullrequests',
961 action='comment', conditions={'function': check_repo,
965 action='comment', conditions={'function': check_repo,
962 'method': ['POST']},
966 'method': ['POST']},
963 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
967 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
964
968
965 rmap.connect('pullrequest_comment_delete',
969 rmap.connect('pullrequest_comment_delete',
966 '/{repo_name}/pull-request-comment/{comment_id}/delete',
970 '/{repo_name}/pull-request-comment/{comment_id}/delete',
967 controller='pullrequests', action='delete_comment',
971 controller='pullrequests', action='delete_comment',
968 conditions={'function': check_repo, 'method': ['DELETE']},
972 conditions={'function': check_repo, 'method': ['DELETE']},
969 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
973 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
970
974
971 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
975 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
972 controller='summary', conditions={'function': check_repo},
976 controller='summary', conditions={'function': check_repo},
973 requirements=URL_NAME_REQUIREMENTS)
977 requirements=URL_NAME_REQUIREMENTS)
974
978
975 rmap.connect('branches_home', '/{repo_name}/branches',
979 rmap.connect('branches_home', '/{repo_name}/branches',
976 controller='branches', conditions={'function': check_repo},
980 controller='branches', conditions={'function': check_repo},
977 requirements=URL_NAME_REQUIREMENTS)
981 requirements=URL_NAME_REQUIREMENTS)
978
982
979 rmap.connect('tags_home', '/{repo_name}/tags',
983 rmap.connect('tags_home', '/{repo_name}/tags',
980 controller='tags', conditions={'function': check_repo},
984 controller='tags', conditions={'function': check_repo},
981 requirements=URL_NAME_REQUIREMENTS)
985 requirements=URL_NAME_REQUIREMENTS)
982
986
983 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
987 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
984 controller='bookmarks', conditions={'function': check_repo},
988 controller='bookmarks', conditions={'function': check_repo},
985 requirements=URL_NAME_REQUIREMENTS)
989 requirements=URL_NAME_REQUIREMENTS)
986
990
987 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
991 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
988 controller='changelog', conditions={'function': check_repo},
992 controller='changelog', conditions={'function': check_repo},
989 requirements=URL_NAME_REQUIREMENTS)
993 requirements=URL_NAME_REQUIREMENTS)
990
994
991 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
995 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
992 controller='changelog', action='changelog_summary',
996 controller='changelog', action='changelog_summary',
993 conditions={'function': check_repo},
997 conditions={'function': check_repo},
994 requirements=URL_NAME_REQUIREMENTS)
998 requirements=URL_NAME_REQUIREMENTS)
995
999
996 rmap.connect('changelog_file_home',
1000 rmap.connect('changelog_file_home',
997 '/{repo_name}/changelog/{revision}/{f_path}',
1001 '/{repo_name}/changelog/{revision}/{f_path}',
998 controller='changelog', f_path=None,
1002 controller='changelog', f_path=None,
999 conditions={'function': check_repo},
1003 conditions={'function': check_repo},
1000 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1004 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1001
1005
1002 rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
1006 rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
1003 controller='changelog', action='changelog_details',
1007 controller='changelog', action='changelog_details',
1004 conditions={'function': check_repo},
1008 conditions={'function': check_repo},
1005 requirements=URL_NAME_REQUIREMENTS)
1009 requirements=URL_NAME_REQUIREMENTS)
1006
1010
1007 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
1011 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
1008 controller='files', revision='tip', f_path='',
1012 controller='files', revision='tip', f_path='',
1009 conditions={'function': check_repo},
1013 conditions={'function': check_repo},
1010 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1014 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1011
1015
1012 rmap.connect('files_home_simple_catchrev',
1016 rmap.connect('files_home_simple_catchrev',
1013 '/{repo_name}/files/{revision}',
1017 '/{repo_name}/files/{revision}',
1014 controller='files', revision='tip', f_path='',
1018 controller='files', revision='tip', f_path='',
1015 conditions={'function': check_repo},
1019 conditions={'function': check_repo},
1016 requirements=URL_NAME_REQUIREMENTS)
1020 requirements=URL_NAME_REQUIREMENTS)
1017
1021
1018 rmap.connect('files_home_simple_catchall',
1022 rmap.connect('files_home_simple_catchall',
1019 '/{repo_name}/files',
1023 '/{repo_name}/files',
1020 controller='files', revision='tip', f_path='',
1024 controller='files', revision='tip', f_path='',
1021 conditions={'function': check_repo},
1025 conditions={'function': check_repo},
1022 requirements=URL_NAME_REQUIREMENTS)
1026 requirements=URL_NAME_REQUIREMENTS)
1023
1027
1024 rmap.connect('files_history_home',
1028 rmap.connect('files_history_home',
1025 '/{repo_name}/history/{revision}/{f_path}',
1029 '/{repo_name}/history/{revision}/{f_path}',
1026 controller='files', action='history', revision='tip', f_path='',
1030 controller='files', action='history', revision='tip', f_path='',
1027 conditions={'function': check_repo},
1031 conditions={'function': check_repo},
1028 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1032 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1029
1033
1030 rmap.connect('files_authors_home',
1034 rmap.connect('files_authors_home',
1031 '/{repo_name}/authors/{revision}/{f_path}',
1035 '/{repo_name}/authors/{revision}/{f_path}',
1032 controller='files', action='authors', revision='tip', f_path='',
1036 controller='files', action='authors', revision='tip', f_path='',
1033 conditions={'function': check_repo},
1037 conditions={'function': check_repo},
1034 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1038 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1035
1039
1036 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
1040 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
1037 controller='files', action='diff', f_path='',
1041 controller='files', action='diff', f_path='',
1038 conditions={'function': check_repo},
1042 conditions={'function': check_repo},
1039 requirements=URL_NAME_REQUIREMENTS)
1043 requirements=URL_NAME_REQUIREMENTS)
1040
1044
1041 rmap.connect('files_diff_2way_home',
1045 rmap.connect('files_diff_2way_home',
1042 '/{repo_name}/diff-2way/{f_path}',
1046 '/{repo_name}/diff-2way/{f_path}',
1043 controller='files', action='diff_2way', f_path='',
1047 controller='files', action='diff_2way', f_path='',
1044 conditions={'function': check_repo},
1048 conditions={'function': check_repo},
1045 requirements=URL_NAME_REQUIREMENTS)
1049 requirements=URL_NAME_REQUIREMENTS)
1046
1050
1047 rmap.connect('files_rawfile_home',
1051 rmap.connect('files_rawfile_home',
1048 '/{repo_name}/rawfile/{revision}/{f_path}',
1052 '/{repo_name}/rawfile/{revision}/{f_path}',
1049 controller='files', action='rawfile', revision='tip',
1053 controller='files', action='rawfile', revision='tip',
1050 f_path='', conditions={'function': check_repo},
1054 f_path='', conditions={'function': check_repo},
1051 requirements=URL_NAME_REQUIREMENTS)
1055 requirements=URL_NAME_REQUIREMENTS)
1052
1056
1053 rmap.connect('files_raw_home',
1057 rmap.connect('files_raw_home',
1054 '/{repo_name}/raw/{revision}/{f_path}',
1058 '/{repo_name}/raw/{revision}/{f_path}',
1055 controller='files', action='raw', revision='tip', f_path='',
1059 controller='files', action='raw', revision='tip', f_path='',
1056 conditions={'function': check_repo},
1060 conditions={'function': check_repo},
1057 requirements=URL_NAME_REQUIREMENTS)
1061 requirements=URL_NAME_REQUIREMENTS)
1058
1062
1059 rmap.connect('files_render_home',
1063 rmap.connect('files_render_home',
1060 '/{repo_name}/render/{revision}/{f_path}',
1064 '/{repo_name}/render/{revision}/{f_path}',
1061 controller='files', action='index', revision='tip', f_path='',
1065 controller='files', action='index', revision='tip', f_path='',
1062 rendered=True, conditions={'function': check_repo},
1066 rendered=True, conditions={'function': check_repo},
1063 requirements=URL_NAME_REQUIREMENTS)
1067 requirements=URL_NAME_REQUIREMENTS)
1064
1068
1065 rmap.connect('files_annotate_home',
1069 rmap.connect('files_annotate_home',
1066 '/{repo_name}/annotate/{revision}/{f_path}',
1070 '/{repo_name}/annotate/{revision}/{f_path}',
1067 controller='files', action='index', revision='tip',
1071 controller='files', action='index', revision='tip',
1068 f_path='', annotate=True, conditions={'function': check_repo},
1072 f_path='', annotate=True, conditions={'function': check_repo},
1069 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1073 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1070
1074
1071 rmap.connect('files_edit',
1075 rmap.connect('files_edit',
1072 '/{repo_name}/edit/{revision}/{f_path}',
1076 '/{repo_name}/edit/{revision}/{f_path}',
1073 controller='files', action='edit', revision='tip',
1077 controller='files', action='edit', revision='tip',
1074 f_path='',
1078 f_path='',
1075 conditions={'function': check_repo, 'method': ['POST']},
1079 conditions={'function': check_repo, 'method': ['POST']},
1076 requirements=URL_NAME_REQUIREMENTS)
1080 requirements=URL_NAME_REQUIREMENTS)
1077
1081
1078 rmap.connect('files_edit_home',
1082 rmap.connect('files_edit_home',
1079 '/{repo_name}/edit/{revision}/{f_path}',
1083 '/{repo_name}/edit/{revision}/{f_path}',
1080 controller='files', action='edit_home', revision='tip',
1084 controller='files', action='edit_home', revision='tip',
1081 f_path='', conditions={'function': check_repo},
1085 f_path='', conditions={'function': check_repo},
1082 requirements=URL_NAME_REQUIREMENTS)
1086 requirements=URL_NAME_REQUIREMENTS)
1083
1087
1084 rmap.connect('files_add',
1088 rmap.connect('files_add',
1085 '/{repo_name}/add/{revision}/{f_path}',
1089 '/{repo_name}/add/{revision}/{f_path}',
1086 controller='files', action='add', revision='tip',
1090 controller='files', action='add', revision='tip',
1087 f_path='',
1091 f_path='',
1088 conditions={'function': check_repo, 'method': ['POST']},
1092 conditions={'function': check_repo, 'method': ['POST']},
1089 requirements=URL_NAME_REQUIREMENTS)
1093 requirements=URL_NAME_REQUIREMENTS)
1090
1094
1091 rmap.connect('files_add_home',
1095 rmap.connect('files_add_home',
1092 '/{repo_name}/add/{revision}/{f_path}',
1096 '/{repo_name}/add/{revision}/{f_path}',
1093 controller='files', action='add_home', revision='tip',
1097 controller='files', action='add_home', revision='tip',
1094 f_path='', conditions={'function': check_repo},
1098 f_path='', conditions={'function': check_repo},
1095 requirements=URL_NAME_REQUIREMENTS)
1099 requirements=URL_NAME_REQUIREMENTS)
1096
1100
1097 rmap.connect('files_delete',
1101 rmap.connect('files_delete',
1098 '/{repo_name}/delete/{revision}/{f_path}',
1102 '/{repo_name}/delete/{revision}/{f_path}',
1099 controller='files', action='delete', revision='tip',
1103 controller='files', action='delete', revision='tip',
1100 f_path='',
1104 f_path='',
1101 conditions={'function': check_repo, 'method': ['POST']},
1105 conditions={'function': check_repo, 'method': ['POST']},
1102 requirements=URL_NAME_REQUIREMENTS)
1106 requirements=URL_NAME_REQUIREMENTS)
1103
1107
1104 rmap.connect('files_delete_home',
1108 rmap.connect('files_delete_home',
1105 '/{repo_name}/delete/{revision}/{f_path}',
1109 '/{repo_name}/delete/{revision}/{f_path}',
1106 controller='files', action='delete_home', revision='tip',
1110 controller='files', action='delete_home', revision='tip',
1107 f_path='', conditions={'function': check_repo},
1111 f_path='', conditions={'function': check_repo},
1108 requirements=URL_NAME_REQUIREMENTS)
1112 requirements=URL_NAME_REQUIREMENTS)
1109
1113
1110 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1114 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1111 controller='files', action='archivefile',
1115 controller='files', action='archivefile',
1112 conditions={'function': check_repo},
1116 conditions={'function': check_repo},
1113 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1117 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1114
1118
1115 rmap.connect('files_nodelist_home',
1119 rmap.connect('files_nodelist_home',
1116 '/{repo_name}/nodelist/{revision}/{f_path}',
1120 '/{repo_name}/nodelist/{revision}/{f_path}',
1117 controller='files', action='nodelist',
1121 controller='files', action='nodelist',
1118 conditions={'function': check_repo},
1122 conditions={'function': check_repo},
1119 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1123 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1120
1124
1121 rmap.connect('files_nodetree_full',
1125 rmap.connect('files_nodetree_full',
1122 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1126 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1123 controller='files', action='nodetree_full',
1127 controller='files', action='nodetree_full',
1124 conditions={'function': check_repo},
1128 conditions={'function': check_repo},
1125 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1129 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1126
1130
1127 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1131 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1128 controller='forks', action='fork_create',
1132 controller='forks', action='fork_create',
1129 conditions={'function': check_repo, 'method': ['POST']},
1133 conditions={'function': check_repo, 'method': ['POST']},
1130 requirements=URL_NAME_REQUIREMENTS)
1134 requirements=URL_NAME_REQUIREMENTS)
1131
1135
1132 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1136 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1133 controller='forks', action='fork',
1137 controller='forks', action='fork',
1134 conditions={'function': check_repo},
1138 conditions={'function': check_repo},
1135 requirements=URL_NAME_REQUIREMENTS)
1139 requirements=URL_NAME_REQUIREMENTS)
1136
1140
1137 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1141 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1138 controller='forks', action='forks',
1142 controller='forks', action='forks',
1139 conditions={'function': check_repo},
1143 conditions={'function': check_repo},
1140 requirements=URL_NAME_REQUIREMENTS)
1144 requirements=URL_NAME_REQUIREMENTS)
1141
1145
1142 rmap.connect('repo_followers_home', '/{repo_name}/followers',
1146 rmap.connect('repo_followers_home', '/{repo_name}/followers',
1143 controller='followers', action='followers',
1147 controller='followers', action='followers',
1144 conditions={'function': check_repo},
1148 conditions={'function': check_repo},
1145 requirements=URL_NAME_REQUIREMENTS)
1149 requirements=URL_NAME_REQUIREMENTS)
1146
1150
1147 # must be here for proper group/repo catching pattern
1151 # must be here for proper group/repo catching pattern
1148 _connect_with_slash(
1152 _connect_with_slash(
1149 rmap, 'repo_group_home', '/{group_name}',
1153 rmap, 'repo_group_home', '/{group_name}',
1150 controller='home', action='index_repo_group',
1154 controller='home', action='index_repo_group',
1151 conditions={'function': check_group},
1155 conditions={'function': check_group},
1152 requirements=URL_NAME_REQUIREMENTS)
1156 requirements=URL_NAME_REQUIREMENTS)
1153
1157
1154 # catch all, at the end
1158 # catch all, at the end
1155 _connect_with_slash(
1159 _connect_with_slash(
1156 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1160 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1157 controller='summary', action='index',
1161 controller='summary', action='index',
1158 conditions={'function': check_repo},
1162 conditions={'function': check_repo},
1159 requirements=URL_NAME_REQUIREMENTS)
1163 requirements=URL_NAME_REQUIREMENTS)
1160
1164
1161 return rmap
1165 return rmap
1162
1166
1163
1167
1164 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1168 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1165 """
1169 """
1166 Connect a route with an optional trailing slash in `path`.
1170 Connect a route with an optional trailing slash in `path`.
1167 """
1171 """
1168 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1172 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1169 mapper.connect(name, path, *args, **kwargs)
1173 mapper.connect(name, path, *args, **kwargs)
@@ -1,432 +1,467 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2013-2017 RhodeCode GmbH
3 # Copyright (C) 2013-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 """
22 """
23 my account controller for RhodeCode admin
23 my account controller for RhodeCode admin
24 """
24 """
25
25
26 import logging
26 import logging
27 import datetime
27
28
28 import formencode
29 import formencode
29 from formencode import htmlfill
30 from formencode import htmlfill
31 from pyramid.threadlocal import get_current_registry
30 from pylons import request, tmpl_context as c, url, session
32 from pylons import request, tmpl_context as c, url, session
31 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
32 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
33 from sqlalchemy.orm import joinedload
35 from sqlalchemy.orm import joinedload
36 from webob.exc import HTTPBadGateway
34
37
35 from rhodecode import forms
38 from rhodecode import forms
36 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
37 from rhodecode.lib import auth
40 from rhodecode.lib import auth
38 from rhodecode.lib.auth import (
41 from rhodecode.lib.auth import (
39 LoginRequired, NotAnonymous, AuthUser, generate_auth_token)
42 LoginRequired, NotAnonymous, AuthUser, generate_auth_token)
40 from rhodecode.lib.base import BaseController, render
43 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.utils import jsonify
44 from rhodecode.lib.utils import jsonify
42 from rhodecode.lib.utils2 import safe_int, md5, str2bool
45 from rhodecode.lib.utils2 import safe_int, md5, str2bool
43 from rhodecode.lib.ext_json import json
46 from rhodecode.lib.ext_json import json
47 from rhodecode.lib.channelstream import channelstream_request, \
48 ChannelstreamException
44
49
45 from rhodecode.model.validation_schema.schemas import user_schema
50 from rhodecode.model.validation_schema.schemas import user_schema
46 from rhodecode.model.db import (
51 from rhodecode.model.db import (
47 Repository, PullRequest, UserEmailMap, User, UserFollowing)
52 Repository, PullRequest, UserEmailMap, User, UserFollowing)
48 from rhodecode.model.forms import UserForm
53 from rhodecode.model.forms import UserForm
49 from rhodecode.model.scm import RepoList
54 from rhodecode.model.scm import RepoList
50 from rhodecode.model.user import UserModel
55 from rhodecode.model.user import UserModel
51 from rhodecode.model.repo import RepoModel
56 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.auth_token import AuthTokenModel
57 from rhodecode.model.auth_token import AuthTokenModel
53 from rhodecode.model.meta import Session
58 from rhodecode.model.meta import Session
54 from rhodecode.model.pull_request import PullRequestModel
59 from rhodecode.model.pull_request import PullRequestModel
55 from rhodecode.model.comment import ChangesetCommentsModel
60 from rhodecode.model.comment import ChangesetCommentsModel
56
61
57 log = logging.getLogger(__name__)
62 log = logging.getLogger(__name__)
58
63
59
64
60 class MyAccountController(BaseController):
65 class MyAccountController(BaseController):
61 """REST Controller styled on the Atom Publishing Protocol"""
66 """REST Controller styled on the Atom Publishing Protocol"""
62 # To properly map this controller, ensure your config/routing.py
67 # To properly map this controller, ensure your config/routing.py
63 # file has a resource setup:
68 # file has a resource setup:
64 # map.resource('setting', 'settings', controller='admin/settings',
69 # map.resource('setting', 'settings', controller='admin/settings',
65 # path_prefix='/admin', name_prefix='admin_')
70 # path_prefix='/admin', name_prefix='admin_')
66
71
67 @LoginRequired()
72 @LoginRequired()
68 @NotAnonymous()
73 @NotAnonymous()
69 def __before__(self):
74 def __before__(self):
70 super(MyAccountController, self).__before__()
75 super(MyAccountController, self).__before__()
71
76
72 def __load_data(self):
77 def __load_data(self):
73 c.user = User.get(c.rhodecode_user.user_id)
78 c.user = User.get(c.rhodecode_user.user_id)
74 if c.user.username == User.DEFAULT_USER:
79 if c.user.username == User.DEFAULT_USER:
75 h.flash(_("You can't edit this user since it's"
80 h.flash(_("You can't edit this user since it's"
76 " crucial for entire application"), category='warning')
81 " crucial for entire application"), category='warning')
77 return redirect(url('users'))
82 return redirect(url('users'))
78
83
79 def _load_my_repos_data(self, watched=False):
84 def _load_my_repos_data(self, watched=False):
80 if watched:
85 if watched:
81 admin = False
86 admin = False
82 follows_repos = Session().query(UserFollowing)\
87 follows_repos = Session().query(UserFollowing)\
83 .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
88 .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
84 .options(joinedload(UserFollowing.follows_repository))\
89 .options(joinedload(UserFollowing.follows_repository))\
85 .all()
90 .all()
86 repo_list = [x.follows_repository for x in follows_repos]
91 repo_list = [x.follows_repository for x in follows_repos]
87 else:
92 else:
88 admin = True
93 admin = True
89 repo_list = Repository.get_all_repos(
94 repo_list = Repository.get_all_repos(
90 user_id=c.rhodecode_user.user_id)
95 user_id=c.rhodecode_user.user_id)
91 repo_list = RepoList(repo_list, perm_set=[
96 repo_list = RepoList(repo_list, perm_set=[
92 'repository.read', 'repository.write', 'repository.admin'])
97 'repository.read', 'repository.write', 'repository.admin'])
93
98
94 repos_data = RepoModel().get_repos_as_dict(
99 repos_data = RepoModel().get_repos_as_dict(
95 repo_list=repo_list, admin=admin)
100 repo_list=repo_list, admin=admin)
96 # json used to render the grid
101 # json used to render the grid
97 return json.dumps(repos_data)
102 return json.dumps(repos_data)
98
103
99 @auth.CSRFRequired()
104 @auth.CSRFRequired()
100 def my_account_update(self):
105 def my_account_update(self):
101 """
106 """
102 POST /_admin/my_account Updates info of my account
107 POST /_admin/my_account Updates info of my account
103 """
108 """
104 # url('my_account')
109 # url('my_account')
105 c.active = 'profile_edit'
110 c.active = 'profile_edit'
106 self.__load_data()
111 self.__load_data()
107 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
112 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
108 ip_addr=self.ip_addr)
113 ip_addr=self.ip_addr)
109 c.extern_type = c.user.extern_type
114 c.extern_type = c.user.extern_type
110 c.extern_name = c.user.extern_name
115 c.extern_name = c.user.extern_name
111
116
112 defaults = c.user.get_dict()
117 defaults = c.user.get_dict()
113 update = False
118 update = False
114 _form = UserForm(edit=True,
119 _form = UserForm(edit=True,
115 old_data={'user_id': c.rhodecode_user.user_id,
120 old_data={'user_id': c.rhodecode_user.user_id,
116 'email': c.rhodecode_user.email})()
121 'email': c.rhodecode_user.email})()
117 form_result = {}
122 form_result = {}
118 try:
123 try:
119 post_data = dict(request.POST)
124 post_data = dict(request.POST)
120 post_data['new_password'] = ''
125 post_data['new_password'] = ''
121 post_data['password_confirmation'] = ''
126 post_data['password_confirmation'] = ''
122 form_result = _form.to_python(post_data)
127 form_result = _form.to_python(post_data)
123 # skip updating those attrs for my account
128 # skip updating those attrs for my account
124 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
129 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
125 'new_password', 'password_confirmation']
130 'new_password', 'password_confirmation']
126 # TODO: plugin should define if username can be updated
131 # TODO: plugin should define if username can be updated
127 if c.extern_type != "rhodecode":
132 if c.extern_type != "rhodecode":
128 # forbid updating username for external accounts
133 # forbid updating username for external accounts
129 skip_attrs.append('username')
134 skip_attrs.append('username')
130
135
131 UserModel().update_user(
136 UserModel().update_user(
132 c.rhodecode_user.user_id, skip_attrs=skip_attrs, **form_result)
137 c.rhodecode_user.user_id, skip_attrs=skip_attrs, **form_result)
133 h.flash(_('Your account was updated successfully'),
138 h.flash(_('Your account was updated successfully'),
134 category='success')
139 category='success')
135 Session().commit()
140 Session().commit()
136 update = True
141 update = True
137
142
138 except formencode.Invalid as errors:
143 except formencode.Invalid as errors:
139 return htmlfill.render(
144 return htmlfill.render(
140 render('admin/my_account/my_account.html'),
145 render('admin/my_account/my_account.html'),
141 defaults=errors.value,
146 defaults=errors.value,
142 errors=errors.error_dict or {},
147 errors=errors.error_dict or {},
143 prefix_error=False,
148 prefix_error=False,
144 encoding="UTF-8",
149 encoding="UTF-8",
145 force_defaults=False)
150 force_defaults=False)
146 except Exception:
151 except Exception:
147 log.exception("Exception updating user")
152 log.exception("Exception updating user")
148 h.flash(_('Error occurred during update of user %s')
153 h.flash(_('Error occurred during update of user %s')
149 % form_result.get('username'), category='error')
154 % form_result.get('username'), category='error')
150
155
151 if update:
156 if update:
152 return redirect('my_account')
157 return redirect('my_account')
153
158
154 return htmlfill.render(
159 return htmlfill.render(
155 render('admin/my_account/my_account.html'),
160 render('admin/my_account/my_account.html'),
156 defaults=defaults,
161 defaults=defaults,
157 encoding="UTF-8",
162 encoding="UTF-8",
158 force_defaults=False
163 force_defaults=False
159 )
164 )
160
165
161 def my_account(self):
166 def my_account(self):
162 """
167 """
163 GET /_admin/my_account Displays info about my account
168 GET /_admin/my_account Displays info about my account
164 """
169 """
165 # url('my_account')
170 # url('my_account')
166 c.active = 'profile'
171 c.active = 'profile'
167 self.__load_data()
172 self.__load_data()
168
173
169 defaults = c.user.get_dict()
174 defaults = c.user.get_dict()
170 return htmlfill.render(
175 return htmlfill.render(
171 render('admin/my_account/my_account.html'),
176 render('admin/my_account/my_account.html'),
172 defaults=defaults, encoding="UTF-8", force_defaults=False)
177 defaults=defaults, encoding="UTF-8", force_defaults=False)
173
178
174 def my_account_edit(self):
179 def my_account_edit(self):
175 """
180 """
176 GET /_admin/my_account/edit Displays edit form of my account
181 GET /_admin/my_account/edit Displays edit form of my account
177 """
182 """
178 c.active = 'profile_edit'
183 c.active = 'profile_edit'
179 self.__load_data()
184 self.__load_data()
180 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
185 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
181 ip_addr=self.ip_addr)
186 ip_addr=self.ip_addr)
182 c.extern_type = c.user.extern_type
187 c.extern_type = c.user.extern_type
183 c.extern_name = c.user.extern_name
188 c.extern_name = c.user.extern_name
184
189
185 defaults = c.user.get_dict()
190 defaults = c.user.get_dict()
186 return htmlfill.render(
191 return htmlfill.render(
187 render('admin/my_account/my_account.html'),
192 render('admin/my_account/my_account.html'),
188 defaults=defaults,
193 defaults=defaults,
189 encoding="UTF-8",
194 encoding="UTF-8",
190 force_defaults=False
195 force_defaults=False
191 )
196 )
192
197
193 @auth.CSRFRequired(except_methods=['GET'])
198 @auth.CSRFRequired(except_methods=['GET'])
194 def my_account_password(self):
199 def my_account_password(self):
195 c.active = 'password'
200 c.active = 'password'
196 self.__load_data()
201 self.__load_data()
197
202
198 schema = user_schema.ChangePasswordSchema().bind(
203 schema = user_schema.ChangePasswordSchema().bind(
199 username=c.rhodecode_user.username)
204 username=c.rhodecode_user.username)
200
205
201 form = forms.Form(schema,
206 form = forms.Form(schema,
202 buttons=(forms.buttons.save, forms.buttons.reset))
207 buttons=(forms.buttons.save, forms.buttons.reset))
203
208
204 if request.method == 'POST':
209 if request.method == 'POST':
205 controls = request.POST.items()
210 controls = request.POST.items()
206 try:
211 try:
207 valid_data = form.validate(controls)
212 valid_data = form.validate(controls)
208 UserModel().update_user(c.rhodecode_user.user_id, **valid_data)
213 UserModel().update_user(c.rhodecode_user.user_id, **valid_data)
209 instance = c.rhodecode_user.get_instance()
214 instance = c.rhodecode_user.get_instance()
210 instance.update_userdata(force_password_change=False)
215 instance.update_userdata(force_password_change=False)
211 Session().commit()
216 Session().commit()
212 except forms.ValidationFailure as e:
217 except forms.ValidationFailure as e:
213 request.session.flash(
218 request.session.flash(
214 _('Error occurred during update of user password'),
219 _('Error occurred during update of user password'),
215 queue='error')
220 queue='error')
216 form = e
221 form = e
217 except Exception:
222 except Exception:
218 log.exception("Exception updating password")
223 log.exception("Exception updating password")
219 request.session.flash(
224 request.session.flash(
220 _('Error occurred during update of user password'),
225 _('Error occurred during update of user password'),
221 queue='error')
226 queue='error')
222 else:
227 else:
223 session.setdefault('rhodecode_user', {}).update(
228 session.setdefault('rhodecode_user', {}).update(
224 {'password': md5(instance.password)})
229 {'password': md5(instance.password)})
225 session.save()
230 session.save()
226 request.session.flash(
231 request.session.flash(
227 _("Successfully updated password"), queue='success')
232 _("Successfully updated password"), queue='success')
228 return redirect(url('my_account_password'))
233 return redirect(url('my_account_password'))
229
234
230 c.form = form
235 c.form = form
231 return render('admin/my_account/my_account.html')
236 return render('admin/my_account/my_account.html')
232
237
233 def my_account_repos(self):
238 def my_account_repos(self):
234 c.active = 'repos'
239 c.active = 'repos'
235 self.__load_data()
240 self.__load_data()
236
241
237 # json used to render the grid
242 # json used to render the grid
238 c.data = self._load_my_repos_data()
243 c.data = self._load_my_repos_data()
239 return render('admin/my_account/my_account.html')
244 return render('admin/my_account/my_account.html')
240
245
241 def my_account_watched(self):
246 def my_account_watched(self):
242 c.active = 'watched'
247 c.active = 'watched'
243 self.__load_data()
248 self.__load_data()
244
249
245 # json used to render the grid
250 # json used to render the grid
246 c.data = self._load_my_repos_data(watched=True)
251 c.data = self._load_my_repos_data(watched=True)
247 return render('admin/my_account/my_account.html')
252 return render('admin/my_account/my_account.html')
248
253
249 def my_account_perms(self):
254 def my_account_perms(self):
250 c.active = 'perms'
255 c.active = 'perms'
251 self.__load_data()
256 self.__load_data()
252 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
257 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
253 ip_addr=self.ip_addr)
258 ip_addr=self.ip_addr)
254
259
255 return render('admin/my_account/my_account.html')
260 return render('admin/my_account/my_account.html')
256
261
257 def my_account_emails(self):
262 def my_account_emails(self):
258 c.active = 'emails'
263 c.active = 'emails'
259 self.__load_data()
264 self.__load_data()
260
265
261 c.user_email_map = UserEmailMap.query()\
266 c.user_email_map = UserEmailMap.query()\
262 .filter(UserEmailMap.user == c.user).all()
267 .filter(UserEmailMap.user == c.user).all()
263 return render('admin/my_account/my_account.html')
268 return render('admin/my_account/my_account.html')
264
269
265 @auth.CSRFRequired()
270 @auth.CSRFRequired()
266 def my_account_emails_add(self):
271 def my_account_emails_add(self):
267 email = request.POST.get('new_email')
272 email = request.POST.get('new_email')
268
273
269 try:
274 try:
270 UserModel().add_extra_email(c.rhodecode_user.user_id, email)
275 UserModel().add_extra_email(c.rhodecode_user.user_id, email)
271 Session().commit()
276 Session().commit()
272 h.flash(_("Added new email address `%s` for user account") % email,
277 h.flash(_("Added new email address `%s` for user account") % email,
273 category='success')
278 category='success')
274 except formencode.Invalid as error:
279 except formencode.Invalid as error:
275 msg = error.error_dict['email']
280 msg = error.error_dict['email']
276 h.flash(msg, category='error')
281 h.flash(msg, category='error')
277 except Exception:
282 except Exception:
278 log.exception("Exception in my_account_emails")
283 log.exception("Exception in my_account_emails")
279 h.flash(_('An error occurred during email saving'),
284 h.flash(_('An error occurred during email saving'),
280 category='error')
285 category='error')
281 return redirect(url('my_account_emails'))
286 return redirect(url('my_account_emails'))
282
287
283 @auth.CSRFRequired()
288 @auth.CSRFRequired()
284 def my_account_emails_delete(self):
289 def my_account_emails_delete(self):
285 email_id = request.POST.get('del_email_id')
290 email_id = request.POST.get('del_email_id')
286 user_model = UserModel()
291 user_model = UserModel()
287 user_model.delete_extra_email(c.rhodecode_user.user_id, email_id)
292 user_model.delete_extra_email(c.rhodecode_user.user_id, email_id)
288 Session().commit()
293 Session().commit()
289 h.flash(_("Removed email address from user account"),
294 h.flash(_("Removed email address from user account"),
290 category='success')
295 category='success')
291 return redirect(url('my_account_emails'))
296 return redirect(url('my_account_emails'))
292
297
293 def _extract_ordering(self, request):
298 def _extract_ordering(self, request):
294 column_index = safe_int(request.GET.get('order[0][column]'))
299 column_index = safe_int(request.GET.get('order[0][column]'))
295 order_dir = request.GET.get('order[0][dir]', 'desc')
300 order_dir = request.GET.get('order[0][dir]', 'desc')
296 order_by = request.GET.get(
301 order_by = request.GET.get(
297 'columns[%s][data][sort]' % column_index, 'name_raw')
302 'columns[%s][data][sort]' % column_index, 'name_raw')
298 return order_by, order_dir
303 return order_by, order_dir
299
304
300 def _get_pull_requests_list(self, statuses):
305 def _get_pull_requests_list(self, statuses):
301 start = safe_int(request.GET.get('start'), 0)
306 start = safe_int(request.GET.get('start'), 0)
302 length = safe_int(request.GET.get('length'), c.visual.dashboard_items)
307 length = safe_int(request.GET.get('length'), c.visual.dashboard_items)
303 order_by, order_dir = self._extract_ordering(request)
308 order_by, order_dir = self._extract_ordering(request)
304
309
305 pull_requests = PullRequestModel().get_im_participating_in(
310 pull_requests = PullRequestModel().get_im_participating_in(
306 user_id=c.rhodecode_user.user_id,
311 user_id=c.rhodecode_user.user_id,
307 statuses=statuses,
312 statuses=statuses,
308 offset=start, length=length, order_by=order_by,
313 offset=start, length=length, order_by=order_by,
309 order_dir=order_dir)
314 order_dir=order_dir)
310
315
311 pull_requests_total_count = PullRequestModel().count_im_participating_in(
316 pull_requests_total_count = PullRequestModel().count_im_participating_in(
312 user_id=c.rhodecode_user.user_id, statuses=statuses)
317 user_id=c.rhodecode_user.user_id, statuses=statuses)
313
318
314 from rhodecode.lib.utils import PartialRenderer
319 from rhodecode.lib.utils import PartialRenderer
315 _render = PartialRenderer('data_table/_dt_elements.html')
320 _render = PartialRenderer('data_table/_dt_elements.html')
316 data = []
321 data = []
317 for pr in pull_requests:
322 for pr in pull_requests:
318 repo_id = pr.target_repo_id
323 repo_id = pr.target_repo_id
319 comments = ChangesetCommentsModel().get_all_comments(
324 comments = ChangesetCommentsModel().get_all_comments(
320 repo_id, pull_request=pr)
325 repo_id, pull_request=pr)
321 owned = pr.user_id == c.rhodecode_user.user_id
326 owned = pr.user_id == c.rhodecode_user.user_id
322 status = pr.calculated_review_status()
327 status = pr.calculated_review_status()
323
328
324 data.append({
329 data.append({
325 'target_repo': _render('pullrequest_target_repo',
330 'target_repo': _render('pullrequest_target_repo',
326 pr.target_repo.repo_name),
331 pr.target_repo.repo_name),
327 'name': _render('pullrequest_name',
332 'name': _render('pullrequest_name',
328 pr.pull_request_id, pr.target_repo.repo_name,
333 pr.pull_request_id, pr.target_repo.repo_name,
329 short=True),
334 short=True),
330 'name_raw': pr.pull_request_id,
335 'name_raw': pr.pull_request_id,
331 'status': _render('pullrequest_status', status),
336 'status': _render('pullrequest_status', status),
332 'title': _render(
337 'title': _render(
333 'pullrequest_title', pr.title, pr.description),
338 'pullrequest_title', pr.title, pr.description),
334 'description': h.escape(pr.description),
339 'description': h.escape(pr.description),
335 'updated_on': _render('pullrequest_updated_on',
340 'updated_on': _render('pullrequest_updated_on',
336 h.datetime_to_time(pr.updated_on)),
341 h.datetime_to_time(pr.updated_on)),
337 'updated_on_raw': h.datetime_to_time(pr.updated_on),
342 'updated_on_raw': h.datetime_to_time(pr.updated_on),
338 'created_on': _render('pullrequest_updated_on',
343 'created_on': _render('pullrequest_updated_on',
339 h.datetime_to_time(pr.created_on)),
344 h.datetime_to_time(pr.created_on)),
340 'created_on_raw': h.datetime_to_time(pr.created_on),
345 'created_on_raw': h.datetime_to_time(pr.created_on),
341 'author': _render('pullrequest_author',
346 'author': _render('pullrequest_author',
342 pr.author.full_contact, ),
347 pr.author.full_contact, ),
343 'author_raw': pr.author.full_name,
348 'author_raw': pr.author.full_name,
344 'comments': _render('pullrequest_comments', len(comments)),
349 'comments': _render('pullrequest_comments', len(comments)),
345 'comments_raw': len(comments),
350 'comments_raw': len(comments),
346 'closed': pr.is_closed(),
351 'closed': pr.is_closed(),
347 'owned': owned
352 'owned': owned
348 })
353 })
349 # json used to render the grid
354 # json used to render the grid
350 data = ({
355 data = ({
351 'data': data,
356 'data': data,
352 'recordsTotal': pull_requests_total_count,
357 'recordsTotal': pull_requests_total_count,
353 'recordsFiltered': pull_requests_total_count,
358 'recordsFiltered': pull_requests_total_count,
354 })
359 })
355 return data
360 return data
356
361
357 def my_account_pullrequests(self):
362 def my_account_pullrequests(self):
358 c.active = 'pullrequests'
363 c.active = 'pullrequests'
359 self.__load_data()
364 self.__load_data()
360 c.show_closed = str2bool(request.GET.get('pr_show_closed'))
365 c.show_closed = str2bool(request.GET.get('pr_show_closed'))
361
366
362 statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN]
367 statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN]
363 if c.show_closed:
368 if c.show_closed:
364 statuses += [PullRequest.STATUS_CLOSED]
369 statuses += [PullRequest.STATUS_CLOSED]
365 data = self._get_pull_requests_list(statuses)
370 data = self._get_pull_requests_list(statuses)
366 if not request.is_xhr:
371 if not request.is_xhr:
367 c.data_participate = json.dumps(data['data'])
372 c.data_participate = json.dumps(data['data'])
368 c.records_total_participate = data['recordsTotal']
373 c.records_total_participate = data['recordsTotal']
369 return render('admin/my_account/my_account.html')
374 return render('admin/my_account/my_account.html')
370 else:
375 else:
371 return json.dumps(data)
376 return json.dumps(data)
372
377
373 def my_account_auth_tokens(self):
378 def my_account_auth_tokens(self):
374 c.active = 'auth_tokens'
379 c.active = 'auth_tokens'
375 self.__load_data()
380 self.__load_data()
376 show_expired = True
381 show_expired = True
377 c.lifetime_values = [
382 c.lifetime_values = [
378 (str(-1), _('forever')),
383 (str(-1), _('forever')),
379 (str(5), _('5 minutes')),
384 (str(5), _('5 minutes')),
380 (str(60), _('1 hour')),
385 (str(60), _('1 hour')),
381 (str(60 * 24), _('1 day')),
386 (str(60 * 24), _('1 day')),
382 (str(60 * 24 * 30), _('1 month')),
387 (str(60 * 24 * 30), _('1 month')),
383 ]
388 ]
384 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
389 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
385 c.role_values = [(x, AuthTokenModel.cls._get_role_name(x))
390 c.role_values = [(x, AuthTokenModel.cls._get_role_name(x))
386 for x in AuthTokenModel.cls.ROLES]
391 for x in AuthTokenModel.cls.ROLES]
387 c.role_options = [(c.role_values, _("Role"))]
392 c.role_options = [(c.role_values, _("Role"))]
388 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
393 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
389 c.rhodecode_user.user_id, show_expired=show_expired)
394 c.rhodecode_user.user_id, show_expired=show_expired)
390 return render('admin/my_account/my_account.html')
395 return render('admin/my_account/my_account.html')
391
396
392 @auth.CSRFRequired()
397 @auth.CSRFRequired()
393 def my_account_auth_tokens_add(self):
398 def my_account_auth_tokens_add(self):
394 lifetime = safe_int(request.POST.get('lifetime'), -1)
399 lifetime = safe_int(request.POST.get('lifetime'), -1)
395 description = request.POST.get('description')
400 description = request.POST.get('description')
396 role = request.POST.get('role')
401 role = request.POST.get('role')
397 AuthTokenModel().create(c.rhodecode_user.user_id, description, lifetime,
402 AuthTokenModel().create(c.rhodecode_user.user_id, description, lifetime,
398 role)
403 role)
399 Session().commit()
404 Session().commit()
400 h.flash(_("Auth token successfully created"), category='success')
405 h.flash(_("Auth token successfully created"), category='success')
401 return redirect(url('my_account_auth_tokens'))
406 return redirect(url('my_account_auth_tokens'))
402
407
403 @auth.CSRFRequired()
408 @auth.CSRFRequired()
404 def my_account_auth_tokens_delete(self):
409 def my_account_auth_tokens_delete(self):
405 auth_token = request.POST.get('del_auth_token')
410 auth_token = request.POST.get('del_auth_token')
406 user_id = c.rhodecode_user.user_id
411 user_id = c.rhodecode_user.user_id
407 if request.POST.get('del_auth_token_builtin'):
412 if request.POST.get('del_auth_token_builtin'):
408 user = User.get(user_id)
413 user = User.get(user_id)
409 if user:
414 if user:
410 user.api_key = generate_auth_token(user.username)
415 user.api_key = generate_auth_token(user.username)
411 Session().add(user)
416 Session().add(user)
412 Session().commit()
417 Session().commit()
413 h.flash(_("Auth token successfully reset"), category='success')
418 h.flash(_("Auth token successfully reset"), category='success')
414 elif auth_token:
419 elif auth_token:
415 AuthTokenModel().delete(auth_token, c.rhodecode_user.user_id)
420 AuthTokenModel().delete(auth_token, c.rhodecode_user.user_id)
416 Session().commit()
421 Session().commit()
417 h.flash(_("Auth token successfully deleted"), category='success')
422 h.flash(_("Auth token successfully deleted"), category='success')
418
423
419 return redirect(url('my_account_auth_tokens'))
424 return redirect(url('my_account_auth_tokens'))
420
425
421 def my_notifications(self):
426 def my_notifications(self):
422 c.active = 'notifications'
427 c.active = 'notifications'
423 return render('admin/my_account/my_account.html')
428 return render('admin/my_account/my_account.html')
424
429
425 @auth.CSRFRequired()
430 @auth.CSRFRequired()
426 @jsonify
431 @jsonify
427 def my_notifications_toggle_visibility(self):
432 def my_notifications_toggle_visibility(self):
428 user = c.rhodecode_user.get_instance()
433 user = c.rhodecode_user.get_instance()
429 new_status = not user.user_data.get('notification_status', True)
434 new_status = not user.user_data.get('notification_status', True)
430 user.update_userdata(notification_status=new_status)
435 user.update_userdata(notification_status=new_status)
431 Session().commit()
436 Session().commit()
432 return user.user_data['notification_status']
437 return user.user_data['notification_status']
438
439 @auth.CSRFRequired()
440 @jsonify
441 def my_account_notifications_test_channelstream(self):
442 message = 'Test message sent via Channelstream by user: {}, on {}'.format(
443 c.rhodecode_user.username, datetime.datetime.now())
444 payload = {
445 'type': 'message',
446 'timestamp': datetime.datetime.utcnow(),
447 'user': 'system',
448 #'channel': 'broadcast',
449 'pm_users': [c.rhodecode_user.username],
450 'message': {
451 'message': message,
452 'level': 'info',
453 'topic': '/notifications'
454 }
455 }
456
457 registry = get_current_registry()
458 rhodecode_plugins = getattr(registry, 'rhodecode_plugins', {})
459 channelstream_config = rhodecode_plugins.get('channelstream', {})
460
461 try:
462 channelstream_request(channelstream_config, [payload], '/message')
463 except ChannelstreamException as e:
464 log.exception('Failed to send channelstream data')
465 return {"response": 'ERROR: {}'.format(e.__class__.__name__)}
466 return {"response": 'Channelstream data sent. '
467 'You should see a new live message now.'}
@@ -1,70 +1,107 b''
1 <template is="dom-bind" id="notificationsPage">
1 <template is="dom-bind" id="notificationsPage">
2 <iron-ajax id="toggleNotifications"
2 <iron-ajax id="toggleNotifications"
3 method="post"
3 method="post"
4 url="${url('my_account_notifications_toggle_visibility')}"
4 url="${url('my_account_notifications_toggle_visibility')}"
5 content-type="application/json"
5 content-type="application/json"
6 loading="{{changeNotificationsLoading}}"
6 loading="{{changeNotificationsLoading}}"
7 on-response="handleNotifications"
7 on-response="handleNotifications"
8 handle-as="json"></iron-ajax>
8 handle-as="json">
9 </iron-ajax>
10
11 <iron-ajax id="sendTestNotification"
12 method="post"
13 url="${url('my_account_notifications_test_channelstream')}"
14 content-type="application/json"
15 on-response="handleTestNotification"
16 handle-as="json">
17 </iron-ajax>
9
18
10 <div class="panel panel-default">
19 <div class="panel panel-default">
11 <div class="panel-heading">
20 <div class="panel-heading">
12 <h3 class="panel-title">${_('Your Live Notification Settings')}</h3>
21 <h3 class="panel-title">${_('Your Live Notification Settings')}</h3>
13 </div>
22 </div>
14 <div class="panel-body">
23 <div class="panel-body">
15
24
16 <p><strong>IMPORTANT:</strong> This feature requires enabled channelstream websocket server to function correctly.</p>
25 <p><strong>IMPORTANT:</strong> This feature requires enabled channelstream websocket server to function correctly.</p>
17
26
18 <p class="hidden">Status of browser notifications permission: <strong id="browser-notification-status"></strong></p>
27 <p class="hidden">Status of browser notifications permission: <strong id="browser-notification-status"></strong></p>
19
28
20 <div class="form">
29 <div class="form">
21 <div class="fields">
30 <div class="fields">
22 <div class="field">
31 <div class="field">
23 <div class="label">
32 <div class="label">
24 <label for="new_email">${_('Notifications Status')}:</label>
33 <label for="new_email">${_('Notifications Status')}:</label>
25 </div>
34 </div>
26 <div class="checkboxes">
35 <div class="checkboxes">
27 <rhodecode-toggle id="live-notifications" active="[[changeNotificationsLoading]]" on-change="toggleNotifications" ${'checked' if c.rhodecode_user.get_instance().user_data.get('notification_status') else ''}></rhodecode-toggle>
36 <rhodecode-toggle id="live-notifications" active="[[changeNotificationsLoading]]" on-change="toggleNotifications" ${'checked' if c.rhodecode_user.get_instance().user_data.get('notification_status') else ''}></rhodecode-toggle>
28 </div>
37 </div>
29 </div>
38 </div>
30 <div class="buttons">
31 <a class="btn btn-default" id="test-notification" on-tap="testNotifications">Test notification</a>
32 </div>
33 </div>
39 </div>
34 </div>
40 </div>
41 </div>
42 </div>
35
43
36 </div>
44 <div class="panel panel-default">
45 <div class="panel-heading">
46 <h3 class="panel-title">${_('Test Notifications')}</h3>
47 </div>
48 <div class="panel-body">
49
50
51 <div style="padding: 0px 0px 20px 0px">
52 <button class="btn" id="test-notification" on-tap="testNotifications">Test flash message</button>
53 <button class="btn" id="test-notification-live" on-tap="testNotificationsLive">Test live notification</button>
54 </div>
55 <h4 id="test-response"></h4>
56 </div>
57
58 </div>
59
60
61
37 </div>
62 </div>
38
63
39 <script type="text/javascript">
64 <script type="text/javascript">
40 /** because im not creating a custom element for this page
65 /** because im not creating a custom element for this page
41 * we need to push the function onto the dom-template
66 * we need to push the function onto the dom-template
42 * ideally we turn this into notification-settings elements
67 * ideally we turn this into notification-settings elements
43 * then it will be cleaner
68 * then it will be cleaner
44 */
69 */
45 var ctrlr = $('#notificationsPage')[0];
70 var ctrlr = $('#notificationsPage')[0];
46 ctrlr.toggleNotifications = function(event){
71 ctrlr.toggleNotifications = function(event){
47 var ajax = $('#toggleNotifications')[0];
72 var ajax = $('#toggleNotifications')[0];
48 ajax.headers = {"X-CSRF-Token": CSRF_TOKEN}
73 ajax.headers = {"X-CSRF-Token": CSRF_TOKEN};
49 ajax.body = {notification_status:event.target.active};
74 ajax.body = {notification_status:event.target.active};
50 ajax.generateRequest();
75 ajax.generateRequest();
51 };
76 };
52 ctrlr.handleNotifications = function(event){
77 ctrlr.handleNotifications = function(event){
53 $('#live-notifications')[0].checked = event.detail.response;
78 $('#live-notifications')[0].checked = event.detail.response;
54 };
79 };
55
80
56 ctrlr.testNotifications = function(event){
81 ctrlr.testNotifications = function(event){
57 var levels = ['info', 'error', 'warning', 'success'];
82 var levels = ['info', 'error', 'warning', 'success'];
58 var level = levels[Math.floor(Math.random()*levels.length)];
83 var level = levels[Math.floor(Math.random()*levels.length)];
59 var payload = {
84 var payload = {
60 message: {
85 message: {
61 message: 'This is a test notification.',
86 message: 'This is a test notification. ' + new Date(),
62 level: level,
87 level: level,
63 force: true
88 force: true
64 }
89 }
65 };
90 };
66 $.Topic('/notifications').publish(payload);
91 $.Topic('/notifications').publish(payload);
67 }
92 };
93 ctrlr.testNotificationsLive = function(event){
94 var ajax = $('#sendTestNotification')[0];
95 ajax.headers = {"X-CSRF-Token": CSRF_TOKEN};
96 ajax.body = {test_msg: 'Hello !'};
97 ajax.generateRequest();
98 };
99 ctrlr.handleTestNotification = function(event){
100 var reply = event.detail.response.response;
101 reply = reply || 'no reply form server';
102 $('#test-response').html(reply);
103 };
68
104
69 </script>
105 </script>
106
70 </template>
107 </template>
General Comments 0
You need to be logged in to leave comments. Login now