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