##// END OF EJS Templates
pyramid: moved add_route_requirements into pyramid base app....
marcink -
r1928:d7d26d76 default
parent child Browse files
Show More
@@ -1,385 +1,409 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import time
22 22 import logging
23 23
24 24 from pyramid.httpexceptions import HTTPFound
25 25
26 26 from rhodecode.lib import helpers as h
27 27 from rhodecode.lib.utils2 import StrictAttributeDict, safe_int, datetime_to_time
28 28 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
29 29 from rhodecode.model import repo
30 30 from rhodecode.model import repo_group
31 31 from rhodecode.model.db import User
32 32 from rhodecode.model.scm import ScmModel
33 33
34 34 log = logging.getLogger(__name__)
35 35
36 36
37 37 ADMIN_PREFIX = '/_admin'
38 38 STATIC_FILE_PREFIX = '/_static'
39 39
40 URL_NAME_REQUIREMENTS = {
41 # group name can have a slash in them, but they must not end with a slash
42 'group_name': r'.*?[^/]',
43 'repo_group_name': r'.*?[^/]',
44 # repo names can have a slash in them, but they must not end with a slash
45 'repo_name': r'.*?[^/]',
46 # file path eats up everything at the end
47 'f_path': r'.*',
48 # reference types
49 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
50 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
51 }
52
40 53
41 54 def add_route_with_slash(config,name, pattern, **kw):
42 55 config.add_route(name, pattern, **kw)
43 56 if not pattern.endswith('/'):
44 57 config.add_route(name + '_slash', pattern + '/', **kw)
45 58
46 59
60 def add_route_requirements(route_path, requirements=URL_NAME_REQUIREMENTS):
61 """
62 Adds regex requirements to pyramid routes using a mapping dict
63 e.g::
64 add_route_requirements('{repo_name}/settings')
65 """
66 for key, regex in requirements.items():
67 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
68 return route_path
69
70
47 71 def get_format_ref_id(repo):
48 72 """Returns a `repo` specific reference formatter function"""
49 73 if h.is_svn(repo):
50 74 return _format_ref_id_svn
51 75 else:
52 76 return _format_ref_id
53 77
54 78
55 79 def _format_ref_id(name, raw_id):
56 80 """Default formatting of a given reference `name`"""
57 81 return name
58 82
59 83
60 84 def _format_ref_id_svn(name, raw_id):
61 85 """Special way of formatting a reference for Subversion including path"""
62 86 return '%s@%s' % (name, raw_id)
63 87
64 88
65 89 class TemplateArgs(StrictAttributeDict):
66 90 pass
67 91
68 92
69 93 class BaseAppView(object):
70 94
71 95 def __init__(self, context, request):
72 96 self.request = request
73 97 self.context = context
74 98 self.session = request.session
75 99 self._rhodecode_user = request.user # auth user
76 100 self._rhodecode_db_user = self._rhodecode_user.get_instance()
77 101 self._maybe_needs_password_change(
78 102 request.matched_route.name, self._rhodecode_db_user)
79 103
80 104 def _maybe_needs_password_change(self, view_name, user_obj):
81 105 log.debug('Checking if user %s needs password change on view %s',
82 106 user_obj, view_name)
83 107 skip_user_views = [
84 108 'logout', 'login',
85 109 'my_account_password', 'my_account_password_update'
86 110 ]
87 111
88 112 if not user_obj:
89 113 return
90 114
91 115 if user_obj.username == User.DEFAULT_USER:
92 116 return
93 117
94 118 now = time.time()
95 119 should_change = user_obj.user_data.get('force_password_change')
96 120 change_after = safe_int(should_change) or 0
97 121 if should_change and now > change_after:
98 122 log.debug('User %s requires password change', user_obj)
99 123 h.flash('You are required to change your password', 'warning',
100 124 ignore_duplicate=True)
101 125
102 126 if view_name not in skip_user_views:
103 127 raise HTTPFound(
104 128 self.request.route_path('my_account_password'))
105 129
106 130 def _get_local_tmpl_context(self, include_app_defaults=False):
107 131 c = TemplateArgs()
108 132 c.auth_user = self.request.user
109 133 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
110 134 c.rhodecode_user = self.request.user
111 135
112 136 if include_app_defaults:
113 137 # NOTE(marcink): after full pyramid migration include_app_defaults
114 138 # should be turned on by default
115 139 from rhodecode.lib.base import attach_context_attributes
116 140 attach_context_attributes(c, self.request, self.request.user.user_id)
117 141
118 142 return c
119 143
120 144 def _register_global_c(self, tmpl_args):
121 145 """
122 146 Registers attributes to pylons global `c`
123 147 """
124 148
125 149 # TODO(marcink): remove once pyramid migration is finished
126 150 from pylons import tmpl_context as c
127 151 try:
128 152 for k, v in tmpl_args.items():
129 153 setattr(c, k, v)
130 154 except TypeError:
131 155 log.exception('Failed to register pylons C')
132 156 pass
133 157
134 158 def _get_template_context(self, tmpl_args):
135 159 self._register_global_c(tmpl_args)
136 160
137 161 local_tmpl_args = {
138 162 'defaults': {},
139 163 'errors': {},
140 164 # register a fake 'c' to be used in templates instead of global
141 165 # pylons c, after migration to pyramid we should rename it to 'c'
142 166 # make sure we replace usage of _c in templates too
143 167 '_c': tmpl_args
144 168 }
145 169 local_tmpl_args.update(tmpl_args)
146 170 return local_tmpl_args
147 171
148 172 def load_default_context(self):
149 173 """
150 174 example:
151 175
152 176 def load_default_context(self):
153 177 c = self._get_local_tmpl_context()
154 178 c.custom_var = 'foobar'
155 179 self._register_global_c(c)
156 180 return c
157 181 """
158 182 raise NotImplementedError('Needs implementation in view class')
159 183
160 184
161 185 class RepoAppView(BaseAppView):
162 186
163 187 def __init__(self, context, request):
164 188 super(RepoAppView, self).__init__(context, request)
165 189 self.db_repo = request.db_repo
166 190 self.db_repo_name = self.db_repo.repo_name
167 191 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
168 192
169 193 def _handle_missing_requirements(self, error):
170 194 log.error(
171 195 'Requirements are missing for repository %s: %s',
172 196 self.db_repo_name, error.message)
173 197
174 198 def _get_local_tmpl_context(self, include_app_defaults=False):
175 199 c = super(RepoAppView, self)._get_local_tmpl_context(
176 200 include_app_defaults=include_app_defaults)
177 201
178 202 # register common vars for this type of view
179 203 c.rhodecode_db_repo = self.db_repo
180 204 c.repo_name = self.db_repo_name
181 205 c.repository_pull_requests = self.db_repo_pull_requests
182 206
183 207 c.repository_requirements_missing = False
184 208 try:
185 209 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
186 210 except RepositoryRequirementError as e:
187 211 c.repository_requirements_missing = True
188 212 self._handle_missing_requirements(e)
189 213
190 214 return c
191 215
192 216
193 217 class DataGridAppView(object):
194 218 """
195 219 Common class to have re-usable grid rendering components
196 220 """
197 221
198 222 def _extract_ordering(self, request, column_map=None):
199 223 column_map = column_map or {}
200 224 column_index = safe_int(request.GET.get('order[0][column]'))
201 225 order_dir = request.GET.get(
202 226 'order[0][dir]', 'desc')
203 227 order_by = request.GET.get(
204 228 'columns[%s][data][sort]' % column_index, 'name_raw')
205 229
206 230 # translate datatable to DB columns
207 231 order_by = column_map.get(order_by) or order_by
208 232
209 233 search_q = request.GET.get('search[value]')
210 234 return search_q, order_by, order_dir
211 235
212 236 def _extract_chunk(self, request):
213 237 start = safe_int(request.GET.get('start'), 0)
214 238 length = safe_int(request.GET.get('length'), 25)
215 239 draw = safe_int(request.GET.get('draw'))
216 240 return draw, start, length
217 241
218 242
219 243 class BaseReferencesView(RepoAppView):
220 244 """
221 245 Base for reference view for branches, tags and bookmarks.
222 246 """
223 247 def load_default_context(self):
224 248 c = self._get_local_tmpl_context()
225 249
226 250 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
227 251 c.repo_info = self.db_repo
228 252
229 253 self._register_global_c(c)
230 254 return c
231 255
232 256 def load_refs_context(self, ref_items, partials_template):
233 257 _render = self.request.get_partial_renderer(partials_template)
234 258 pre_load = ["author", "date", "message"]
235 259
236 260 is_svn = h.is_svn(self.rhodecode_vcs_repo)
237 261 is_hg = h.is_hg(self.rhodecode_vcs_repo)
238 262
239 263 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
240 264
241 265 closed_refs = {}
242 266 if is_hg:
243 267 closed_refs = self.rhodecode_vcs_repo.branches_closed
244 268
245 269 data = []
246 270 for ref_name, commit_id in ref_items:
247 271 commit = self.rhodecode_vcs_repo.get_commit(
248 272 commit_id=commit_id, pre_load=pre_load)
249 273 closed = ref_name in closed_refs
250 274
251 275 # TODO: johbo: Unify generation of reference links
252 276 use_commit_id = '/' in ref_name or is_svn
253 277
254 278 if use_commit_id:
255 279 files_url = h.route_path(
256 280 'repo_files',
257 281 repo_name=self.db_repo_name,
258 282 f_path=ref_name if is_svn else '',
259 283 commit_id=commit_id)
260 284
261 285 else:
262 286 files_url = h.route_path(
263 287 'repo_files',
264 288 repo_name=self.db_repo_name,
265 289 f_path=ref_name if is_svn else '',
266 290 commit_id=ref_name,
267 291 _query=dict(at=ref_name))
268 292
269 293 data.append({
270 294 "name": _render('name', ref_name, files_url, closed),
271 295 "name_raw": ref_name,
272 296 "date": _render('date', commit.date),
273 297 "date_raw": datetime_to_time(commit.date),
274 298 "author": _render('author', commit.author),
275 299 "commit": _render(
276 300 'commit', commit.message, commit.raw_id, commit.idx),
277 301 "commit_raw": commit.idx,
278 302 "compare": _render(
279 303 'compare', format_ref_id(ref_name, commit.raw_id)),
280 304 })
281 305
282 306 return data
283 307
284 308
285 309 class RepoRoutePredicate(object):
286 310 def __init__(self, val, config):
287 311 self.val = val
288 312
289 313 def text(self):
290 314 return 'repo_route = %s' % self.val
291 315
292 316 phash = text
293 317
294 318 def __call__(self, info, request):
295 319
296 320 if hasattr(request, 'vcs_call'):
297 321 # skip vcs calls
298 322 return
299 323
300 324 repo_name = info['match']['repo_name']
301 325 repo_model = repo.RepoModel()
302 326 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
303 327
304 328 if by_name_match:
305 329 # register this as request object we can re-use later
306 330 request.db_repo = by_name_match
307 331 return True
308 332
309 333 by_id_match = repo_model.get_repo_by_id(repo_name)
310 334 if by_id_match:
311 335 request.db_repo = by_id_match
312 336 return True
313 337
314 338 return False
315 339
316 340
317 341 class RepoTypeRoutePredicate(object):
318 342 def __init__(self, val, config):
319 343 self.val = val or ['hg', 'git', 'svn']
320 344
321 345 def text(self):
322 346 return 'repo_accepted_type = %s' % self.val
323 347
324 348 phash = text
325 349
326 350 def __call__(self, info, request):
327 351 if hasattr(request, 'vcs_call'):
328 352 # skip vcs calls
329 353 return
330 354
331 355 rhodecode_db_repo = request.db_repo
332 356
333 357 log.debug(
334 358 '%s checking repo type for %s in %s',
335 359 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
336 360
337 361 if rhodecode_db_repo.repo_type in self.val:
338 362 return True
339 363 else:
340 364 log.warning('Current view is not supported for repo type:%s',
341 365 rhodecode_db_repo.repo_type)
342 366 #
343 367 # h.flash(h.literal(
344 368 # _('Action not supported for %s.' % rhodecode_repo.alias)),
345 369 # category='warning')
346 370 # return redirect(
347 371 # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
348 372
349 373 return False
350 374
351 375
352 376 class RepoGroupRoutePredicate(object):
353 377 def __init__(self, val, config):
354 378 self.val = val
355 379
356 380 def text(self):
357 381 return 'repo_group_route = %s' % self.val
358 382
359 383 phash = text
360 384
361 385 def __call__(self, info, request):
362 386 if hasattr(request, 'vcs_call'):
363 387 # skip vcs calls
364 388 return
365 389
366 390 repo_group_name = info['match']['repo_group_name']
367 391 repo_group_model = repo_group.RepoGroupModel()
368 392 by_name_match = repo_group_model.get_by_group_name(
369 393 repo_group_name, cache=True)
370 394
371 395 if by_name_match:
372 396 # register this as request object we can re-use later
373 397 request.db_repo_group = by_name_match
374 398 return True
375 399
376 400 return False
377 401
378 402
379 403 def includeme(config):
380 404 config.add_route_predicate(
381 405 'repo_route', RepoRoutePredicate)
382 406 config.add_route_predicate(
383 407 'repo_accepted_types', RepoTypeRoutePredicate)
384 408 config.add_route_predicate(
385 409 'repo_group_route', RepoGroupRoutePredicate)
@@ -1,744 +1,731 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Routes configuration
23 23
24 24 The more specific and detailed routes should be defined first so they
25 25 may take precedent over the more generic routes. For more information
26 26 refer to the routes manual at http://routes.groovie.org/docs/
27 27
28 28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 29 and _route_name variable which uses some of stored naming here to do redirects.
30 30 """
31 31 import os
32 32 import re
33 33 from routes import Mapper
34 34
35 35 # prefix for non repository related links needs to be prefixed with `/`
36 36 ADMIN_PREFIX = '/_admin'
37 37 STATIC_FILE_PREFIX = '/_static'
38 38
39 39 # Default requirements for URL parts
40 40 URL_NAME_REQUIREMENTS = {
41 41 # group name can have a slash in them, but they must not end with a slash
42 42 'group_name': r'.*?[^/]',
43 43 'repo_group_name': r'.*?[^/]',
44 44 # repo names can have a slash in them, but they must not end with a slash
45 45 'repo_name': r'.*?[^/]',
46 46 # file path eats up everything at the end
47 47 'f_path': r'.*',
48 48 # reference types
49 49 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
50 50 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
51 51 }
52 52
53 53
54 def add_route_requirements(route_path, requirements):
55 """
56 Adds regex requirements to pyramid routes using a mapping dict
57
58 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
59 '/{action}/{id:\d+}'
60
61 """
62 for key, regex in requirements.items():
63 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
64 return route_path
65
66
67 54 class JSRoutesMapper(Mapper):
68 55 """
69 56 Wrapper for routes.Mapper to make pyroutes compatible url definitions
70 57 """
71 58 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
72 59 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
73 60 def __init__(self, *args, **kw):
74 61 super(JSRoutesMapper, self).__init__(*args, **kw)
75 62 self._jsroutes = []
76 63
77 64 def connect(self, *args, **kw):
78 65 """
79 66 Wrapper for connect to take an extra argument jsroute=True
80 67
81 68 :param jsroute: boolean, if True will add the route to the pyroutes list
82 69 """
83 70 if kw.pop('jsroute', False):
84 71 if not self._named_route_regex.match(args[0]):
85 72 raise Exception('only named routes can be added to pyroutes')
86 73 self._jsroutes.append(args[0])
87 74
88 75 super(JSRoutesMapper, self).connect(*args, **kw)
89 76
90 77 def _extract_route_information(self, route):
91 78 """
92 79 Convert a route into tuple(name, path, args), eg:
93 80 ('show_user', '/profile/%(username)s', ['username'])
94 81 """
95 82 routepath = route.routepath
96 83 def replace(matchobj):
97 84 if matchobj.group(1):
98 85 return "%%(%s)s" % matchobj.group(1).split(':')[0]
99 86 else:
100 87 return "%%(%s)s" % matchobj.group(2)
101 88
102 89 routepath = self._argument_prog.sub(replace, routepath)
103 90 return (
104 91 route.name,
105 92 routepath,
106 93 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
107 94 for arg in self._argument_prog.findall(route.routepath)]
108 95 )
109 96
110 97 def jsroutes(self):
111 98 """
112 99 Return a list of pyroutes.js compatible routes
113 100 """
114 101 for route_name in self._jsroutes:
115 102 yield self._extract_route_information(self._routenames[route_name])
116 103
117 104
118 105 def make_map(config):
119 106 """Create, configure and return the routes Mapper"""
120 107 rmap = JSRoutesMapper(
121 108 directory=config['pylons.paths']['controllers'],
122 109 always_scan=config['debug'])
123 110 rmap.minimization = False
124 111 rmap.explicit = False
125 112
126 113 from rhodecode.lib.utils2 import str2bool
127 114 from rhodecode.model import repo, repo_group
128 115
129 116 def check_repo(environ, match_dict):
130 117 """
131 118 check for valid repository for proper 404 handling
132 119
133 120 :param environ:
134 121 :param match_dict:
135 122 """
136 123 repo_name = match_dict.get('repo_name')
137 124
138 125 if match_dict.get('f_path'):
139 126 # fix for multiple initial slashes that causes errors
140 127 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
141 128 repo_model = repo.RepoModel()
142 129 by_name_match = repo_model.get_by_repo_name(repo_name)
143 130 # if we match quickly from database, short circuit the operation,
144 131 # and validate repo based on the type.
145 132 if by_name_match:
146 133 return True
147 134
148 135 by_id_match = repo_model.get_repo_by_id(repo_name)
149 136 if by_id_match:
150 137 repo_name = by_id_match.repo_name
151 138 match_dict['repo_name'] = repo_name
152 139 return True
153 140
154 141 return False
155 142
156 143 def check_group(environ, match_dict):
157 144 """
158 145 check for valid repository group path for proper 404 handling
159 146
160 147 :param environ:
161 148 :param match_dict:
162 149 """
163 150 repo_group_name = match_dict.get('group_name')
164 151 repo_group_model = repo_group.RepoGroupModel()
165 152 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
166 153 if by_name_match:
167 154 return True
168 155
169 156 return False
170 157
171 158 def check_user_group(environ, match_dict):
172 159 """
173 160 check for valid user group for proper 404 handling
174 161
175 162 :param environ:
176 163 :param match_dict:
177 164 """
178 165 return True
179 166
180 167 def check_int(environ, match_dict):
181 168 return match_dict.get('id').isdigit()
182 169
183 170
184 171 #==========================================================================
185 172 # CUSTOM ROUTES HERE
186 173 #==========================================================================
187 174
188 175 # ping and pylons error test
189 176 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
190 177 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
191 178
192 179 # ADMIN REPOSITORY ROUTES
193 180 with rmap.submapper(path_prefix=ADMIN_PREFIX,
194 181 controller='admin/repos') as m:
195 182 m.connect('repos', '/repos',
196 183 action='create', conditions={'method': ['POST']})
197 184 m.connect('repos', '/repos',
198 185 action='index', conditions={'method': ['GET']})
199 186 m.connect('new_repo', '/create_repository', jsroute=True,
200 187 action='create_repository', conditions={'method': ['GET']})
201 188 m.connect('delete_repo', '/repos/{repo_name}',
202 189 action='delete', conditions={'method': ['DELETE']},
203 190 requirements=URL_NAME_REQUIREMENTS)
204 191 m.connect('repo', '/repos/{repo_name}',
205 192 action='show', conditions={'method': ['GET'],
206 193 'function': check_repo},
207 194 requirements=URL_NAME_REQUIREMENTS)
208 195
209 196 # ADMIN REPOSITORY GROUPS ROUTES
210 197 with rmap.submapper(path_prefix=ADMIN_PREFIX,
211 198 controller='admin/repo_groups') as m:
212 199 m.connect('repo_groups', '/repo_groups',
213 200 action='create', conditions={'method': ['POST']})
214 201 m.connect('repo_groups', '/repo_groups',
215 202 action='index', conditions={'method': ['GET']})
216 203 m.connect('new_repo_group', '/repo_groups/new',
217 204 action='new', conditions={'method': ['GET']})
218 205 m.connect('update_repo_group', '/repo_groups/{group_name}',
219 206 action='update', conditions={'method': ['PUT'],
220 207 'function': check_group},
221 208 requirements=URL_NAME_REQUIREMENTS)
222 209
223 210 # EXTRAS REPO GROUP ROUTES
224 211 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
225 212 action='edit',
226 213 conditions={'method': ['GET'], 'function': check_group},
227 214 requirements=URL_NAME_REQUIREMENTS)
228 215 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
229 216 action='edit',
230 217 conditions={'method': ['PUT'], 'function': check_group},
231 218 requirements=URL_NAME_REQUIREMENTS)
232 219
233 220 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
234 221 action='edit_repo_group_advanced',
235 222 conditions={'method': ['GET'], 'function': check_group},
236 223 requirements=URL_NAME_REQUIREMENTS)
237 224 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
238 225 action='edit_repo_group_advanced',
239 226 conditions={'method': ['PUT'], 'function': check_group},
240 227 requirements=URL_NAME_REQUIREMENTS)
241 228
242 229 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
243 230 action='edit_repo_group_perms',
244 231 conditions={'method': ['GET'], 'function': check_group},
245 232 requirements=URL_NAME_REQUIREMENTS)
246 233 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
247 234 action='update_perms',
248 235 conditions={'method': ['PUT'], 'function': check_group},
249 236 requirements=URL_NAME_REQUIREMENTS)
250 237
251 238 m.connect('delete_repo_group', '/repo_groups/{group_name}',
252 239 action='delete', conditions={'method': ['DELETE'],
253 240 'function': check_group},
254 241 requirements=URL_NAME_REQUIREMENTS)
255 242
256 243 # ADMIN USER ROUTES
257 244 with rmap.submapper(path_prefix=ADMIN_PREFIX,
258 245 controller='admin/users') as m:
259 246 m.connect('users', '/users',
260 247 action='create', conditions={'method': ['POST']})
261 248 m.connect('new_user', '/users/new',
262 249 action='new', conditions={'method': ['GET']})
263 250 m.connect('update_user', '/users/{user_id}',
264 251 action='update', conditions={'method': ['PUT']})
265 252 m.connect('delete_user', '/users/{user_id}',
266 253 action='delete', conditions={'method': ['DELETE']})
267 254 m.connect('edit_user', '/users/{user_id}/edit',
268 255 action='edit', conditions={'method': ['GET']}, jsroute=True)
269 256 m.connect('user', '/users/{user_id}',
270 257 action='show', conditions={'method': ['GET']})
271 258 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
272 259 action='reset_password', conditions={'method': ['POST']})
273 260 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
274 261 action='create_personal_repo_group', conditions={'method': ['POST']})
275 262
276 263 # EXTRAS USER ROUTES
277 264 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
278 265 action='edit_advanced', conditions={'method': ['GET']})
279 266 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
280 267 action='update_advanced', conditions={'method': ['PUT']})
281 268
282 269 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
283 270 action='edit_global_perms', conditions={'method': ['GET']})
284 271 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
285 272 action='update_global_perms', conditions={'method': ['PUT']})
286 273
287 274 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
288 275 action='edit_perms_summary', conditions={'method': ['GET']})
289 276
290 277
291 278 # ADMIN USER GROUPS REST ROUTES
292 279 with rmap.submapper(path_prefix=ADMIN_PREFIX,
293 280 controller='admin/user_groups') as m:
294 281 m.connect('users_groups', '/user_groups',
295 282 action='create', conditions={'method': ['POST']})
296 283 m.connect('users_groups', '/user_groups',
297 284 action='index', conditions={'method': ['GET']})
298 285 m.connect('new_users_group', '/user_groups/new',
299 286 action='new', conditions={'method': ['GET']})
300 287 m.connect('update_users_group', '/user_groups/{user_group_id}',
301 288 action='update', conditions={'method': ['PUT']})
302 289 m.connect('delete_users_group', '/user_groups/{user_group_id}',
303 290 action='delete', conditions={'method': ['DELETE']})
304 291 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
305 292 action='edit', conditions={'method': ['GET']},
306 293 function=check_user_group)
307 294
308 295 # EXTRAS USER GROUP ROUTES
309 296 m.connect('edit_user_group_global_perms',
310 297 '/user_groups/{user_group_id}/edit/global_permissions',
311 298 action='edit_global_perms', conditions={'method': ['GET']})
312 299 m.connect('edit_user_group_global_perms',
313 300 '/user_groups/{user_group_id}/edit/global_permissions',
314 301 action='update_global_perms', conditions={'method': ['PUT']})
315 302 m.connect('edit_user_group_perms_summary',
316 303 '/user_groups/{user_group_id}/edit/permissions_summary',
317 304 action='edit_perms_summary', conditions={'method': ['GET']})
318 305
319 306 m.connect('edit_user_group_perms',
320 307 '/user_groups/{user_group_id}/edit/permissions',
321 308 action='edit_perms', conditions={'method': ['GET']})
322 309 m.connect('edit_user_group_perms',
323 310 '/user_groups/{user_group_id}/edit/permissions',
324 311 action='update_perms', conditions={'method': ['PUT']})
325 312
326 313 m.connect('edit_user_group_advanced',
327 314 '/user_groups/{user_group_id}/edit/advanced',
328 315 action='edit_advanced', conditions={'method': ['GET']})
329 316
330 317 m.connect('edit_user_group_advanced_sync',
331 318 '/user_groups/{user_group_id}/edit/advanced/sync',
332 319 action='edit_advanced_set_synchronization', conditions={'method': ['POST']})
333 320
334 321 m.connect('edit_user_group_members',
335 322 '/user_groups/{user_group_id}/edit/members', jsroute=True,
336 323 action='user_group_members', conditions={'method': ['GET']})
337 324
338 325 # ADMIN PERMISSIONS ROUTES
339 326 with rmap.submapper(path_prefix=ADMIN_PREFIX,
340 327 controller='admin/permissions') as m:
341 328 m.connect('admin_permissions_application', '/permissions/application',
342 329 action='permission_application_update', conditions={'method': ['POST']})
343 330 m.connect('admin_permissions_application', '/permissions/application',
344 331 action='permission_application', conditions={'method': ['GET']})
345 332
346 333 m.connect('admin_permissions_global', '/permissions/global',
347 334 action='permission_global_update', conditions={'method': ['POST']})
348 335 m.connect('admin_permissions_global', '/permissions/global',
349 336 action='permission_global', conditions={'method': ['GET']})
350 337
351 338 m.connect('admin_permissions_object', '/permissions/object',
352 339 action='permission_objects_update', conditions={'method': ['POST']})
353 340 m.connect('admin_permissions_object', '/permissions/object',
354 341 action='permission_objects', conditions={'method': ['GET']})
355 342
356 343 m.connect('admin_permissions_ips', '/permissions/ips',
357 344 action='permission_ips', conditions={'method': ['POST']})
358 345 m.connect('admin_permissions_ips', '/permissions/ips',
359 346 action='permission_ips', conditions={'method': ['GET']})
360 347
361 348 m.connect('admin_permissions_overview', '/permissions/overview',
362 349 action='permission_perms', conditions={'method': ['GET']})
363 350
364 351 # ADMIN DEFAULTS REST ROUTES
365 352 with rmap.submapper(path_prefix=ADMIN_PREFIX,
366 353 controller='admin/defaults') as m:
367 354 m.connect('admin_defaults_repositories', '/defaults/repositories',
368 355 action='update_repository_defaults', conditions={'method': ['POST']})
369 356 m.connect('admin_defaults_repositories', '/defaults/repositories',
370 357 action='index', conditions={'method': ['GET']})
371 358
372 359 # ADMIN SETTINGS ROUTES
373 360 with rmap.submapper(path_prefix=ADMIN_PREFIX,
374 361 controller='admin/settings') as m:
375 362
376 363 # default
377 364 m.connect('admin_settings', '/settings',
378 365 action='settings_global_update',
379 366 conditions={'method': ['POST']})
380 367 m.connect('admin_settings', '/settings',
381 368 action='settings_global', conditions={'method': ['GET']})
382 369
383 370 m.connect('admin_settings_vcs', '/settings/vcs',
384 371 action='settings_vcs_update',
385 372 conditions={'method': ['POST']})
386 373 m.connect('admin_settings_vcs', '/settings/vcs',
387 374 action='settings_vcs',
388 375 conditions={'method': ['GET']})
389 376 m.connect('admin_settings_vcs', '/settings/vcs',
390 377 action='delete_svn_pattern',
391 378 conditions={'method': ['DELETE']})
392 379
393 380 m.connect('admin_settings_mapping', '/settings/mapping',
394 381 action='settings_mapping_update',
395 382 conditions={'method': ['POST']})
396 383 m.connect('admin_settings_mapping', '/settings/mapping',
397 384 action='settings_mapping', conditions={'method': ['GET']})
398 385
399 386 m.connect('admin_settings_global', '/settings/global',
400 387 action='settings_global_update',
401 388 conditions={'method': ['POST']})
402 389 m.connect('admin_settings_global', '/settings/global',
403 390 action='settings_global', conditions={'method': ['GET']})
404 391
405 392 m.connect('admin_settings_visual', '/settings/visual',
406 393 action='settings_visual_update',
407 394 conditions={'method': ['POST']})
408 395 m.connect('admin_settings_visual', '/settings/visual',
409 396 action='settings_visual', conditions={'method': ['GET']})
410 397
411 398 m.connect('admin_settings_issuetracker',
412 399 '/settings/issue-tracker', action='settings_issuetracker',
413 400 conditions={'method': ['GET']})
414 401 m.connect('admin_settings_issuetracker_save',
415 402 '/settings/issue-tracker/save',
416 403 action='settings_issuetracker_save',
417 404 conditions={'method': ['POST']})
418 405 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
419 406 action='settings_issuetracker_test',
420 407 conditions={'method': ['POST']})
421 408 m.connect('admin_issuetracker_delete',
422 409 '/settings/issue-tracker/delete',
423 410 action='settings_issuetracker_delete',
424 411 conditions={'method': ['DELETE']})
425 412
426 413 m.connect('admin_settings_email', '/settings/email',
427 414 action='settings_email_update',
428 415 conditions={'method': ['POST']})
429 416 m.connect('admin_settings_email', '/settings/email',
430 417 action='settings_email', conditions={'method': ['GET']})
431 418
432 419 m.connect('admin_settings_hooks', '/settings/hooks',
433 420 action='settings_hooks_update',
434 421 conditions={'method': ['POST', 'DELETE']})
435 422 m.connect('admin_settings_hooks', '/settings/hooks',
436 423 action='settings_hooks', conditions={'method': ['GET']})
437 424
438 425 m.connect('admin_settings_search', '/settings/search',
439 426 action='settings_search', conditions={'method': ['GET']})
440 427
441 428 m.connect('admin_settings_supervisor', '/settings/supervisor',
442 429 action='settings_supervisor', conditions={'method': ['GET']})
443 430 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
444 431 action='settings_supervisor_log', conditions={'method': ['GET']})
445 432
446 433 m.connect('admin_settings_labs', '/settings/labs',
447 434 action='settings_labs_update',
448 435 conditions={'method': ['POST']})
449 436 m.connect('admin_settings_labs', '/settings/labs',
450 437 action='settings_labs', conditions={'method': ['GET']})
451 438
452 439 # ADMIN MY ACCOUNT
453 440 with rmap.submapper(path_prefix=ADMIN_PREFIX,
454 441 controller='admin/my_account') as m:
455 442
456 443 # NOTE(marcink): this needs to be kept for password force flag to be
457 444 # handled in pylons controllers, remove after full migration to pyramid
458 445 m.connect('my_account_password', '/my_account/password',
459 446 action='my_account_password', conditions={'method': ['GET']})
460 447
461 448 # USER JOURNAL
462 449 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
463 450 controller='journal', action='index')
464 451 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
465 452 controller='journal', action='journal_rss')
466 453 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
467 454 controller='journal', action='journal_atom')
468 455
469 456 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
470 457 controller='journal', action='public_journal')
471 458
472 459 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
473 460 controller='journal', action='public_journal_rss')
474 461
475 462 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
476 463 controller='journal', action='public_journal_rss')
477 464
478 465 rmap.connect('public_journal_atom',
479 466 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
480 467 action='public_journal_atom')
481 468
482 469 rmap.connect('public_journal_atom_old',
483 470 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
484 471 action='public_journal_atom')
485 472
486 473 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
487 474 controller='journal', action='toggle_following', jsroute=True,
488 475 conditions={'method': ['POST']})
489 476
490 477 #==========================================================================
491 478 # REPOSITORY ROUTES
492 479 #==========================================================================
493 480
494 481 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
495 482 controller='admin/repos', action='repo_creating',
496 483 requirements=URL_NAME_REQUIREMENTS)
497 484 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
498 485 controller='admin/repos', action='repo_check',
499 486 requirements=URL_NAME_REQUIREMENTS)
500 487
501 488 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
502 489 controller='changeset', revision='tip',
503 490 conditions={'function': check_repo},
504 491 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
505 492 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
506 493 controller='changeset', revision='tip', action='changeset_children',
507 494 conditions={'function': check_repo},
508 495 requirements=URL_NAME_REQUIREMENTS)
509 496 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
510 497 controller='changeset', revision='tip', action='changeset_parents',
511 498 conditions={'function': check_repo},
512 499 requirements=URL_NAME_REQUIREMENTS)
513 500
514 501 # repo edit options
515 502 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
516 503 controller='admin/repos', action='edit_fields',
517 504 conditions={'method': ['GET'], 'function': check_repo},
518 505 requirements=URL_NAME_REQUIREMENTS)
519 506 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
520 507 controller='admin/repos', action='create_repo_field',
521 508 conditions={'method': ['PUT'], 'function': check_repo},
522 509 requirements=URL_NAME_REQUIREMENTS)
523 510 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
524 511 controller='admin/repos', action='delete_repo_field',
525 512 conditions={'method': ['DELETE'], 'function': check_repo},
526 513 requirements=URL_NAME_REQUIREMENTS)
527 514
528 515 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
529 516 controller='admin/repos', action='toggle_locking',
530 517 conditions={'method': ['GET'], 'function': check_repo},
531 518 requirements=URL_NAME_REQUIREMENTS)
532 519
533 520 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
534 521 controller='admin/repos', action='edit_remote_form',
535 522 conditions={'method': ['GET'], 'function': check_repo},
536 523 requirements=URL_NAME_REQUIREMENTS)
537 524 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
538 525 controller='admin/repos', action='edit_remote',
539 526 conditions={'method': ['PUT'], 'function': check_repo},
540 527 requirements=URL_NAME_REQUIREMENTS)
541 528
542 529 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
543 530 controller='admin/repos', action='edit_statistics_form',
544 531 conditions={'method': ['GET'], 'function': check_repo},
545 532 requirements=URL_NAME_REQUIREMENTS)
546 533 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
547 534 controller='admin/repos', action='edit_statistics',
548 535 conditions={'method': ['PUT'], 'function': check_repo},
549 536 requirements=URL_NAME_REQUIREMENTS)
550 537 rmap.connect('repo_settings_issuetracker',
551 538 '/{repo_name}/settings/issue-tracker',
552 539 controller='admin/repos', action='repo_issuetracker',
553 540 conditions={'method': ['GET'], 'function': check_repo},
554 541 requirements=URL_NAME_REQUIREMENTS)
555 542 rmap.connect('repo_issuetracker_test',
556 543 '/{repo_name}/settings/issue-tracker/test',
557 544 controller='admin/repos', action='repo_issuetracker_test',
558 545 conditions={'method': ['POST'], 'function': check_repo},
559 546 requirements=URL_NAME_REQUIREMENTS)
560 547 rmap.connect('repo_issuetracker_delete',
561 548 '/{repo_name}/settings/issue-tracker/delete',
562 549 controller='admin/repos', action='repo_issuetracker_delete',
563 550 conditions={'method': ['DELETE'], 'function': check_repo},
564 551 requirements=URL_NAME_REQUIREMENTS)
565 552 rmap.connect('repo_issuetracker_save',
566 553 '/{repo_name}/settings/issue-tracker/save',
567 554 controller='admin/repos', action='repo_issuetracker_save',
568 555 conditions={'method': ['POST'], 'function': check_repo},
569 556 requirements=URL_NAME_REQUIREMENTS)
570 557 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
571 558 controller='admin/repos', action='repo_settings_vcs_update',
572 559 conditions={'method': ['POST'], 'function': check_repo},
573 560 requirements=URL_NAME_REQUIREMENTS)
574 561 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
575 562 controller='admin/repos', action='repo_settings_vcs',
576 563 conditions={'method': ['GET'], 'function': check_repo},
577 564 requirements=URL_NAME_REQUIREMENTS)
578 565 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
579 566 controller='admin/repos', action='repo_delete_svn_pattern',
580 567 conditions={'method': ['DELETE'], 'function': check_repo},
581 568 requirements=URL_NAME_REQUIREMENTS)
582 569 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
583 570 controller='admin/repos', action='repo_settings_pullrequest',
584 571 conditions={'method': ['GET', 'POST'], 'function': check_repo},
585 572 requirements=URL_NAME_REQUIREMENTS)
586 573
587 574 # still working url for backward compat.
588 575 rmap.connect('raw_changeset_home_depraced',
589 576 '/{repo_name}/raw-changeset/{revision}',
590 577 controller='changeset', action='changeset_raw',
591 578 revision='tip', conditions={'function': check_repo},
592 579 requirements=URL_NAME_REQUIREMENTS)
593 580
594 581 # new URLs
595 582 rmap.connect('changeset_raw_home',
596 583 '/{repo_name}/changeset-diff/{revision}',
597 584 controller='changeset', action='changeset_raw',
598 585 revision='tip', conditions={'function': check_repo},
599 586 requirements=URL_NAME_REQUIREMENTS)
600 587
601 588 rmap.connect('changeset_patch_home',
602 589 '/{repo_name}/changeset-patch/{revision}',
603 590 controller='changeset', action='changeset_patch',
604 591 revision='tip', conditions={'function': check_repo},
605 592 requirements=URL_NAME_REQUIREMENTS)
606 593
607 594 rmap.connect('changeset_download_home',
608 595 '/{repo_name}/changeset-download/{revision}',
609 596 controller='changeset', action='changeset_download',
610 597 revision='tip', conditions={'function': check_repo},
611 598 requirements=URL_NAME_REQUIREMENTS)
612 599
613 600 rmap.connect('changeset_comment',
614 601 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
615 602 controller='changeset', revision='tip', action='comment',
616 603 conditions={'function': check_repo},
617 604 requirements=URL_NAME_REQUIREMENTS)
618 605
619 606 rmap.connect('changeset_comment_preview',
620 607 '/{repo_name}/changeset/comment/preview', jsroute=True,
621 608 controller='changeset', action='preview_comment',
622 609 conditions={'function': check_repo, 'method': ['POST']},
623 610 requirements=URL_NAME_REQUIREMENTS)
624 611
625 612 rmap.connect('changeset_comment_delete',
626 613 '/{repo_name}/changeset/comment/{comment_id}/delete',
627 614 controller='changeset', action='delete_comment',
628 615 conditions={'function': check_repo, 'method': ['DELETE']},
629 616 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
630 617
631 618 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
632 619 controller='changeset', action='changeset_info',
633 620 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
634 621
635 622 rmap.connect('compare_home',
636 623 '/{repo_name}/compare',
637 624 controller='compare', action='index',
638 625 conditions={'function': check_repo},
639 626 requirements=URL_NAME_REQUIREMENTS)
640 627
641 628 rmap.connect('compare_url',
642 629 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
643 630 controller='compare', action='compare',
644 631 conditions={'function': check_repo},
645 632 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
646 633
647 634 rmap.connect('pullrequest_home',
648 635 '/{repo_name}/pull-request/new', controller='pullrequests',
649 636 action='index', conditions={'function': check_repo,
650 637 'method': ['GET']},
651 638 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
652 639
653 640 rmap.connect('pullrequest',
654 641 '/{repo_name}/pull-request/new', controller='pullrequests',
655 642 action='create', conditions={'function': check_repo,
656 643 'method': ['POST']},
657 644 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
658 645
659 646 rmap.connect('pullrequest_repo_refs',
660 647 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
661 648 controller='pullrequests',
662 649 action='get_repo_refs',
663 650 conditions={'function': check_repo, 'method': ['GET']},
664 651 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
665 652
666 653 rmap.connect('pullrequest_repo_destinations',
667 654 '/{repo_name}/pull-request/repo-destinations',
668 655 controller='pullrequests',
669 656 action='get_repo_destinations',
670 657 conditions={'function': check_repo, 'method': ['GET']},
671 658 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
672 659
673 660 rmap.connect('pullrequest_show',
674 661 '/{repo_name}/pull-request/{pull_request_id}',
675 662 controller='pullrequests',
676 663 action='show', conditions={'function': check_repo,
677 664 'method': ['GET']},
678 665 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
679 666
680 667 rmap.connect('pullrequest_update',
681 668 '/{repo_name}/pull-request/{pull_request_id}',
682 669 controller='pullrequests',
683 670 action='update', conditions={'function': check_repo,
684 671 'method': ['PUT']},
685 672 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
686 673
687 674 rmap.connect('pullrequest_merge',
688 675 '/{repo_name}/pull-request/{pull_request_id}',
689 676 controller='pullrequests',
690 677 action='merge', conditions={'function': check_repo,
691 678 'method': ['POST']},
692 679 requirements=URL_NAME_REQUIREMENTS)
693 680
694 681 rmap.connect('pullrequest_delete',
695 682 '/{repo_name}/pull-request/{pull_request_id}',
696 683 controller='pullrequests',
697 684 action='delete', conditions={'function': check_repo,
698 685 'method': ['DELETE']},
699 686 requirements=URL_NAME_REQUIREMENTS)
700 687
701 688 rmap.connect('pullrequest_comment',
702 689 '/{repo_name}/pull-request-comment/{pull_request_id}',
703 690 controller='pullrequests',
704 691 action='comment', conditions={'function': check_repo,
705 692 'method': ['POST']},
706 693 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
707 694
708 695 rmap.connect('pullrequest_comment_delete',
709 696 '/{repo_name}/pull-request-comment/{comment_id}/delete',
710 697 controller='pullrequests', action='delete_comment',
711 698 conditions={'function': check_repo, 'method': ['DELETE']},
712 699 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
713 700
714 701 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
715 702 controller='changelog', conditions={'function': check_repo},
716 703 requirements=URL_NAME_REQUIREMENTS)
717 704
718 705 rmap.connect('changelog_file_home',
719 706 '/{repo_name}/changelog/{revision}/{f_path}',
720 707 controller='changelog', f_path=None,
721 708 conditions={'function': check_repo},
722 709 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
723 710
724 711 rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
725 712 controller='changelog', action='changelog_elements',
726 713 conditions={'function': check_repo},
727 714 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
728 715
729 716 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
730 717 controller='forks', action='fork_create',
731 718 conditions={'function': check_repo, 'method': ['POST']},
732 719 requirements=URL_NAME_REQUIREMENTS)
733 720
734 721 rmap.connect('repo_fork_home', '/{repo_name}/fork',
735 722 controller='forks', action='fork',
736 723 conditions={'function': check_repo},
737 724 requirements=URL_NAME_REQUIREMENTS)
738 725
739 726 rmap.connect('repo_forks_home', '/{repo_name}/forks',
740 727 controller='forks', action='forks',
741 728 conditions={'function': check_repo},
742 729 requirements=URL_NAME_REQUIREMENTS)
743 730
744 731 return rmap
@@ -1,238 +1,226 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22
23 from rhodecode.apps._base import ADMIN_PREFIX, add_route_requirements
23 24 from rhodecode.model.db import Repository, Integration, RepoGroup
24 from rhodecode.config.routing import (
25 ADMIN_PREFIX, add_route_requirements, URL_NAME_REQUIREMENTS)
26 25 from rhodecode.integrations import integration_type_registry
27 26
28 27 log = logging.getLogger(__name__)
29 28
30 29
31 30 def includeme(config):
32 31
33 32 # global integrations
34 33
35 34 config.add_route('global_integrations_new',
36 35 ADMIN_PREFIX + '/integrations/new')
37 36 config.add_view('rhodecode.integrations.views.GlobalIntegrationsView',
38 37 attr='new_integration',
39 38 renderer='rhodecode:templates/admin/integrations/new.mako',
40 39 request_method='GET',
41 40 route_name='global_integrations_new')
42 41
43 42 config.add_route('global_integrations_home',
44 43 ADMIN_PREFIX + '/integrations')
45 44 config.add_route('global_integrations_list',
46 45 ADMIN_PREFIX + '/integrations/{integration}')
47 46 for route_name in ['global_integrations_home', 'global_integrations_list']:
48 47 config.add_view('rhodecode.integrations.views.GlobalIntegrationsView',
49 48 attr='index',
50 49 renderer='rhodecode:templates/admin/integrations/list.mako',
51 50 request_method='GET',
52 51 route_name=route_name)
53 52
54 53 config.add_route('global_integrations_create',
55 54 ADMIN_PREFIX + '/integrations/{integration}/new',
56 55 custom_predicates=(valid_integration,))
57 56 config.add_route('global_integrations_edit',
58 57 ADMIN_PREFIX + '/integrations/{integration}/{integration_id}',
59 58 custom_predicates=(valid_integration,))
60 59
61 60
62 61 for route_name in ['global_integrations_create', 'global_integrations_edit']:
63 62 config.add_view('rhodecode.integrations.views.GlobalIntegrationsView',
64 63 attr='settings_get',
65 64 renderer='rhodecode:templates/admin/integrations/form.mako',
66 65 request_method='GET',
67 66 route_name=route_name)
68 67 config.add_view('rhodecode.integrations.views.GlobalIntegrationsView',
69 68 attr='settings_post',
70 69 renderer='rhodecode:templates/admin/integrations/form.mako',
71 70 request_method='POST',
72 71 route_name=route_name)
73 72
74 73
75 74 # repo group integrations
76 75 config.add_route('repo_group_integrations_home',
77 76 add_route_requirements(
78 77 '{repo_group_name}/settings/integrations',
79 URL_NAME_REQUIREMENTS
80 78 ),
81 79 custom_predicates=(valid_repo_group,)
82 80 )
83 81 config.add_route('repo_group_integrations_list',
84 82 add_route_requirements(
85 83 '{repo_group_name}/settings/integrations/{integration}',
86 URL_NAME_REQUIREMENTS
87 84 ),
88 85 custom_predicates=(valid_repo_group, valid_integration))
89 86 for route_name in ['repo_group_integrations_home', 'repo_group_integrations_list']:
90 87 config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
91 88 attr='index',
92 89 renderer='rhodecode:templates/admin/integrations/list.mako',
93 90 request_method='GET',
94 91 route_name=route_name)
95 92
96 93 config.add_route('repo_group_integrations_new',
97 94 add_route_requirements(
98 95 '{repo_group_name}/settings/integrations/new',
99 URL_NAME_REQUIREMENTS
100 96 ),
101 97 custom_predicates=(valid_repo_group,))
102 98 config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
103 99 attr='new_integration',
104 100 renderer='rhodecode:templates/admin/integrations/new.mako',
105 101 request_method='GET',
106 102 route_name='repo_group_integrations_new')
107 103
108 104 config.add_route('repo_group_integrations_create',
109 105 add_route_requirements(
110 106 '{repo_group_name}/settings/integrations/{integration}/new',
111 URL_NAME_REQUIREMENTS
112 107 ),
113 108 custom_predicates=(valid_repo_group, valid_integration))
114 109 config.add_route('repo_group_integrations_edit',
115 110 add_route_requirements(
116 111 '{repo_group_name}/settings/integrations/{integration}/{integration_id}',
117 URL_NAME_REQUIREMENTS
118 112 ),
119 113 custom_predicates=(valid_repo_group, valid_integration))
120 114 for route_name in ['repo_group_integrations_edit', 'repo_group_integrations_create']:
121 115 config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
122 116 attr='settings_get',
123 117 renderer='rhodecode:templates/admin/integrations/form.mako',
124 118 request_method='GET',
125 119 route_name=route_name)
126 120 config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
127 121 attr='settings_post',
128 122 renderer='rhodecode:templates/admin/integrations/form.mako',
129 123 request_method='POST',
130 124 route_name=route_name)
131 125
132 126
133 127 # repo integrations
134 128 config.add_route('repo_integrations_home',
135 129 add_route_requirements(
136 130 '{repo_name}/settings/integrations',
137 URL_NAME_REQUIREMENTS
138 131 ),
139 132 custom_predicates=(valid_repo,))
140 133 config.add_route('repo_integrations_list',
141 134 add_route_requirements(
142 135 '{repo_name}/settings/integrations/{integration}',
143 URL_NAME_REQUIREMENTS
144 136 ),
145 137 custom_predicates=(valid_repo, valid_integration))
146 138 for route_name in ['repo_integrations_home', 'repo_integrations_list']:
147 139 config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
148 140 attr='index',
149 141 request_method='GET',
150 142 renderer='rhodecode:templates/admin/integrations/list.mako',
151 143 route_name=route_name)
152 144
153 145 config.add_route('repo_integrations_new',
154 146 add_route_requirements(
155 147 '{repo_name}/settings/integrations/new',
156 URL_NAME_REQUIREMENTS
157 148 ),
158 149 custom_predicates=(valid_repo,))
159 150 config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
160 151 attr='new_integration',
161 152 renderer='rhodecode:templates/admin/integrations/new.mako',
162 153 request_method='GET',
163 154 route_name='repo_integrations_new')
164 155
165 156 config.add_route('repo_integrations_create',
166 157 add_route_requirements(
167 158 '{repo_name}/settings/integrations/{integration}/new',
168 URL_NAME_REQUIREMENTS
169 159 ),
170 160 custom_predicates=(valid_repo, valid_integration))
171 161 config.add_route('repo_integrations_edit',
172 162 add_route_requirements(
173 163 '{repo_name}/settings/integrations/{integration}/{integration_id}',
174 URL_NAME_REQUIREMENTS
175 164 ),
176 165 custom_predicates=(valid_repo, valid_integration))
177 166 for route_name in ['repo_integrations_edit', 'repo_integrations_create']:
178 167 config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
179 168 attr='settings_get',
180 169 renderer='rhodecode:templates/admin/integrations/form.mako',
181 170 request_method='GET',
182 171 route_name=route_name)
183 172 config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
184 173 attr='settings_post',
185 174 renderer='rhodecode:templates/admin/integrations/form.mako',
186 175 request_method='POST',
187 176 route_name=route_name)
188 177
189 178
190 179 def valid_repo(info, request):
191 180 repo = Repository.get_by_repo_name(info['match']['repo_name'])
192 181 if repo:
193 182 return True
194 183
195 184
196 185 def valid_repo_group(info, request):
197 186 repo_group = RepoGroup.get_by_group_name(info['match']['repo_group_name'])
198 187 if repo_group:
199 188 return True
200 189 return False
201 190
202 191
203 192 def valid_integration(info, request):
204 193 integration_type = info['match']['integration']
205 194 integration_id = info['match'].get('integration_id')
206 195 repo_name = info['match'].get('repo_name')
207 196 repo_group_name = info['match'].get('repo_group_name')
208 197
209 198 if integration_type not in integration_type_registry:
210 199 return False
211 200
212 201 repo, repo_group = None, None
213 202 if repo_name:
214 203 repo = Repository.get_by_repo_name(repo_name)
215 204 if not repo:
216 205 return False
217 206
218 207 if repo_group_name:
219 208 repo_group = RepoGroup.get_by_group_name(repo_group_name)
220 209 if not repo_group:
221 210 return False
222 211
223 212 if repo_name and repo_group:
224 213 raise Exception('Either repo or repo_group can be set, not both')
225 214
226
227 215 if integration_id:
228 216 integration = Integration.get(integration_id)
229 217 if not integration:
230 218 return False
231 219 if integration.integration_type != integration_type:
232 220 return False
233 221 if repo and repo.repo_id != integration.repo_id:
234 222 return False
235 223 if repo_group and repo_group.group_id != integration.repo_group_id:
236 224 return False
237 225
238 226 return True
General Comments 0
You need to be logged in to leave comments. Login now