##// 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
@@ -1,858 +1,947 b''
1 # Copyright (C) 2016-2023 RhodeCode GmbH
1 # Copyright (C) 2016-2023 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 import time
19 import time
20 import logging
20 import logging
21 import operator
21 import operator
22
22
23 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPBadRequest
23 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPBadRequest
24
24
25 from rhodecode.lib import helpers as h, diffs, rc_cache
25 from rhodecode.lib import helpers as h, diffs, rc_cache
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
33 from rhodecode.model import repo
37 from rhodecode.model import repo
34 from rhodecode.model import repo_group
38 from rhodecode.model import repo_group
35 from rhodecode.model import user_group
39 from rhodecode.model import user_group
36 from rhodecode.model import user
40 from rhodecode.model import user
37 from rhodecode.model.db import User
41 from rhodecode.model.db import User
38 from rhodecode.model.scm import ScmModel
42 from rhodecode.model.scm import ScmModel
39 from rhodecode.model.settings import VcsSettingsModel, IssueTrackerSettingsModel
43 from rhodecode.model.settings import VcsSettingsModel, IssueTrackerSettingsModel
40 from rhodecode.model.repo import ReadmeFinder
44 from rhodecode.model.repo import ReadmeFinder
41
45
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):
69 """
73 """
70 Adds regex requirements to pyramid routes using a mapping dict
74 Adds regex requirements to pyramid routes using a mapping dict
71 e.g::
75 e.g::
72 add_route_requirements('{repo_name}/settings')
76 add_route_requirements('{repo_name}/settings')
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
80 def get_format_ref_id(repo):
84 def get_format_ref_id(repo):
81 """Returns a `repo` specific reference formatter function"""
85 """Returns a `repo` specific reference formatter function"""
82 if h.is_svn(repo):
86 if h.is_svn(repo):
83 return _format_ref_id_svn
87 return _format_ref_id_svn
84 else:
88 else:
85 return _format_ref_id
89 return _format_ref_id
86
90
87
91
88 def _format_ref_id(name, raw_id):
92 def _format_ref_id(name, raw_id):
89 """Default formatting of a given reference `name`"""
93 """Default formatting of a given reference `name`"""
90 return name
94 return name
91
95
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):
99 pass
103 pass
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:
138 return
141 return
139
142
140 if user_obj.username == User.DEFAULT_USER:
143 if user_obj.username == User.DEFAULT_USER:
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
157 reason = None
162 reason = None
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):
173 c = TemplateArgs()
175 c = TemplateArgs()
174 c.auth_user = self.request.user
176 c.auth_user = self.request.user
175 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
177 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
176 c.rhodecode_user = self.request.user
178 c.rhodecode_user = self.request.user
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
183
186
184 c.can_create_repo = c.is_super_admin
187 c.can_create_repo = c.is_super_admin
185 c.can_create_repo_group = c.is_super_admin
188 c.can_create_repo_group = c.is_super_admin
186 c.can_create_user_group = c.is_super_admin
189 c.can_create_user_group = c.is_super_admin
187
190
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
216 def load_default_context(self):
219 def load_default_context(self):
217 """
220 """
218 example:
221 example:
219
222
220 def load_default_context(self):
223 def load_default_context(self):
221 c = self._get_local_tmpl_context()
224 c = self._get_local_tmpl_context()
222 c.custom_var = 'foobar'
225 c.custom_var = 'foobar'
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
234 self.db_repo_name = self.db_repo.repo_name
236 self.db_repo_name = self.db_repo.repo_name
235 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
237 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
236 self.db_repo_artifacts = ScmModel().get_artifacts(self.db_repo)
238 self.db_repo_artifacts = ScmModel().get_artifacts(self.db_repo)
237 self.db_repo_patterns = IssueTrackerSettingsModel(repo=self.db_repo)
239 self.db_repo_patterns = IssueTrackerSettingsModel(repo=self.db_repo)
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
249 _def_clone_uri = c.clone_uri_tmpl
253 _def_clone_uri = c.clone_uri_tmpl
250 _def_clone_uri_id = c.clone_uri_id_tmpl
254 _def_clone_uri_id = c.clone_uri_id_tmpl
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
267 c.repo_name = self.db_repo_name
273 c.repo_name = self.db_repo_name
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 = {}
275 try:
282 try:
276 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
283 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
277 # NOTE(marcink):
284 # NOTE(marcink):
278 # comparison to None since if it's an object __bool__ is expensive to
285 # comparison to None since if it's an object __bool__ is expensive to
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
289 c.path_filter = self.path_filter # used by atom_feed_entry.mako
297 c.path_filter = self.path_filter # used by atom_feed_entry.mako
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"
295 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
303 )
296 "Please check if it exist, or is not damaged.") %
304 h.flash(
297 {'repo_name': c.repo_name},
305 _(
298 category='error', ignore_duplicate=True)
306 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
307 "Please check if it exist, or is not damaged."
308 )
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
319 def _get_f_path_unchecked(self, matchdict, default=None):
334 def _get_f_path_unchecked(self, matchdict, default=None):
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
330 def _get_f_path(self, matchdict, default=None):
345 def _get_f_path(self, matchdict, default=None):
331 f_path_match = self._get_f_path_unchecked(matchdict, default)
346 f_path_match = self._get_f_path_unchecked(matchdict, default)
332 return self.path_filter.assert_path_permissions(f_path_match)
347 return self.path_filter.assert_path_permissions(f_path_match)
333
348
334 def _get_general_setting(self, target_repo, settings_key, default=False):
349 def _get_general_setting(self, target_repo, settings_key, default=False):
335 settings_model = VcsSettingsModel(repo=target_repo)
350 settings_model = VcsSettingsModel(repo=target_repo)
336 settings = settings_model.get_general_settings()
351 settings = settings_model.get_general_settings()
337 return settings.get(settings_key, default)
352 return settings.get(settings_key, default)
338
353
339 def _get_repo_setting(self, target_repo, settings_key, default=False):
354 def _get_repo_setting(self, target_repo, settings_key, default=False):
340 settings_model = VcsSettingsModel(repo=target_repo)
355 settings_model = VcsSettingsModel(repo=target_repo)
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:
349 landing_commit = db_repo.get_landing_commit()
364 landing_commit = db_repo.get_landing_commit()
350 if isinstance(landing_commit, EmptyCommit):
365 if isinstance(landing_commit, EmptyCommit):
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
400 except Exception:
439 except Exception:
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
421
467
422 def assert_path_permissions(self, path):
468 def assert_path_permissions(self, path):
423 if self.path_access_allowed(path):
469 if self.path_access_allowed(path):
424 return path
470 return path
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):
438 if not self.permission_checker or not patchset:
486 if not self.permission_checker or not patchset:
439 return patchset, False
487 return patchset, False
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
463 def get_raw_patch(self, diff_processor):
515 def get_raw_patch(self, diff_processor):
464 if self.permission_checker is None:
516 if self.permission_checker is None:
465 return diff_processor.as_raw()
517 return diff_processor.as_raw()
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):
473 return self.permission_checker is not None
525 return self.permission_checker is not None
474
526
475
527
476 class RepoGroupAppView(BaseAppView):
528 class RepoGroupAppView(BaseAppView):
477 def __init__(self, context, request):
529 def __init__(self, context, request):
478 super().__init__(context, request)
530 super().__init__(context, request)
479 self.db_repo_group = request.db_repo_group
531 self.db_repo_group = request.db_repo_group
480 self.db_repo_group_name = self.db_repo_group.group_name
532 self.db_repo_group_name = self.db_repo_group.group_name
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
500
568
501 class UserGroupAppView(BaseAppView):
569 class UserGroupAppView(BaseAppView):
502 def __init__(self, context, request):
570 def __init__(self, context, request):
503 super().__init__(context, request)
571 super().__init__(context, request)
504 self.db_user_group = request.db_user_group
572 self.db_user_group = request.db_user_group
505 self.db_user_group_name = self.db_user_group.users_group_name
573 self.db_user_group_name = self.db_user_group.users_group_name
506
574
507
575
508 class UserAppView(BaseAppView):
576 class UserAppView(BaseAppView):
509 def __init__(self, context, request):
577 def __init__(self, context, request):
510 super().__init__(context, request)
578 super().__init__(context, request)
511 self.db_user = request.db_user
579 self.db_user = request.db_user
512 self.db_user_id = self.db_user.user_id
580 self.db_user_id = self.db_user.user_id
513
581
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):
523 """
593 """
524 Common class to have re-usable grid rendering components
594 Common class to have re-usable grid rendering components
525 """
595 """
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):
548 if isinstance(order_by, str):
616 if isinstance(order_by, str):
549 try:
617 try:
550 return operator.attrgetter(order_by)(model)
618 return operator.attrgetter(order_by)(model)
551 except AttributeError:
619 except AttributeError:
552 return None
620 return None
553 else:
621 else:
554 return order_by
622 return order_by
555
623
556
624
557 class BaseReferencesView(RepoAppView):
625 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
564
633
565 def load_refs_context(self, ref_items, partials_template):
634 def load_refs_context(self, ref_items, partials_template):
566 _render = self.request.get_partial_renderer(partials_template)
635 _render = self.request.get_partial_renderer(partials_template)
567 pre_load = ["author", "date", "message", "parents"]
636 pre_load = ["author", "date", "message", "parents"]
568
637
569 is_svn = h.is_svn(self.rhodecode_vcs_repo)
638 is_svn = h.is_svn(self.rhodecode_vcs_repo)
570 is_hg = h.is_hg(self.rhodecode_vcs_repo)
639 is_hg = h.is_hg(self.rhodecode_vcs_repo)
571
640
572 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
641 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
573
642
574 closed_refs = {}
643 closed_refs = {}
575 if is_hg:
644 if is_hg:
576 closed_refs = self.rhodecode_vcs_repo.branches_closed
645 closed_refs = self.rhodecode_vcs_repo.branches_closed
577
646
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 {
607 "name_raw": ref_name,
677 "name": _render("name", ref_name, files_url, closed),
608 "date": _render('date', commit.date),
678 "name_raw": ref_name,
609 "date_raw": datetime_to_time(commit.date),
679 "date": _render("date", commit.date),
610 "author": _render('author', commit.author),
680 "date_raw": datetime_to_time(commit.date),
611 "commit": _render(
681 "author": _render("author", commit.author),
612 'commit', commit.message, commit.raw_id, commit.idx),
682 "commit": _render(
613 "commit_raw": commit.idx,
683 "commit", commit.message, commit.raw_id, commit.idx
614 "compare": _render(
684 ),
615 'compare', format_ref_id(ref_name, commit.raw_id)),
685 "commit_raw": commit.idx,
616 })
686 "compare": _render(
687 "compare", format_ref_id(ref_name, commit.raw_id)
688 ),
689 }
690 )
617
691
618 return data
692 return data
619
693
620
694
621 class RepoRoutePredicate(object):
695 class RepoRoutePredicate(object):
622 def __init__(self, val, config):
696 def __init__(self, val, config):
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()
646
722
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:
655 return
731 return
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:
663 # register this as request object we can re-use later
740 # register this as request object we can re-use later
664 request.db_repo = by_name_match
741 request.db_repo = by_name_match
665 request.db_repo_name = request.db_repo.repo_name
742 request.db_repo_name = request.db_repo.repo_name
666
743
667 redirect_if_creating(info, by_name_match)
744 redirect_if_creating(info, by_name_match)
668 return True
745 return True
669
746
670 by_id_match = repo_model.get_repo_by_id(repo_name)
747 by_id_match = repo_model.get_repo_by_id(repo_name)
671 if by_id_match:
748 if by_id_match:
672 request.db_repo = by_id_match
749 request.db_repo = by_id_match
673 request.db_repo_name = request.db_repo.repo_name
750 request.db_repo_name = request.db_repo.repo_name
674 redirect_if_creating(info, by_id_match)
751 redirect_if_creating(info, by_id_match)
675 return True
752 return True
676
753
677 return False
754 return False
678
755
679
756
680 class RepoForbidArchivedRoutePredicate(object):
757 class RepoForbidArchivedRoutePredicate(object):
681 def __init__(self, val, config):
758 def __init__(self, val, config):
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
689 def __call__(self, info, request):
766 def __call__(self, info, request):
690 _ = request.translate
767 _ = request.translate
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
738 class RepoGroupRoutePredicate(object):
826 class RepoGroupRoutePredicate(object):
739 def __init__(self, val, config):
827 def __init__(self, val, config):
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()
762 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
856 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
763
857
764 if by_name_match:
858 if by_name_match:
765 # register this as request object we can re-use later
859 # register this as request object we can re-use later
766 request.db_repo_group = by_name_match
860 request.db_repo_group = by_name_match
767 request.db_repo_group_name = request.db_repo_group.group_name
861 request.db_repo_group_name = request.db_repo_group.group_name
768 return True
862 return True
769
863
770 return False
864 return False
771
865
772
866
773 class UserGroupRoutePredicate(object):
867 class UserGroupRoutePredicate(object):
774 def __init__(self, val, config):
868 def __init__(self, val, config):
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
791 if by_id_match:
885 if by_id_match:
792 # register this as request object we can re-use later
886 # register this as request object we can re-use later
793 request.db_user_group = by_id_match
887 request.db_user_group = by_id_match
794 return True
888 return True
795
889
796 return False
890 return False
797
891
798
892
799 class UserRoutePredicateBase(object):
893 class UserRoutePredicateBase(object):
800 supports_default = None
894 supports_default = None
801
895
802 def __init__(self, val, config):
896 def __init__(self, val, config):
803 self.val = val
897 self.val = val
804
898
805 def text(self):
899 def text(self):
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
817 if by_id_match:
911 if by_id_match:
818 # register this as request object we can re-use later
912 # register this as request object we can re-use later
819 request.db_user = by_id_match
913 request.db_user = by_id_match
820 request.db_user_supports_default = self.supports_default
914 request.db_user_supports_default = self.supports_default
821 return True
915 return True
822
916
823 return False
917 return False
824
918
825
919
826 class UserRoutePredicate(UserRoutePredicateBase):
920 class UserRoutePredicate(UserRoutePredicateBase):
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
834
928
835 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
929 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
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