##// END OF EJS Templates
core: don't check channelstream connections for faster handling of this route.
super-admin -
r4700:ba59a558 stable
parent child Browse files
Show More
@@ -1,808 +1,816 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2020 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 25 from pyramid import compat
26 26 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPBadRequest
27 27
28 28 from rhodecode.lib import helpers as h, diffs, rc_cache
29 29 from rhodecode.lib.utils2 import (
30 30 StrictAttributeDict, str2bool, safe_int, datetime_to_time, safe_unicode)
31 31 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
32 32 from rhodecode.lib.vcs.backends.base import EmptyCommit
33 33 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
34 34 from rhodecode.model import repo
35 35 from rhodecode.model import repo_group
36 36 from rhodecode.model import user_group
37 37 from rhodecode.model import user
38 38 from rhodecode.model.db import User
39 39 from rhodecode.model.scm import ScmModel
40 40 from rhodecode.model.settings import VcsSettingsModel, IssueTrackerSettingsModel
41 41 from rhodecode.model.repo import ReadmeFinder
42 42
43 43 log = logging.getLogger(__name__)
44 44
45 45
46 46 ADMIN_PREFIX = '/_admin'
47 47 STATIC_FILE_PREFIX = '/_static'
48 48
49 49 URL_NAME_REQUIREMENTS = {
50 50 # group name can have a slash in them, but they must not end with a slash
51 51 'group_name': r'.*?[^/]',
52 52 'repo_group_name': r'.*?[^/]',
53 53 # repo names can have a slash in them, but they must not end with a slash
54 54 'repo_name': r'.*?[^/]',
55 55 # file path eats up everything at the end
56 56 'f_path': r'.*',
57 57 # reference types
58 58 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
59 59 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
60 60 }
61 61
62 62
63 63 def add_route_with_slash(config,name, pattern, **kw):
64 64 config.add_route(name, pattern, **kw)
65 65 if not pattern.endswith('/'):
66 66 config.add_route(name + '_slash', pattern + '/', **kw)
67 67
68 68
69 69 def add_route_requirements(route_path, requirements=None):
70 70 """
71 71 Adds regex requirements to pyramid routes using a mapping dict
72 72 e.g::
73 73 add_route_requirements('{repo_name}/settings')
74 74 """
75 75 requirements = requirements or URL_NAME_REQUIREMENTS
76 76 for key, regex in requirements.items():
77 77 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
78 78 return route_path
79 79
80 80
81 81 def get_format_ref_id(repo):
82 82 """Returns a `repo` specific reference formatter function"""
83 83 if h.is_svn(repo):
84 84 return _format_ref_id_svn
85 85 else:
86 86 return _format_ref_id
87 87
88 88
89 89 def _format_ref_id(name, raw_id):
90 90 """Default formatting of a given reference `name`"""
91 91 return name
92 92
93 93
94 94 def _format_ref_id_svn(name, raw_id):
95 95 """Special way of formatting a reference for Subversion including path"""
96 96 return '%s@%s' % (name, raw_id)
97 97
98 98
99 99 class TemplateArgs(StrictAttributeDict):
100 100 pass
101 101
102 102
103 103 class BaseAppView(object):
104 104
105 105 def __init__(self, context, request):
106 106 self.request = request
107 107 self.context = context
108 108 self.session = request.session
109 109 if not hasattr(request, 'user'):
110 110 # NOTE(marcink): edge case, we ended up in matched route
111 111 # but probably of web-app context, e.g API CALL/VCS CALL
112 112 if hasattr(request, 'vcs_call') or hasattr(request, 'rpc_method'):
113 113 log.warning('Unable to process request `%s` in this scope', request)
114 114 raise HTTPBadRequest()
115 115
116 116 self._rhodecode_user = request.user # auth user
117 117 self._rhodecode_db_user = self._rhodecode_user.get_instance()
118 118 self._maybe_needs_password_change(
119 119 request.matched_route.name, self._rhodecode_db_user)
120 120
121 121 def _maybe_needs_password_change(self, view_name, user_obj):
122
123 dont_check_views = [
124 'channelstream_connect'
125 ]
126 if view_name in dont_check_views:
127 return
128
122 129 log.debug('Checking if user %s needs password change on view %s',
123 130 user_obj, view_name)
131
124 132 skip_user_views = [
125 133 'logout', 'login',
126 134 'my_account_password', 'my_account_password_update'
127 135 ]
128 136
129 137 if not user_obj:
130 138 return
131 139
132 140 if user_obj.username == User.DEFAULT_USER:
133 141 return
134 142
135 143 now = time.time()
136 144 should_change = user_obj.user_data.get('force_password_change')
137 145 change_after = safe_int(should_change) or 0
138 146 if should_change and now > change_after:
139 147 log.debug('User %s requires password change', user_obj)
140 148 h.flash('You are required to change your password', 'warning',
141 149 ignore_duplicate=True)
142 150
143 151 if view_name not in skip_user_views:
144 152 raise HTTPFound(
145 153 self.request.route_path('my_account_password'))
146 154
147 155 def _log_creation_exception(self, e, repo_name):
148 156 _ = self.request.translate
149 157 reason = None
150 158 if len(e.args) == 2:
151 159 reason = e.args[1]
152 160
153 161 if reason == 'INVALID_CERTIFICATE':
154 162 log.exception(
155 163 'Exception creating a repository: invalid certificate')
156 164 msg = (_('Error creating repository %s: invalid certificate')
157 165 % repo_name)
158 166 else:
159 167 log.exception("Exception creating a repository")
160 168 msg = (_('Error creating repository %s')
161 169 % repo_name)
162 170 return msg
163 171
164 172 def _get_local_tmpl_context(self, include_app_defaults=True):
165 173 c = TemplateArgs()
166 174 c.auth_user = self.request.user
167 175 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
168 176 c.rhodecode_user = self.request.user
169 177
170 178 if include_app_defaults:
171 179 from rhodecode.lib.base import attach_context_attributes
172 180 attach_context_attributes(c, self.request, self.request.user.user_id)
173 181
174 182 c.is_super_admin = c.auth_user.is_admin
175 183
176 184 c.can_create_repo = c.is_super_admin
177 185 c.can_create_repo_group = c.is_super_admin
178 186 c.can_create_user_group = c.is_super_admin
179 187
180 188 c.is_delegated_admin = False
181 189
182 190 if not c.auth_user.is_default and not c.is_super_admin:
183 191 c.can_create_repo = h.HasPermissionAny('hg.create.repository')(
184 192 user=self.request.user)
185 193 repositories = c.auth_user.repositories_admin or c.can_create_repo
186 194
187 195 c.can_create_repo_group = h.HasPermissionAny('hg.repogroup.create.true')(
188 196 user=self.request.user)
189 197 repository_groups = c.auth_user.repository_groups_admin or c.can_create_repo_group
190 198
191 199 c.can_create_user_group = h.HasPermissionAny('hg.usergroup.create.true')(
192 200 user=self.request.user)
193 201 user_groups = c.auth_user.user_groups_admin or c.can_create_user_group
194 202 # delegated admin can create, or manage some objects
195 203 c.is_delegated_admin = repositories or repository_groups or user_groups
196 204 return c
197 205
198 206 def _get_template_context(self, tmpl_args, **kwargs):
199 207
200 208 local_tmpl_args = {
201 209 'defaults': {},
202 210 'errors': {},
203 211 'c': tmpl_args
204 212 }
205 213 local_tmpl_args.update(kwargs)
206 214 return local_tmpl_args
207 215
208 216 def load_default_context(self):
209 217 """
210 218 example:
211 219
212 220 def load_default_context(self):
213 221 c = self._get_local_tmpl_context()
214 222 c.custom_var = 'foobar'
215 223
216 224 return c
217 225 """
218 226 raise NotImplementedError('Needs implementation in view class')
219 227
220 228
221 229 class RepoAppView(BaseAppView):
222 230
223 231 def __init__(self, context, request):
224 232 super(RepoAppView, self).__init__(context, request)
225 233 self.db_repo = request.db_repo
226 234 self.db_repo_name = self.db_repo.repo_name
227 235 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
228 236 self.db_repo_artifacts = ScmModel().get_artifacts(self.db_repo)
229 237 self.db_repo_patterns = IssueTrackerSettingsModel(repo=self.db_repo)
230 238
231 239 def _handle_missing_requirements(self, error):
232 240 log.error(
233 241 'Requirements are missing for repository %s: %s',
234 242 self.db_repo_name, safe_unicode(error))
235 243
236 244 def _get_local_tmpl_context(self, include_app_defaults=True):
237 245 _ = self.request.translate
238 246 c = super(RepoAppView, self)._get_local_tmpl_context(
239 247 include_app_defaults=include_app_defaults)
240 248
241 249 # register common vars for this type of view
242 250 c.rhodecode_db_repo = self.db_repo
243 251 c.repo_name = self.db_repo_name
244 252 c.repository_pull_requests = self.db_repo_pull_requests
245 253 c.repository_artifacts = self.db_repo_artifacts
246 254 c.repository_is_user_following = ScmModel().is_following_repo(
247 255 self.db_repo_name, self._rhodecode_user.user_id)
248 256 self.path_filter = PathFilter(None)
249 257
250 258 c.repository_requirements_missing = {}
251 259 try:
252 260 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
253 261 # NOTE(marcink):
254 262 # comparison to None since if it's an object __bool__ is expensive to
255 263 # calculate
256 264 if self.rhodecode_vcs_repo is not None:
257 265 path_perms = self.rhodecode_vcs_repo.get_path_permissions(
258 266 c.auth_user.username)
259 267 self.path_filter = PathFilter(path_perms)
260 268 except RepositoryRequirementError as e:
261 269 c.repository_requirements_missing = {'error': str(e)}
262 270 self._handle_missing_requirements(e)
263 271 self.rhodecode_vcs_repo = None
264 272
265 273 c.path_filter = self.path_filter # used by atom_feed_entry.mako
266 274
267 275 if self.rhodecode_vcs_repo is None:
268 276 # unable to fetch this repo as vcs instance, report back to user
269 277 h.flash(_(
270 278 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
271 279 "Please check if it exist, or is not damaged.") %
272 280 {'repo_name': c.repo_name},
273 281 category='error', ignore_duplicate=True)
274 282 if c.repository_requirements_missing:
275 283 route = self.request.matched_route.name
276 284 if route.startswith(('edit_repo', 'repo_summary')):
277 285 # allow summary and edit repo on missing requirements
278 286 return c
279 287
280 288 raise HTTPFound(
281 289 h.route_path('repo_summary', repo_name=self.db_repo_name))
282 290
283 291 else: # redirect if we don't show missing requirements
284 292 raise HTTPFound(h.route_path('home'))
285 293
286 294 c.has_origin_repo_read_perm = False
287 295 if self.db_repo.fork:
288 296 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
289 297 'repository.write', 'repository.read', 'repository.admin')(
290 298 self.db_repo.fork.repo_name, 'summary fork link')
291 299
292 300 return c
293 301
294 302 def _get_f_path_unchecked(self, matchdict, default=None):
295 303 """
296 304 Should only be used by redirects, everything else should call _get_f_path
297 305 """
298 306 f_path = matchdict.get('f_path')
299 307 if f_path:
300 308 # fix for multiple initial slashes that causes errors for GIT
301 309 return f_path.lstrip('/')
302 310
303 311 return default
304 312
305 313 def _get_f_path(self, matchdict, default=None):
306 314 f_path_match = self._get_f_path_unchecked(matchdict, default)
307 315 return self.path_filter.assert_path_permissions(f_path_match)
308 316
309 317 def _get_general_setting(self, target_repo, settings_key, default=False):
310 318 settings_model = VcsSettingsModel(repo=target_repo)
311 319 settings = settings_model.get_general_settings()
312 320 return settings.get(settings_key, default)
313 321
314 322 def _get_repo_setting(self, target_repo, settings_key, default=False):
315 323 settings_model = VcsSettingsModel(repo=target_repo)
316 324 settings = settings_model.get_repo_settings_inherited()
317 325 return settings.get(settings_key, default)
318 326
319 327 def _get_readme_data(self, db_repo, renderer_type, commit_id=None, path='/'):
320 328 log.debug('Looking for README file at path %s', path)
321 329 if commit_id:
322 330 landing_commit_id = commit_id
323 331 else:
324 332 landing_commit = db_repo.get_landing_commit()
325 333 if isinstance(landing_commit, EmptyCommit):
326 334 return None, None
327 335 landing_commit_id = landing_commit.raw_id
328 336
329 337 cache_namespace_uid = 'cache_repo.{}'.format(db_repo.repo_id)
330 338 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
331 339 start = time.time()
332 340
333 341 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
334 342 def generate_repo_readme(repo_id, _commit_id, _repo_name, _readme_search_path, _renderer_type):
335 343 readme_data = None
336 344 readme_filename = None
337 345
338 346 commit = db_repo.get_commit(_commit_id)
339 347 log.debug("Searching for a README file at commit %s.", _commit_id)
340 348 readme_node = ReadmeFinder(_renderer_type).search(commit, path=_readme_search_path)
341 349
342 350 if readme_node:
343 351 log.debug('Found README node: %s', readme_node)
344 352 relative_urls = {
345 353 'raw': h.route_path(
346 354 'repo_file_raw', repo_name=_repo_name,
347 355 commit_id=commit.raw_id, f_path=readme_node.path),
348 356 'standard': h.route_path(
349 357 'repo_files', repo_name=_repo_name,
350 358 commit_id=commit.raw_id, f_path=readme_node.path),
351 359 }
352 360 readme_data = self._render_readme_or_none(commit, readme_node, relative_urls)
353 361 readme_filename = readme_node.unicode_path
354 362
355 363 return readme_data, readme_filename
356 364
357 365 readme_data, readme_filename = generate_repo_readme(
358 366 db_repo.repo_id, landing_commit_id, db_repo.repo_name, path, renderer_type,)
359 367 compute_time = time.time() - start
360 368 log.debug('Repo README for path %s generated and computed in %.4fs',
361 369 path, compute_time)
362 370 return readme_data, readme_filename
363 371
364 372 def _render_readme_or_none(self, commit, readme_node, relative_urls):
365 373 log.debug('Found README file `%s` rendering...', readme_node.path)
366 374 renderer = MarkupRenderer()
367 375 try:
368 376 html_source = renderer.render(
369 377 readme_node.content, filename=readme_node.path)
370 378 if relative_urls:
371 379 return relative_links(html_source, relative_urls)
372 380 return html_source
373 381 except Exception:
374 382 log.exception(
375 383 "Exception while trying to render the README")
376 384
377 385 def get_recache_flag(self):
378 386 for flag_name in ['force_recache', 'force-recache', 'no-cache']:
379 387 flag_val = self.request.GET.get(flag_name)
380 388 if str2bool(flag_val):
381 389 return True
382 390 return False
383 391
384 392
385 393 class PathFilter(object):
386 394
387 395 # Expects and instance of BasePathPermissionChecker or None
388 396 def __init__(self, permission_checker):
389 397 self.permission_checker = permission_checker
390 398
391 399 def assert_path_permissions(self, path):
392 400 if self.path_access_allowed(path):
393 401 return path
394 402 raise HTTPForbidden()
395 403
396 404 def path_access_allowed(self, path):
397 405 log.debug('Checking ACL permissions for PathFilter for `%s`', path)
398 406 if self.permission_checker:
399 407 has_access = path and self.permission_checker.has_access(path)
400 408 log.debug('ACL Permissions checker enabled, ACL Check has_access: %s', has_access)
401 409 return has_access
402 410
403 411 log.debug('ACL permissions checker not enabled, skipping...')
404 412 return True
405 413
406 414 def filter_patchset(self, patchset):
407 415 if not self.permission_checker or not patchset:
408 416 return patchset, False
409 417 had_filtered = False
410 418 filtered_patchset = []
411 419 for patch in patchset:
412 420 filename = patch.get('filename', None)
413 421 if not filename or self.permission_checker.has_access(filename):
414 422 filtered_patchset.append(patch)
415 423 else:
416 424 had_filtered = True
417 425 if had_filtered:
418 426 if isinstance(patchset, diffs.LimitedDiffContainer):
419 427 filtered_patchset = diffs.LimitedDiffContainer(patchset.diff_limit, patchset.cur_diff_size, filtered_patchset)
420 428 return filtered_patchset, True
421 429 else:
422 430 return patchset, False
423 431
424 432 def render_patchset_filtered(self, diffset, patchset, source_ref=None, target_ref=None):
425 433 filtered_patchset, has_hidden_changes = self.filter_patchset(patchset)
426 434 result = diffset.render_patchset(
427 435 filtered_patchset, source_ref=source_ref, target_ref=target_ref)
428 436 result.has_hidden_changes = has_hidden_changes
429 437 return result
430 438
431 439 def get_raw_patch(self, diff_processor):
432 440 if self.permission_checker is None:
433 441 return diff_processor.as_raw()
434 442 elif self.permission_checker.has_full_access:
435 443 return diff_processor.as_raw()
436 444 else:
437 445 return '# Repository has user-specific filters, raw patch generation is disabled.'
438 446
439 447 @property
440 448 def is_enabled(self):
441 449 return self.permission_checker is not None
442 450
443 451
444 452 class RepoGroupAppView(BaseAppView):
445 453 def __init__(self, context, request):
446 454 super(RepoGroupAppView, self).__init__(context, request)
447 455 self.db_repo_group = request.db_repo_group
448 456 self.db_repo_group_name = self.db_repo_group.group_name
449 457
450 458 def _get_local_tmpl_context(self, include_app_defaults=True):
451 459 _ = self.request.translate
452 460 c = super(RepoGroupAppView, self)._get_local_tmpl_context(
453 461 include_app_defaults=include_app_defaults)
454 462 c.repo_group = self.db_repo_group
455 463 return c
456 464
457 465 def _revoke_perms_on_yourself(self, form_result):
458 466 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
459 467 form_result['perm_updates'])
460 468 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
461 469 form_result['perm_additions'])
462 470 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
463 471 form_result['perm_deletions'])
464 472 admin_perm = 'group.admin'
465 473 if _updates and _updates[0][1] != admin_perm or \
466 474 _additions and _additions[0][1] != admin_perm or \
467 475 _deletions and _deletions[0][1] != admin_perm:
468 476 return True
469 477 return False
470 478
471 479
472 480 class UserGroupAppView(BaseAppView):
473 481 def __init__(self, context, request):
474 482 super(UserGroupAppView, self).__init__(context, request)
475 483 self.db_user_group = request.db_user_group
476 484 self.db_user_group_name = self.db_user_group.users_group_name
477 485
478 486
479 487 class UserAppView(BaseAppView):
480 488 def __init__(self, context, request):
481 489 super(UserAppView, self).__init__(context, request)
482 490 self.db_user = request.db_user
483 491 self.db_user_id = self.db_user.user_id
484 492
485 493 _ = self.request.translate
486 494 if not request.db_user_supports_default:
487 495 if self.db_user.username == User.DEFAULT_USER:
488 496 h.flash(_("Editing user `{}` is disabled.".format(
489 497 User.DEFAULT_USER)), category='warning')
490 498 raise HTTPFound(h.route_path('users'))
491 499
492 500
493 501 class DataGridAppView(object):
494 502 """
495 503 Common class to have re-usable grid rendering components
496 504 """
497 505
498 506 def _extract_ordering(self, request, column_map=None):
499 507 column_map = column_map or {}
500 508 column_index = safe_int(request.GET.get('order[0][column]'))
501 509 order_dir = request.GET.get(
502 510 'order[0][dir]', 'desc')
503 511 order_by = request.GET.get(
504 512 'columns[%s][data][sort]' % column_index, 'name_raw')
505 513
506 514 # translate datatable to DB columns
507 515 order_by = column_map.get(order_by) or order_by
508 516
509 517 search_q = request.GET.get('search[value]')
510 518 return search_q, order_by, order_dir
511 519
512 520 def _extract_chunk(self, request):
513 521 start = safe_int(request.GET.get('start'), 0)
514 522 length = safe_int(request.GET.get('length'), 25)
515 523 draw = safe_int(request.GET.get('draw'))
516 524 return draw, start, length
517 525
518 526 def _get_order_col(self, order_by, model):
519 527 if isinstance(order_by, compat.string_types):
520 528 try:
521 529 return operator.attrgetter(order_by)(model)
522 530 except AttributeError:
523 531 return None
524 532 else:
525 533 return order_by
526 534
527 535
528 536 class BaseReferencesView(RepoAppView):
529 537 """
530 538 Base for reference view for branches, tags and bookmarks.
531 539 """
532 540 def load_default_context(self):
533 541 c = self._get_local_tmpl_context()
534 542 return c
535 543
536 544 def load_refs_context(self, ref_items, partials_template):
537 545 _render = self.request.get_partial_renderer(partials_template)
538 546 pre_load = ["author", "date", "message", "parents"]
539 547
540 548 is_svn = h.is_svn(self.rhodecode_vcs_repo)
541 549 is_hg = h.is_hg(self.rhodecode_vcs_repo)
542 550
543 551 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
544 552
545 553 closed_refs = {}
546 554 if is_hg:
547 555 closed_refs = self.rhodecode_vcs_repo.branches_closed
548 556
549 557 data = []
550 558 for ref_name, commit_id in ref_items:
551 559 commit = self.rhodecode_vcs_repo.get_commit(
552 560 commit_id=commit_id, pre_load=pre_load)
553 561 closed = ref_name in closed_refs
554 562
555 563 # TODO: johbo: Unify generation of reference links
556 564 use_commit_id = '/' in ref_name or is_svn
557 565
558 566 if use_commit_id:
559 567 files_url = h.route_path(
560 568 'repo_files',
561 569 repo_name=self.db_repo_name,
562 570 f_path=ref_name if is_svn else '',
563 571 commit_id=commit_id,
564 572 _query=dict(at=ref_name)
565 573 )
566 574
567 575 else:
568 576 files_url = h.route_path(
569 577 'repo_files',
570 578 repo_name=self.db_repo_name,
571 579 f_path=ref_name if is_svn else '',
572 580 commit_id=ref_name,
573 581 _query=dict(at=ref_name)
574 582 )
575 583
576 584 data.append({
577 585 "name": _render('name', ref_name, files_url, closed),
578 586 "name_raw": ref_name,
579 587 "date": _render('date', commit.date),
580 588 "date_raw": datetime_to_time(commit.date),
581 589 "author": _render('author', commit.author),
582 590 "commit": _render(
583 591 'commit', commit.message, commit.raw_id, commit.idx),
584 592 "commit_raw": commit.idx,
585 593 "compare": _render(
586 594 'compare', format_ref_id(ref_name, commit.raw_id)),
587 595 })
588 596
589 597 return data
590 598
591 599
592 600 class RepoRoutePredicate(object):
593 601 def __init__(self, val, config):
594 602 self.val = val
595 603
596 604 def text(self):
597 605 return 'repo_route = %s' % self.val
598 606
599 607 phash = text
600 608
601 609 def __call__(self, info, request):
602 610 if hasattr(request, 'vcs_call'):
603 611 # skip vcs calls
604 612 return
605 613
606 614 repo_name = info['match']['repo_name']
607 615 repo_model = repo.RepoModel()
608 616
609 617 by_name_match = repo_model.get_by_repo_name(repo_name, cache=False)
610 618
611 619 def redirect_if_creating(route_info, db_repo):
612 620 skip_views = ['edit_repo_advanced_delete']
613 621 route = route_info['route']
614 622 # we should skip delete view so we can actually "remove" repositories
615 623 # if they get stuck in creating state.
616 624 if route.name in skip_views:
617 625 return
618 626
619 627 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
620 628 repo_creating_url = request.route_path(
621 629 'repo_creating', repo_name=db_repo.repo_name)
622 630 raise HTTPFound(repo_creating_url)
623 631
624 632 if by_name_match:
625 633 # register this as request object we can re-use later
626 634 request.db_repo = by_name_match
627 635 redirect_if_creating(info, by_name_match)
628 636 return True
629 637
630 638 by_id_match = repo_model.get_repo_by_id(repo_name)
631 639 if by_id_match:
632 640 request.db_repo = by_id_match
633 641 redirect_if_creating(info, by_id_match)
634 642 return True
635 643
636 644 return False
637 645
638 646
639 647 class RepoForbidArchivedRoutePredicate(object):
640 648 def __init__(self, val, config):
641 649 self.val = val
642 650
643 651 def text(self):
644 652 return 'repo_forbid_archived = %s' % self.val
645 653
646 654 phash = text
647 655
648 656 def __call__(self, info, request):
649 657 _ = request.translate
650 658 rhodecode_db_repo = request.db_repo
651 659
652 660 log.debug(
653 661 '%s checking if archived flag for repo for %s',
654 662 self.__class__.__name__, rhodecode_db_repo.repo_name)
655 663
656 664 if rhodecode_db_repo.archived:
657 665 log.warning('Current view is not supported for archived repo:%s',
658 666 rhodecode_db_repo.repo_name)
659 667
660 668 h.flash(
661 669 h.literal(_('Action not supported for archived repository.')),
662 670 category='warning')
663 671 summary_url = request.route_path(
664 672 'repo_summary', repo_name=rhodecode_db_repo.repo_name)
665 673 raise HTTPFound(summary_url)
666 674 return True
667 675
668 676
669 677 class RepoTypeRoutePredicate(object):
670 678 def __init__(self, val, config):
671 679 self.val = val or ['hg', 'git', 'svn']
672 680
673 681 def text(self):
674 682 return 'repo_accepted_type = %s' % self.val
675 683
676 684 phash = text
677 685
678 686 def __call__(self, info, request):
679 687 if hasattr(request, 'vcs_call'):
680 688 # skip vcs calls
681 689 return
682 690
683 691 rhodecode_db_repo = request.db_repo
684 692
685 693 log.debug(
686 694 '%s checking repo type for %s in %s',
687 695 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
688 696
689 697 if rhodecode_db_repo.repo_type in self.val:
690 698 return True
691 699 else:
692 700 log.warning('Current view is not supported for repo type:%s',
693 701 rhodecode_db_repo.repo_type)
694 702 return False
695 703
696 704
697 705 class RepoGroupRoutePredicate(object):
698 706 def __init__(self, val, config):
699 707 self.val = val
700 708
701 709 def text(self):
702 710 return 'repo_group_route = %s' % self.val
703 711
704 712 phash = text
705 713
706 714 def __call__(self, info, request):
707 715 if hasattr(request, 'vcs_call'):
708 716 # skip vcs calls
709 717 return
710 718
711 719 repo_group_name = info['match']['repo_group_name']
712 720 repo_group_model = repo_group.RepoGroupModel()
713 721 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
714 722
715 723 if by_name_match:
716 724 # register this as request object we can re-use later
717 725 request.db_repo_group = by_name_match
718 726 return True
719 727
720 728 return False
721 729
722 730
723 731 class UserGroupRoutePredicate(object):
724 732 def __init__(self, val, config):
725 733 self.val = val
726 734
727 735 def text(self):
728 736 return 'user_group_route = %s' % self.val
729 737
730 738 phash = text
731 739
732 740 def __call__(self, info, request):
733 741 if hasattr(request, 'vcs_call'):
734 742 # skip vcs calls
735 743 return
736 744
737 745 user_group_id = info['match']['user_group_id']
738 746 user_group_model = user_group.UserGroup()
739 747 by_id_match = user_group_model.get(user_group_id, cache=False)
740 748
741 749 if by_id_match:
742 750 # register this as request object we can re-use later
743 751 request.db_user_group = by_id_match
744 752 return True
745 753
746 754 return False
747 755
748 756
749 757 class UserRoutePredicateBase(object):
750 758 supports_default = None
751 759
752 760 def __init__(self, val, config):
753 761 self.val = val
754 762
755 763 def text(self):
756 764 raise NotImplementedError()
757 765
758 766 def __call__(self, info, request):
759 767 if hasattr(request, 'vcs_call'):
760 768 # skip vcs calls
761 769 return
762 770
763 771 user_id = info['match']['user_id']
764 772 user_model = user.User()
765 773 by_id_match = user_model.get(user_id, cache=False)
766 774
767 775 if by_id_match:
768 776 # register this as request object we can re-use later
769 777 request.db_user = by_id_match
770 778 request.db_user_supports_default = self.supports_default
771 779 return True
772 780
773 781 return False
774 782
775 783
776 784 class UserRoutePredicate(UserRoutePredicateBase):
777 785 supports_default = False
778 786
779 787 def text(self):
780 788 return 'user_route = %s' % self.val
781 789
782 790 phash = text
783 791
784 792
785 793 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
786 794 supports_default = True
787 795
788 796 def text(self):
789 797 return 'user_with_default_route = %s' % self.val
790 798
791 799 phash = text
792 800
793 801
794 802 def includeme(config):
795 803 config.add_route_predicate(
796 804 'repo_route', RepoRoutePredicate)
797 805 config.add_route_predicate(
798 806 'repo_accepted_types', RepoTypeRoutePredicate)
799 807 config.add_route_predicate(
800 808 'repo_forbid_when_archived', RepoForbidArchivedRoutePredicate)
801 809 config.add_route_predicate(
802 810 'repo_group_route', RepoGroupRoutePredicate)
803 811 config.add_route_predicate(
804 812 'user_group_route', UserGroupRoutePredicate)
805 813 config.add_route_predicate(
806 814 'user_route_with_default', UserRouteWithDefaultPredicate)
807 815 config.add_route_predicate(
808 816 'user_route', UserRoutePredicate)
General Comments 0
You need to be logged in to leave comments. Login now