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