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