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