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