##// END OF EJS Templates
logging: expose logs when not mapped repo is found
super-admin -
r4844:ca029735 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 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.utils import repo_name_slug
30 30 from rhodecode.lib.utils2 import (
31 31 StrictAttributeDict, str2bool, safe_int, datetime_to_time, safe_unicode)
32 32 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
33 33 from rhodecode.lib.vcs.backends.base import EmptyCommit
34 34 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
35 35 from rhodecode.model import repo
36 36 from rhodecode.model import repo_group
37 37 from rhodecode.model import user_group
38 38 from rhodecode.model import user
39 39 from rhodecode.model.db import User
40 40 from rhodecode.model.scm import ScmModel
41 41 from rhodecode.model.settings import VcsSettingsModel, IssueTrackerSettingsModel
42 42 from rhodecode.model.repo import ReadmeFinder
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46
47 47 ADMIN_PREFIX = '/_admin'
48 48 STATIC_FILE_PREFIX = '/_static'
49 49
50 50 URL_NAME_REQUIREMENTS = {
51 51 # group name can have a slash in them, but they must not end with a slash
52 52 'group_name': r'.*?[^/]',
53 53 'repo_group_name': r'.*?[^/]',
54 54 # repo names can have a slash in them, but they must not end with a slash
55 55 'repo_name': r'.*?[^/]',
56 56 # file path eats up everything at the end
57 57 'f_path': r'.*',
58 58 # reference types
59 59 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
60 60 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
61 61 }
62 62
63 63
64 64 def add_route_with_slash(config,name, pattern, **kw):
65 65 config.add_route(name, pattern, **kw)
66 66 if not pattern.endswith('/'):
67 67 config.add_route(name + '_slash', pattern + '/', **kw)
68 68
69 69
70 70 def add_route_requirements(route_path, requirements=None):
71 71 """
72 72 Adds regex requirements to pyramid routes using a mapping dict
73 73 e.g::
74 74 add_route_requirements('{repo_name}/settings')
75 75 """
76 76 requirements = requirements or URL_NAME_REQUIREMENTS
77 77 for key, regex in requirements.items():
78 78 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
79 79 return route_path
80 80
81 81
82 82 def get_format_ref_id(repo):
83 83 """Returns a `repo` specific reference formatter function"""
84 84 if h.is_svn(repo):
85 85 return _format_ref_id_svn
86 86 else:
87 87 return _format_ref_id
88 88
89 89
90 90 def _format_ref_id(name, raw_id):
91 91 """Default formatting of a given reference `name`"""
92 92 return name
93 93
94 94
95 95 def _format_ref_id_svn(name, raw_id):
96 96 """Special way of formatting a reference for Subversion including path"""
97 97 return '%s@%s' % (name, raw_id)
98 98
99 99
100 100 class TemplateArgs(StrictAttributeDict):
101 101 pass
102 102
103 103
104 104 class BaseAppView(object):
105 105
106 106 def __init__(self, context, request):
107 107 self.request = request
108 108 self.context = context
109 109 self.session = request.session
110 110 if not hasattr(request, 'user'):
111 111 # NOTE(marcink): edge case, we ended up in matched route
112 112 # but probably of web-app context, e.g API CALL/VCS CALL
113 113 if hasattr(request, 'vcs_call') or hasattr(request, 'rpc_method'):
114 114 log.warning('Unable to process request `%s` in this scope', request)
115 115 raise HTTPBadRequest()
116 116
117 117 self._rhodecode_user = request.user # auth user
118 118 self._rhodecode_db_user = self._rhodecode_user.get_instance()
119 119 self._maybe_needs_password_change(
120 120 request.matched_route.name, self._rhodecode_db_user)
121 121
122 122 def _maybe_needs_password_change(self, view_name, user_obj):
123 123
124 124 dont_check_views = [
125 125 'channelstream_connect'
126 126 ]
127 127 if view_name in dont_check_views:
128 128 return
129 129
130 130 log.debug('Checking if user %s needs password change on view %s',
131 131 user_obj, view_name)
132 132
133 133 skip_user_views = [
134 134 'logout', 'login',
135 135 'my_account_password', 'my_account_password_update'
136 136 ]
137 137
138 138 if not user_obj:
139 139 return
140 140
141 141 if user_obj.username == User.DEFAULT_USER:
142 142 return
143 143
144 144 now = time.time()
145 145 should_change = user_obj.user_data.get('force_password_change')
146 146 change_after = safe_int(should_change) or 0
147 147 if should_change and now > change_after:
148 148 log.debug('User %s requires password change', user_obj)
149 149 h.flash('You are required to change your password', 'warning',
150 150 ignore_duplicate=True)
151 151
152 152 if view_name not in skip_user_views:
153 153 raise HTTPFound(
154 154 self.request.route_path('my_account_password'))
155 155
156 156 def _log_creation_exception(self, e, repo_name):
157 157 _ = self.request.translate
158 158 reason = None
159 159 if len(e.args) == 2:
160 160 reason = e.args[1]
161 161
162 162 if reason == 'INVALID_CERTIFICATE':
163 163 log.exception(
164 164 'Exception creating a repository: invalid certificate')
165 165 msg = (_('Error creating repository %s: invalid certificate')
166 166 % repo_name)
167 167 else:
168 168 log.exception("Exception creating a repository")
169 169 msg = (_('Error creating repository %s')
170 170 % repo_name)
171 171 return msg
172 172
173 173 def _get_local_tmpl_context(self, include_app_defaults=True):
174 174 c = TemplateArgs()
175 175 c.auth_user = self.request.user
176 176 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
177 177 c.rhodecode_user = self.request.user
178 178
179 179 if include_app_defaults:
180 180 from rhodecode.lib.base import attach_context_attributes
181 181 attach_context_attributes(c, self.request, self.request.user.user_id)
182 182
183 183 c.is_super_admin = c.auth_user.is_admin
184 184
185 185 c.can_create_repo = c.is_super_admin
186 186 c.can_create_repo_group = c.is_super_admin
187 187 c.can_create_user_group = c.is_super_admin
188 188
189 189 c.is_delegated_admin = False
190 190
191 191 if not c.auth_user.is_default and not c.is_super_admin:
192 192 c.can_create_repo = h.HasPermissionAny('hg.create.repository')(
193 193 user=self.request.user)
194 194 repositories = c.auth_user.repositories_admin or c.can_create_repo
195 195
196 196 c.can_create_repo_group = h.HasPermissionAny('hg.repogroup.create.true')(
197 197 user=self.request.user)
198 198 repository_groups = c.auth_user.repository_groups_admin or c.can_create_repo_group
199 199
200 200 c.can_create_user_group = h.HasPermissionAny('hg.usergroup.create.true')(
201 201 user=self.request.user)
202 202 user_groups = c.auth_user.user_groups_admin or c.can_create_user_group
203 203 # delegated admin can create, or manage some objects
204 204 c.is_delegated_admin = repositories or repository_groups or user_groups
205 205 return c
206 206
207 207 def _get_template_context(self, tmpl_args, **kwargs):
208 208
209 209 local_tmpl_args = {
210 210 'defaults': {},
211 211 'errors': {},
212 212 'c': tmpl_args
213 213 }
214 214 local_tmpl_args.update(kwargs)
215 215 return local_tmpl_args
216 216
217 217 def load_default_context(self):
218 218 """
219 219 example:
220 220
221 221 def load_default_context(self):
222 222 c = self._get_local_tmpl_context()
223 223 c.custom_var = 'foobar'
224 224
225 225 return c
226 226 """
227 227 raise NotImplementedError('Needs implementation in view class')
228 228
229 229
230 230 class RepoAppView(BaseAppView):
231 231
232 232 def __init__(self, context, request):
233 233 super(RepoAppView, self).__init__(context, request)
234 234 self.db_repo = request.db_repo
235 235 self.db_repo_name = self.db_repo.repo_name
236 236 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
237 237 self.db_repo_artifacts = ScmModel().get_artifacts(self.db_repo)
238 238 self.db_repo_patterns = IssueTrackerSettingsModel(repo=self.db_repo)
239 239
240 240 def _handle_missing_requirements(self, error):
241 241 log.error(
242 242 'Requirements are missing for repository %s: %s',
243 243 self.db_repo_name, safe_unicode(error))
244 244
245 245 def _get_local_tmpl_context(self, include_app_defaults=True):
246 246 _ = self.request.translate
247 247 c = super(RepoAppView, self)._get_local_tmpl_context(
248 248 include_app_defaults=include_app_defaults)
249 249
250 250 # register common vars for this type of view
251 251 c.rhodecode_db_repo = self.db_repo
252 252 c.repo_name = self.db_repo_name
253 253 c.repository_pull_requests = self.db_repo_pull_requests
254 254 c.repository_artifacts = self.db_repo_artifacts
255 255 c.repository_is_user_following = ScmModel().is_following_repo(
256 256 self.db_repo_name, self._rhodecode_user.user_id)
257 257 self.path_filter = PathFilter(None)
258 258
259 259 c.repository_requirements_missing = {}
260 260 try:
261 261 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
262 262 # NOTE(marcink):
263 263 # comparison to None since if it's an object __bool__ is expensive to
264 264 # calculate
265 265 if self.rhodecode_vcs_repo is not None:
266 266 path_perms = self.rhodecode_vcs_repo.get_path_permissions(
267 267 c.auth_user.username)
268 268 self.path_filter = PathFilter(path_perms)
269 269 except RepositoryRequirementError as e:
270 270 c.repository_requirements_missing = {'error': str(e)}
271 271 self._handle_missing_requirements(e)
272 272 self.rhodecode_vcs_repo = None
273 273
274 274 c.path_filter = self.path_filter # used by atom_feed_entry.mako
275 275
276 276 if self.rhodecode_vcs_repo is None:
277 277 # unable to fetch this repo as vcs instance, report back to user
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, compat.string_types):
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