##// END OF EJS Templates
core: handle edge case requesting matched routes but with hg/svn/git or api context....
marcink -
r3036:bfb27900 stable
parent child Browse files
Show More
@@ -1,645 +1,652 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2018 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 import operator
24 24
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPBadRequest
26 26
27 27 from rhodecode.lib import helpers as h, diffs
28 28 from rhodecode.lib.utils2 import StrictAttributeDict, safe_int, datetime_to_time
29 29 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
30 30 from rhodecode.model import repo
31 31 from rhodecode.model import repo_group
32 32 from rhodecode.model import user_group
33 33 from rhodecode.model import user
34 34 from rhodecode.model.db import User
35 35 from rhodecode.model.scm import ScmModel
36 36 from rhodecode.model.settings import VcsSettingsModel
37 37
38 38 log = logging.getLogger(__name__)
39 39
40 40
41 41 ADMIN_PREFIX = '/_admin'
42 42 STATIC_FILE_PREFIX = '/_static'
43 43
44 44 URL_NAME_REQUIREMENTS = {
45 45 # group name can have a slash in them, but they must not end with a slash
46 46 'group_name': r'.*?[^/]',
47 47 'repo_group_name': r'.*?[^/]',
48 48 # repo names can have a slash in them, but they must not end with a slash
49 49 'repo_name': r'.*?[^/]',
50 50 # file path eats up everything at the end
51 51 'f_path': r'.*',
52 52 # reference types
53 53 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
54 54 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
55 55 }
56 56
57 57
58 58 def add_route_with_slash(config,name, pattern, **kw):
59 59 config.add_route(name, pattern, **kw)
60 60 if not pattern.endswith('/'):
61 61 config.add_route(name + '_slash', pattern + '/', **kw)
62 62
63 63
64 64 def add_route_requirements(route_path, requirements=URL_NAME_REQUIREMENTS):
65 65 """
66 66 Adds regex requirements to pyramid routes using a mapping dict
67 67 e.g::
68 68 add_route_requirements('{repo_name}/settings')
69 69 """
70 70 for key, regex in requirements.items():
71 71 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
72 72 return route_path
73 73
74 74
75 75 def get_format_ref_id(repo):
76 76 """Returns a `repo` specific reference formatter function"""
77 77 if h.is_svn(repo):
78 78 return _format_ref_id_svn
79 79 else:
80 80 return _format_ref_id
81 81
82 82
83 83 def _format_ref_id(name, raw_id):
84 84 """Default formatting of a given reference `name`"""
85 85 return name
86 86
87 87
88 88 def _format_ref_id_svn(name, raw_id):
89 89 """Special way of formatting a reference for Subversion including path"""
90 90 return '%s@%s' % (name, raw_id)
91 91
92 92
93 93 class TemplateArgs(StrictAttributeDict):
94 94 pass
95 95
96 96
97 97 class BaseAppView(object):
98 98
99 99 def __init__(self, context, request):
100 100 self.request = request
101 101 self.context = context
102 102 self.session = request.session
103 if not hasattr(request, 'user'):
104 # NOTE(marcink): edge case, we ended up in matched route
105 # but probably of web-app context, e.g API CALL/VCS CALL
106 if hasattr(request, 'vcs_call') or hasattr(request, 'rpc_method'):
107 log.warning('Unable to process request `%s` in this scope', request)
108 raise HTTPBadRequest()
109
103 110 self._rhodecode_user = request.user # auth user
104 111 self._rhodecode_db_user = self._rhodecode_user.get_instance()
105 112 self._maybe_needs_password_change(
106 113 request.matched_route.name, self._rhodecode_db_user)
107 114
108 115 def _maybe_needs_password_change(self, view_name, user_obj):
109 116 log.debug('Checking if user %s needs password change on view %s',
110 117 user_obj, view_name)
111 118 skip_user_views = [
112 119 'logout', 'login',
113 120 'my_account_password', 'my_account_password_update'
114 121 ]
115 122
116 123 if not user_obj:
117 124 return
118 125
119 126 if user_obj.username == User.DEFAULT_USER:
120 127 return
121 128
122 129 now = time.time()
123 130 should_change = user_obj.user_data.get('force_password_change')
124 131 change_after = safe_int(should_change) or 0
125 132 if should_change and now > change_after:
126 133 log.debug('User %s requires password change', user_obj)
127 134 h.flash('You are required to change your password', 'warning',
128 135 ignore_duplicate=True)
129 136
130 137 if view_name not in skip_user_views:
131 138 raise HTTPFound(
132 139 self.request.route_path('my_account_password'))
133 140
134 141 def _log_creation_exception(self, e, repo_name):
135 142 _ = self.request.translate
136 143 reason = None
137 144 if len(e.args) == 2:
138 145 reason = e.args[1]
139 146
140 147 if reason == 'INVALID_CERTIFICATE':
141 148 log.exception(
142 149 'Exception creating a repository: invalid certificate')
143 150 msg = (_('Error creating repository %s: invalid certificate')
144 151 % repo_name)
145 152 else:
146 153 log.exception("Exception creating a repository")
147 154 msg = (_('Error creating repository %s')
148 155 % repo_name)
149 156 return msg
150 157
151 158 def _get_local_tmpl_context(self, include_app_defaults=True):
152 159 c = TemplateArgs()
153 160 c.auth_user = self.request.user
154 161 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
155 162 c.rhodecode_user = self.request.user
156 163
157 164 if include_app_defaults:
158 165 from rhodecode.lib.base import attach_context_attributes
159 166 attach_context_attributes(c, self.request, self.request.user.user_id)
160 167
161 168 return c
162 169
163 170 def _get_template_context(self, tmpl_args, **kwargs):
164 171
165 172 local_tmpl_args = {
166 173 'defaults': {},
167 174 'errors': {},
168 175 'c': tmpl_args
169 176 }
170 177 local_tmpl_args.update(kwargs)
171 178 return local_tmpl_args
172 179
173 180 def load_default_context(self):
174 181 """
175 182 example:
176 183
177 184 def load_default_context(self):
178 185 c = self._get_local_tmpl_context()
179 186 c.custom_var = 'foobar'
180 187
181 188 return c
182 189 """
183 190 raise NotImplementedError('Needs implementation in view class')
184 191
185 192
186 193 class RepoAppView(BaseAppView):
187 194
188 195 def __init__(self, context, request):
189 196 super(RepoAppView, self).__init__(context, request)
190 197 self.db_repo = request.db_repo
191 198 self.db_repo_name = self.db_repo.repo_name
192 199 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
193 200
194 201 def _handle_missing_requirements(self, error):
195 202 log.error(
196 203 'Requirements are missing for repository %s: %s',
197 204 self.db_repo_name, error.message)
198 205
199 206 def _get_local_tmpl_context(self, include_app_defaults=True):
200 207 _ = self.request.translate
201 208 c = super(RepoAppView, self)._get_local_tmpl_context(
202 209 include_app_defaults=include_app_defaults)
203 210
204 211 # register common vars for this type of view
205 212 c.rhodecode_db_repo = self.db_repo
206 213 c.repo_name = self.db_repo_name
207 214 c.repository_pull_requests = self.db_repo_pull_requests
208 215 self.path_filter = PathFilter(None)
209 216
210 217 c.repository_requirements_missing = {}
211 218 try:
212 219 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
213 220 if self.rhodecode_vcs_repo:
214 221 path_perms = self.rhodecode_vcs_repo.get_path_permissions(
215 222 c.auth_user.username)
216 223 self.path_filter = PathFilter(path_perms)
217 224 except RepositoryRequirementError as e:
218 225 c.repository_requirements_missing = {'error': str(e)}
219 226 self._handle_missing_requirements(e)
220 227 self.rhodecode_vcs_repo = None
221 228
222 229 c.path_filter = self.path_filter # used by atom_feed_entry.mako
223 230
224 231 if self.rhodecode_vcs_repo is None:
225 232 # unable to fetch this repo as vcs instance, report back to user
226 233 h.flash(_(
227 234 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
228 235 "Please check if it exist, or is not damaged.") %
229 236 {'repo_name': c.repo_name},
230 237 category='error', ignore_duplicate=True)
231 238 if c.repository_requirements_missing:
232 239 route = self.request.matched_route.name
233 240 if route.startswith(('edit_repo', 'repo_summary')):
234 241 # allow summary and edit repo on missing requirements
235 242 return c
236 243
237 244 raise HTTPFound(
238 245 h.route_path('repo_summary', repo_name=self.db_repo_name))
239 246
240 247 else: # redirect if we don't show missing requirements
241 248 raise HTTPFound(h.route_path('home'))
242 249
243 250 return c
244 251
245 252 def _get_f_path_unchecked(self, matchdict, default=None):
246 253 """
247 254 Should only be used by redirects, everything else should call _get_f_path
248 255 """
249 256 f_path = matchdict.get('f_path')
250 257 if f_path:
251 258 # fix for multiple initial slashes that causes errors for GIT
252 259 return f_path.lstrip('/')
253 260
254 261 return default
255 262
256 263 def _get_f_path(self, matchdict, default=None):
257 264 f_path_match = self._get_f_path_unchecked(matchdict, default)
258 265 return self.path_filter.assert_path_permissions(f_path_match)
259 266
260 267 def _get_general_setting(self, target_repo, settings_key, default=False):
261 268 settings_model = VcsSettingsModel(repo=target_repo)
262 269 settings = settings_model.get_general_settings()
263 270 return settings.get(settings_key, default)
264 271
265 272
266 273 class PathFilter(object):
267 274
268 275 # Expects and instance of BasePathPermissionChecker or None
269 276 def __init__(self, permission_checker):
270 277 self.permission_checker = permission_checker
271 278
272 279 def assert_path_permissions(self, path):
273 280 if path and self.permission_checker and not self.permission_checker.has_access(path):
274 281 raise HTTPForbidden()
275 282 return path
276 283
277 284 def filter_patchset(self, patchset):
278 285 if not self.permission_checker or not patchset:
279 286 return patchset, False
280 287 had_filtered = False
281 288 filtered_patchset = []
282 289 for patch in patchset:
283 290 filename = patch.get('filename', None)
284 291 if not filename or self.permission_checker.has_access(filename):
285 292 filtered_patchset.append(patch)
286 293 else:
287 294 had_filtered = True
288 295 if had_filtered:
289 296 if isinstance(patchset, diffs.LimitedDiffContainer):
290 297 filtered_patchset = diffs.LimitedDiffContainer(patchset.diff_limit, patchset.cur_diff_size, filtered_patchset)
291 298 return filtered_patchset, True
292 299 else:
293 300 return patchset, False
294 301
295 302 def render_patchset_filtered(self, diffset, patchset, source_ref=None, target_ref=None):
296 303 filtered_patchset, has_hidden_changes = self.filter_patchset(patchset)
297 304 result = diffset.render_patchset(filtered_patchset, source_ref=source_ref, target_ref=target_ref)
298 305 result.has_hidden_changes = has_hidden_changes
299 306 return result
300 307
301 308 def get_raw_patch(self, diff_processor):
302 309 if self.permission_checker is None:
303 310 return diff_processor.as_raw()
304 311 elif self.permission_checker.has_full_access:
305 312 return diff_processor.as_raw()
306 313 else:
307 314 return '# Repository has user-specific filters, raw patch generation is disabled.'
308 315
309 316 @property
310 317 def is_enabled(self):
311 318 return self.permission_checker is not None
312 319
313 320
314 321 class RepoGroupAppView(BaseAppView):
315 322 def __init__(self, context, request):
316 323 super(RepoGroupAppView, self).__init__(context, request)
317 324 self.db_repo_group = request.db_repo_group
318 325 self.db_repo_group_name = self.db_repo_group.group_name
319 326
320 327 def _revoke_perms_on_yourself(self, form_result):
321 328 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
322 329 form_result['perm_updates'])
323 330 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
324 331 form_result['perm_additions'])
325 332 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
326 333 form_result['perm_deletions'])
327 334 admin_perm = 'group.admin'
328 335 if _updates and _updates[0][1] != admin_perm or \
329 336 _additions and _additions[0][1] != admin_perm or \
330 337 _deletions and _deletions[0][1] != admin_perm:
331 338 return True
332 339 return False
333 340
334 341
335 342 class UserGroupAppView(BaseAppView):
336 343 def __init__(self, context, request):
337 344 super(UserGroupAppView, self).__init__(context, request)
338 345 self.db_user_group = request.db_user_group
339 346 self.db_user_group_name = self.db_user_group.users_group_name
340 347
341 348
342 349 class UserAppView(BaseAppView):
343 350 def __init__(self, context, request):
344 351 super(UserAppView, self).__init__(context, request)
345 352 self.db_user = request.db_user
346 353 self.db_user_id = self.db_user.user_id
347 354
348 355 _ = self.request.translate
349 356 if not request.db_user_supports_default:
350 357 if self.db_user.username == User.DEFAULT_USER:
351 358 h.flash(_("Editing user `{}` is disabled.".format(
352 359 User.DEFAULT_USER)), category='warning')
353 360 raise HTTPFound(h.route_path('users'))
354 361
355 362
356 363 class DataGridAppView(object):
357 364 """
358 365 Common class to have re-usable grid rendering components
359 366 """
360 367
361 368 def _extract_ordering(self, request, column_map=None):
362 369 column_map = column_map or {}
363 370 column_index = safe_int(request.GET.get('order[0][column]'))
364 371 order_dir = request.GET.get(
365 372 'order[0][dir]', 'desc')
366 373 order_by = request.GET.get(
367 374 'columns[%s][data][sort]' % column_index, 'name_raw')
368 375
369 376 # translate datatable to DB columns
370 377 order_by = column_map.get(order_by) or order_by
371 378
372 379 search_q = request.GET.get('search[value]')
373 380 return search_q, order_by, order_dir
374 381
375 382 def _extract_chunk(self, request):
376 383 start = safe_int(request.GET.get('start'), 0)
377 384 length = safe_int(request.GET.get('length'), 25)
378 385 draw = safe_int(request.GET.get('draw'))
379 386 return draw, start, length
380 387
381 388 def _get_order_col(self, order_by, model):
382 389 if isinstance(order_by, basestring):
383 390 try:
384 391 return operator.attrgetter(order_by)(model)
385 392 except AttributeError:
386 393 return None
387 394 else:
388 395 return order_by
389 396
390 397
391 398 class BaseReferencesView(RepoAppView):
392 399 """
393 400 Base for reference view for branches, tags and bookmarks.
394 401 """
395 402 def load_default_context(self):
396 403 c = self._get_local_tmpl_context()
397 404
398 405
399 406 return c
400 407
401 408 def load_refs_context(self, ref_items, partials_template):
402 409 _render = self.request.get_partial_renderer(partials_template)
403 410 pre_load = ["author", "date", "message"]
404 411
405 412 is_svn = h.is_svn(self.rhodecode_vcs_repo)
406 413 is_hg = h.is_hg(self.rhodecode_vcs_repo)
407 414
408 415 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
409 416
410 417 closed_refs = {}
411 418 if is_hg:
412 419 closed_refs = self.rhodecode_vcs_repo.branches_closed
413 420
414 421 data = []
415 422 for ref_name, commit_id in ref_items:
416 423 commit = self.rhodecode_vcs_repo.get_commit(
417 424 commit_id=commit_id, pre_load=pre_load)
418 425 closed = ref_name in closed_refs
419 426
420 427 # TODO: johbo: Unify generation of reference links
421 428 use_commit_id = '/' in ref_name or is_svn
422 429
423 430 if use_commit_id:
424 431 files_url = h.route_path(
425 432 'repo_files',
426 433 repo_name=self.db_repo_name,
427 434 f_path=ref_name if is_svn else '',
428 435 commit_id=commit_id)
429 436
430 437 else:
431 438 files_url = h.route_path(
432 439 'repo_files',
433 440 repo_name=self.db_repo_name,
434 441 f_path=ref_name if is_svn else '',
435 442 commit_id=ref_name,
436 443 _query=dict(at=ref_name))
437 444
438 445 data.append({
439 446 "name": _render('name', ref_name, files_url, closed),
440 447 "name_raw": ref_name,
441 448 "date": _render('date', commit.date),
442 449 "date_raw": datetime_to_time(commit.date),
443 450 "author": _render('author', commit.author),
444 451 "commit": _render(
445 452 'commit', commit.message, commit.raw_id, commit.idx),
446 453 "commit_raw": commit.idx,
447 454 "compare": _render(
448 455 'compare', format_ref_id(ref_name, commit.raw_id)),
449 456 })
450 457
451 458 return data
452 459
453 460
454 461 class RepoRoutePredicate(object):
455 462 def __init__(self, val, config):
456 463 self.val = val
457 464
458 465 def text(self):
459 466 return 'repo_route = %s' % self.val
460 467
461 468 phash = text
462 469
463 470 def __call__(self, info, request):
464 471 if hasattr(request, 'vcs_call'):
465 472 # skip vcs calls
466 473 return
467 474
468 475 repo_name = info['match']['repo_name']
469 476 repo_model = repo.RepoModel()
470 477
471 478 by_name_match = repo_model.get_by_repo_name(repo_name, cache=False)
472 479
473 480 def redirect_if_creating(route_info, db_repo):
474 481 skip_views = ['edit_repo_advanced_delete']
475 482 route = route_info['route']
476 483 # we should skip delete view so we can actually "remove" repositories
477 484 # if they get stuck in creating state.
478 485 if route.name in skip_views:
479 486 return
480 487
481 488 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
482 489 repo_creating_url = request.route_path(
483 490 'repo_creating', repo_name=db_repo.repo_name)
484 491 raise HTTPFound(repo_creating_url)
485 492
486 493 if by_name_match:
487 494 # register this as request object we can re-use later
488 495 request.db_repo = by_name_match
489 496 redirect_if_creating(info, by_name_match)
490 497 return True
491 498
492 499 by_id_match = repo_model.get_repo_by_id(repo_name)
493 500 if by_id_match:
494 501 request.db_repo = by_id_match
495 502 redirect_if_creating(info, by_id_match)
496 503 return True
497 504
498 505 return False
499 506
500 507
501 508 class RepoTypeRoutePredicate(object):
502 509 def __init__(self, val, config):
503 510 self.val = val or ['hg', 'git', 'svn']
504 511
505 512 def text(self):
506 513 return 'repo_accepted_type = %s' % self.val
507 514
508 515 phash = text
509 516
510 517 def __call__(self, info, request):
511 518 if hasattr(request, 'vcs_call'):
512 519 # skip vcs calls
513 520 return
514 521
515 522 rhodecode_db_repo = request.db_repo
516 523
517 524 log.debug(
518 525 '%s checking repo type for %s in %s',
519 526 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
520 527
521 528 if rhodecode_db_repo.repo_type in self.val:
522 529 return True
523 530 else:
524 531 log.warning('Current view is not supported for repo type:%s',
525 532 rhodecode_db_repo.repo_type)
526 533
527 534 # h.flash(h.literal(
528 535 # _('Action not supported for %s.' % rhodecode_repo.alias)),
529 536 # category='warning')
530 537 # return redirect(
531 538 # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
532 539
533 540 return False
534 541
535 542
536 543 class RepoGroupRoutePredicate(object):
537 544 def __init__(self, val, config):
538 545 self.val = val
539 546
540 547 def text(self):
541 548 return 'repo_group_route = %s' % self.val
542 549
543 550 phash = text
544 551
545 552 def __call__(self, info, request):
546 553 if hasattr(request, 'vcs_call'):
547 554 # skip vcs calls
548 555 return
549 556
550 557 repo_group_name = info['match']['repo_group_name']
551 558 repo_group_model = repo_group.RepoGroupModel()
552 559 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
553 560
554 561 if by_name_match:
555 562 # register this as request object we can re-use later
556 563 request.db_repo_group = by_name_match
557 564 return True
558 565
559 566 return False
560 567
561 568
562 569 class UserGroupRoutePredicate(object):
563 570 def __init__(self, val, config):
564 571 self.val = val
565 572
566 573 def text(self):
567 574 return 'user_group_route = %s' % self.val
568 575
569 576 phash = text
570 577
571 578 def __call__(self, info, request):
572 579 if hasattr(request, 'vcs_call'):
573 580 # skip vcs calls
574 581 return
575 582
576 583 user_group_id = info['match']['user_group_id']
577 584 user_group_model = user_group.UserGroup()
578 585 by_id_match = user_group_model.get(user_group_id, cache=False)
579 586
580 587 if by_id_match:
581 588 # register this as request object we can re-use later
582 589 request.db_user_group = by_id_match
583 590 return True
584 591
585 592 return False
586 593
587 594
588 595 class UserRoutePredicateBase(object):
589 596 supports_default = None
590 597
591 598 def __init__(self, val, config):
592 599 self.val = val
593 600
594 601 def text(self):
595 602 raise NotImplementedError()
596 603
597 604 def __call__(self, info, request):
598 605 if hasattr(request, 'vcs_call'):
599 606 # skip vcs calls
600 607 return
601 608
602 609 user_id = info['match']['user_id']
603 610 user_model = user.User()
604 611 by_id_match = user_model.get(user_id, cache=False)
605 612
606 613 if by_id_match:
607 614 # register this as request object we can re-use later
608 615 request.db_user = by_id_match
609 616 request.db_user_supports_default = self.supports_default
610 617 return True
611 618
612 619 return False
613 620
614 621
615 622 class UserRoutePredicate(UserRoutePredicateBase):
616 623 supports_default = False
617 624
618 625 def text(self):
619 626 return 'user_route = %s' % self.val
620 627
621 628 phash = text
622 629
623 630
624 631 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
625 632 supports_default = True
626 633
627 634 def text(self):
628 635 return 'user_with_default_route = %s' % self.val
629 636
630 637 phash = text
631 638
632 639
633 640 def includeme(config):
634 641 config.add_route_predicate(
635 642 'repo_route', RepoRoutePredicate)
636 643 config.add_route_predicate(
637 644 'repo_accepted_types', RepoTypeRoutePredicate)
638 645 config.add_route_predicate(
639 646 'repo_group_route', RepoGroupRoutePredicate)
640 647 config.add_route_predicate(
641 648 'user_group_route', UserGroupRoutePredicate)
642 649 config.add_route_predicate(
643 650 'user_route_with_default', UserRouteWithDefaultPredicate)
644 651 config.add_route_predicate(
645 652 'user_route', UserRoutePredicate) No newline at end of file
@@ -1,53 +1,73 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2018 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 from rhodecode.config import routing_links
21 21
22 22
23 class VCSCallPredicate(object):
24 def __init__(self, val, config):
25 self.val = val
26
27 def text(self):
28 return 'vcs_call route = %s' % self.val
29
30 phash = text
31
32 def __call__(self, info, request):
33 if hasattr(request, 'vcs_call'):
34 # skip vcs calls
35 return False
36
37 return True
38
39
23 40 def includeme(config):
24 41
25 42 config.add_route(
26 43 name='home',
27 44 pattern='/')
28 45
29 46 config.add_route(
30 47 name='user_autocomplete_data',
31 48 pattern='/_users')
32 49
33 50 config.add_route(
34 51 name='user_group_autocomplete_data',
35 52 pattern='/_user_groups')
36 53
37 54 config.add_route(
38 55 name='repo_list_data',
39 56 pattern='/_repos')
40 57
41 58 config.add_route(
42 59 name='goto_switcher_data',
43 60 pattern='/_goto_data')
44 61
45 62 config.add_route(
46 63 name='markup_preview',
47 64 pattern='/_markup_preview')
48 65
49 66 # register our static links via redirection mechanism
50 67 routing_links.connect_redirection_links(config)
51 68
52 69 # Scan module for configuration decorators.
53 70 config.scan('.views', ignore='.tests')
71
72 config.add_route_predicate(
73 'skip_vcs_call', VCSCallPredicate)
General Comments 0
You need to be logged in to leave comments. Login now