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