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