##// END OF EJS Templates
path-permissions: handle case of missing requirements and initializing self.path_filter with None value....
marcink -
r2624:c116493f default
parent child Browse files
Show More
@@ -1,628 +1,626 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 self.path_filter = PathFilter(None)
207
208
208 c.repository_requirements_missing = False
209 c.repository_requirements_missing = False
209 try:
210 try:
210 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
211 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
211 if self.rhodecode_vcs_repo:
212 if self.rhodecode_vcs_repo:
212 path_perms = self.rhodecode_vcs_repo.get_path_permissions(
213 path_perms = self.rhodecode_vcs_repo.get_path_permissions(
213 c.auth_user.username)
214 c.auth_user.username)
214 self.path_filter = PathFilter(path_perms)
215 self.path_filter = PathFilter(path_perms)
215 else:
216 self.path_filter = PathFilter(None)
217 except RepositoryRequirementError as e:
216 except RepositoryRequirementError as e:
218 c.repository_requirements_missing = True
217 c.repository_requirements_missing = True
219 self._handle_missing_requirements(e)
218 self._handle_missing_requirements(e)
220 self.rhodecode_vcs_repo = None
219 self.rhodecode_vcs_repo = None
221 self.path_filter = None
222
220
223 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
224
222
225 if (not c.repository_requirements_missing
223 if (not c.repository_requirements_missing
226 and self.rhodecode_vcs_repo is None):
224 and self.rhodecode_vcs_repo is None):
227 # 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
228 h.flash(_(
226 h.flash(_(
229 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
227 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
230 "Please check if it exist, or is not damaged.") %
228 "Please check if it exist, or is not damaged.") %
231 {'repo_name': c.repo_name},
229 {'repo_name': c.repo_name},
232 category='error', ignore_duplicate=True)
230 category='error', ignore_duplicate=True)
233 raise HTTPFound(h.route_path('home'))
231 raise HTTPFound(h.route_path('home'))
234
232
235 return c
233 return c
236
234
237 def _get_f_path_unchecked(self, matchdict, default=None):
235 def _get_f_path_unchecked(self, matchdict, default=None):
238 """
236 """
239 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
240 """
238 """
241 f_path = matchdict.get('f_path')
239 f_path = matchdict.get('f_path')
242 if f_path:
240 if f_path:
243 # fix for multiple initial slashes that causes errors for GIT
241 # fix for multiple initial slashes that causes errors for GIT
244 return f_path.lstrip('/')
242 return f_path.lstrip('/')
245
243
246 return default
244 return default
247
245
248 def _get_f_path(self, matchdict, default=None):
246 def _get_f_path(self, matchdict, default=None):
249 f_path_match = self._get_f_path_unchecked(matchdict, default)
247 f_path_match = self._get_f_path_unchecked(matchdict, default)
250 return self.path_filter.assert_path_permissions(f_path_match)
248 return self.path_filter.assert_path_permissions(f_path_match)
251
249
252
250
253 class PathFilter(object):
251 class PathFilter(object):
254
252
255 # Expects and instance of BasePathPermissionChecker or None
253 # Expects and instance of BasePathPermissionChecker or None
256 def __init__(self, permission_checker):
254 def __init__(self, permission_checker):
257 self.permission_checker = permission_checker
255 self.permission_checker = permission_checker
258
256
259 def assert_path_permissions(self, path):
257 def assert_path_permissions(self, path):
260 if path and self.permission_checker and not self.permission_checker.has_access(path):
258 if path and self.permission_checker and not self.permission_checker.has_access(path):
261 raise HTTPForbidden()
259 raise HTTPForbidden()
262 return path
260 return path
263
261
264 def filter_patchset(self, patchset):
262 def filter_patchset(self, patchset):
265 if not self.permission_checker or not patchset:
263 if not self.permission_checker or not patchset:
266 return patchset, False
264 return patchset, False
267 had_filtered = False
265 had_filtered = False
268 filtered_patchset = []
266 filtered_patchset = []
269 for patch in patchset:
267 for patch in patchset:
270 filename = patch.get('filename', None)
268 filename = patch.get('filename', None)
271 if not filename or self.permission_checker.has_access(filename):
269 if not filename or self.permission_checker.has_access(filename):
272 filtered_patchset.append(patch)
270 filtered_patchset.append(patch)
273 else:
271 else:
274 had_filtered = True
272 had_filtered = True
275 if had_filtered:
273 if had_filtered:
276 if isinstance(patchset, diffs.LimitedDiffContainer):
274 if isinstance(patchset, diffs.LimitedDiffContainer):
277 filtered_patchset = diffs.LimitedDiffContainer(patchset.diff_limit, patchset.cur_diff_size, filtered_patchset)
275 filtered_patchset = diffs.LimitedDiffContainer(patchset.diff_limit, patchset.cur_diff_size, filtered_patchset)
278 return filtered_patchset, True
276 return filtered_patchset, True
279 else:
277 else:
280 return patchset, False
278 return patchset, False
281
279
282 def render_patchset_filtered(self, diffset, patchset, source_ref=None, target_ref=None):
280 def render_patchset_filtered(self, diffset, patchset, source_ref=None, target_ref=None):
283 filtered_patchset, has_hidden_changes = self.filter_patchset(patchset)
281 filtered_patchset, has_hidden_changes = self.filter_patchset(patchset)
284 result = diffset.render_patchset(filtered_patchset, source_ref=source_ref, target_ref=target_ref)
282 result = diffset.render_patchset(filtered_patchset, source_ref=source_ref, target_ref=target_ref)
285 result.has_hidden_changes = has_hidden_changes
283 result.has_hidden_changes = has_hidden_changes
286 return result
284 return result
287
285
288 def get_raw_patch(self, diff_processor):
286 def get_raw_patch(self, diff_processor):
289 if self.permission_checker is None:
287 if self.permission_checker is None:
290 return diff_processor.as_raw()
288 return diff_processor.as_raw()
291 elif self.permission_checker.has_full_access:
289 elif self.permission_checker.has_full_access:
292 return diff_processor.as_raw()
290 return diff_processor.as_raw()
293 else:
291 else:
294 return '# Repository has user-specific filters, raw patch generation is disabled.'
292 return '# Repository has user-specific filters, raw patch generation is disabled.'
295
293
296 @property
294 @property
297 def is_enabled(self):
295 def is_enabled(self):
298 return self.permission_checker is not None
296 return self.permission_checker is not None
299
297
300
298
301 class RepoGroupAppView(BaseAppView):
299 class RepoGroupAppView(BaseAppView):
302 def __init__(self, context, request):
300 def __init__(self, context, request):
303 super(RepoGroupAppView, self).__init__(context, request)
301 super(RepoGroupAppView, self).__init__(context, request)
304 self.db_repo_group = request.db_repo_group
302 self.db_repo_group = request.db_repo_group
305 self.db_repo_group_name = self.db_repo_group.group_name
303 self.db_repo_group_name = self.db_repo_group.group_name
306
304
307 def _revoke_perms_on_yourself(self, form_result):
305 def _revoke_perms_on_yourself(self, form_result):
308 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
306 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
309 form_result['perm_updates'])
307 form_result['perm_updates'])
310 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
308 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
311 form_result['perm_additions'])
309 form_result['perm_additions'])
312 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
310 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
313 form_result['perm_deletions'])
311 form_result['perm_deletions'])
314 admin_perm = 'group.admin'
312 admin_perm = 'group.admin'
315 if _updates and _updates[0][1] != admin_perm or \
313 if _updates and _updates[0][1] != admin_perm or \
316 _additions and _additions[0][1] != admin_perm or \
314 _additions and _additions[0][1] != admin_perm or \
317 _deletions and _deletions[0][1] != admin_perm:
315 _deletions and _deletions[0][1] != admin_perm:
318 return True
316 return True
319 return False
317 return False
320
318
321
319
322 class UserGroupAppView(BaseAppView):
320 class UserGroupAppView(BaseAppView):
323 def __init__(self, context, request):
321 def __init__(self, context, request):
324 super(UserGroupAppView, self).__init__(context, request)
322 super(UserGroupAppView, self).__init__(context, request)
325 self.db_user_group = request.db_user_group
323 self.db_user_group = request.db_user_group
326 self.db_user_group_name = self.db_user_group.users_group_name
324 self.db_user_group_name = self.db_user_group.users_group_name
327
325
328
326
329 class UserAppView(BaseAppView):
327 class UserAppView(BaseAppView):
330 def __init__(self, context, request):
328 def __init__(self, context, request):
331 super(UserAppView, self).__init__(context, request)
329 super(UserAppView, self).__init__(context, request)
332 self.db_user = request.db_user
330 self.db_user = request.db_user
333 self.db_user_id = self.db_user.user_id
331 self.db_user_id = self.db_user.user_id
334
332
335 _ = self.request.translate
333 _ = self.request.translate
336 if not request.db_user_supports_default:
334 if not request.db_user_supports_default:
337 if self.db_user.username == User.DEFAULT_USER:
335 if self.db_user.username == User.DEFAULT_USER:
338 h.flash(_("Editing user `{}` is disabled.".format(
336 h.flash(_("Editing user `{}` is disabled.".format(
339 User.DEFAULT_USER)), category='warning')
337 User.DEFAULT_USER)), category='warning')
340 raise HTTPFound(h.route_path('users'))
338 raise HTTPFound(h.route_path('users'))
341
339
342
340
343 class DataGridAppView(object):
341 class DataGridAppView(object):
344 """
342 """
345 Common class to have re-usable grid rendering components
343 Common class to have re-usable grid rendering components
346 """
344 """
347
345
348 def _extract_ordering(self, request, column_map=None):
346 def _extract_ordering(self, request, column_map=None):
349 column_map = column_map or {}
347 column_map = column_map or {}
350 column_index = safe_int(request.GET.get('order[0][column]'))
348 column_index = safe_int(request.GET.get('order[0][column]'))
351 order_dir = request.GET.get(
349 order_dir = request.GET.get(
352 'order[0][dir]', 'desc')
350 'order[0][dir]', 'desc')
353 order_by = request.GET.get(
351 order_by = request.GET.get(
354 'columns[%s][data][sort]' % column_index, 'name_raw')
352 'columns[%s][data][sort]' % column_index, 'name_raw')
355
353
356 # translate datatable to DB columns
354 # translate datatable to DB columns
357 order_by = column_map.get(order_by) or order_by
355 order_by = column_map.get(order_by) or order_by
358
356
359 search_q = request.GET.get('search[value]')
357 search_q = request.GET.get('search[value]')
360 return search_q, order_by, order_dir
358 return search_q, order_by, order_dir
361
359
362 def _extract_chunk(self, request):
360 def _extract_chunk(self, request):
363 start = safe_int(request.GET.get('start'), 0)
361 start = safe_int(request.GET.get('start'), 0)
364 length = safe_int(request.GET.get('length'), 25)
362 length = safe_int(request.GET.get('length'), 25)
365 draw = safe_int(request.GET.get('draw'))
363 draw = safe_int(request.GET.get('draw'))
366 return draw, start, length
364 return draw, start, length
367
365
368 def _get_order_col(self, order_by, model):
366 def _get_order_col(self, order_by, model):
369 if isinstance(order_by, basestring):
367 if isinstance(order_by, basestring):
370 try:
368 try:
371 return operator.attrgetter(order_by)(model)
369 return operator.attrgetter(order_by)(model)
372 except AttributeError:
370 except AttributeError:
373 return None
371 return None
374 else:
372 else:
375 return order_by
373 return order_by
376
374
377
375
378 class BaseReferencesView(RepoAppView):
376 class BaseReferencesView(RepoAppView):
379 """
377 """
380 Base for reference view for branches, tags and bookmarks.
378 Base for reference view for branches, tags and bookmarks.
381 """
379 """
382 def load_default_context(self):
380 def load_default_context(self):
383 c = self._get_local_tmpl_context()
381 c = self._get_local_tmpl_context()
384
382
385
383
386 return c
384 return c
387
385
388 def load_refs_context(self, ref_items, partials_template):
386 def load_refs_context(self, ref_items, partials_template):
389 _render = self.request.get_partial_renderer(partials_template)
387 _render = self.request.get_partial_renderer(partials_template)
390 pre_load = ["author", "date", "message"]
388 pre_load = ["author", "date", "message"]
391
389
392 is_svn = h.is_svn(self.rhodecode_vcs_repo)
390 is_svn = h.is_svn(self.rhodecode_vcs_repo)
393 is_hg = h.is_hg(self.rhodecode_vcs_repo)
391 is_hg = h.is_hg(self.rhodecode_vcs_repo)
394
392
395 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
393 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
396
394
397 closed_refs = {}
395 closed_refs = {}
398 if is_hg:
396 if is_hg:
399 closed_refs = self.rhodecode_vcs_repo.branches_closed
397 closed_refs = self.rhodecode_vcs_repo.branches_closed
400
398
401 data = []
399 data = []
402 for ref_name, commit_id in ref_items:
400 for ref_name, commit_id in ref_items:
403 commit = self.rhodecode_vcs_repo.get_commit(
401 commit = self.rhodecode_vcs_repo.get_commit(
404 commit_id=commit_id, pre_load=pre_load)
402 commit_id=commit_id, pre_load=pre_load)
405 closed = ref_name in closed_refs
403 closed = ref_name in closed_refs
406
404
407 # TODO: johbo: Unify generation of reference links
405 # TODO: johbo: Unify generation of reference links
408 use_commit_id = '/' in ref_name or is_svn
406 use_commit_id = '/' in ref_name or is_svn
409
407
410 if use_commit_id:
408 if use_commit_id:
411 files_url = h.route_path(
409 files_url = h.route_path(
412 'repo_files',
410 'repo_files',
413 repo_name=self.db_repo_name,
411 repo_name=self.db_repo_name,
414 f_path=ref_name if is_svn else '',
412 f_path=ref_name if is_svn else '',
415 commit_id=commit_id)
413 commit_id=commit_id)
416
414
417 else:
415 else:
418 files_url = h.route_path(
416 files_url = h.route_path(
419 'repo_files',
417 'repo_files',
420 repo_name=self.db_repo_name,
418 repo_name=self.db_repo_name,
421 f_path=ref_name if is_svn else '',
419 f_path=ref_name if is_svn else '',
422 commit_id=ref_name,
420 commit_id=ref_name,
423 _query=dict(at=ref_name))
421 _query=dict(at=ref_name))
424
422
425 data.append({
423 data.append({
426 "name": _render('name', ref_name, files_url, closed),
424 "name": _render('name', ref_name, files_url, closed),
427 "name_raw": ref_name,
425 "name_raw": ref_name,
428 "date": _render('date', commit.date),
426 "date": _render('date', commit.date),
429 "date_raw": datetime_to_time(commit.date),
427 "date_raw": datetime_to_time(commit.date),
430 "author": _render('author', commit.author),
428 "author": _render('author', commit.author),
431 "commit": _render(
429 "commit": _render(
432 'commit', commit.message, commit.raw_id, commit.idx),
430 'commit', commit.message, commit.raw_id, commit.idx),
433 "commit_raw": commit.idx,
431 "commit_raw": commit.idx,
434 "compare": _render(
432 "compare": _render(
435 'compare', format_ref_id(ref_name, commit.raw_id)),
433 'compare', format_ref_id(ref_name, commit.raw_id)),
436 })
434 })
437
435
438 return data
436 return data
439
437
440
438
441 class RepoRoutePredicate(object):
439 class RepoRoutePredicate(object):
442 def __init__(self, val, config):
440 def __init__(self, val, config):
443 self.val = val
441 self.val = val
444
442
445 def text(self):
443 def text(self):
446 return 'repo_route = %s' % self.val
444 return 'repo_route = %s' % self.val
447
445
448 phash = text
446 phash = text
449
447
450 def __call__(self, info, request):
448 def __call__(self, info, request):
451
449
452 if hasattr(request, 'vcs_call'):
450 if hasattr(request, 'vcs_call'):
453 # skip vcs calls
451 # skip vcs calls
454 return
452 return
455
453
456 repo_name = info['match']['repo_name']
454 repo_name = info['match']['repo_name']
457 repo_model = repo.RepoModel()
455 repo_model = repo.RepoModel()
458 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
456 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
459
457
460 def redirect_if_creating(db_repo):
458 def redirect_if_creating(db_repo):
461 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
459 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
462 raise HTTPFound(
460 raise HTTPFound(
463 request.route_path('repo_creating',
461 request.route_path('repo_creating',
464 repo_name=db_repo.repo_name))
462 repo_name=db_repo.repo_name))
465
463
466 if by_name_match:
464 if by_name_match:
467 # register this as request object we can re-use later
465 # register this as request object we can re-use later
468 request.db_repo = by_name_match
466 request.db_repo = by_name_match
469 redirect_if_creating(by_name_match)
467 redirect_if_creating(by_name_match)
470 return True
468 return True
471
469
472 by_id_match = repo_model.get_repo_by_id(repo_name)
470 by_id_match = repo_model.get_repo_by_id(repo_name)
473 if by_id_match:
471 if by_id_match:
474 request.db_repo = by_id_match
472 request.db_repo = by_id_match
475 redirect_if_creating(by_id_match)
473 redirect_if_creating(by_id_match)
476 return True
474 return True
477
475
478 return False
476 return False
479
477
480
478
481 class RepoTypeRoutePredicate(object):
479 class RepoTypeRoutePredicate(object):
482 def __init__(self, val, config):
480 def __init__(self, val, config):
483 self.val = val or ['hg', 'git', 'svn']
481 self.val = val or ['hg', 'git', 'svn']
484
482
485 def text(self):
483 def text(self):
486 return 'repo_accepted_type = %s' % self.val
484 return 'repo_accepted_type = %s' % self.val
487
485
488 phash = text
486 phash = text
489
487
490 def __call__(self, info, request):
488 def __call__(self, info, request):
491 if hasattr(request, 'vcs_call'):
489 if hasattr(request, 'vcs_call'):
492 # skip vcs calls
490 # skip vcs calls
493 return
491 return
494
492
495 rhodecode_db_repo = request.db_repo
493 rhodecode_db_repo = request.db_repo
496
494
497 log.debug(
495 log.debug(
498 '%s checking repo type for %s in %s',
496 '%s checking repo type for %s in %s',
499 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
497 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
500
498
501 if rhodecode_db_repo.repo_type in self.val:
499 if rhodecode_db_repo.repo_type in self.val:
502 return True
500 return True
503 else:
501 else:
504 log.warning('Current view is not supported for repo type:%s',
502 log.warning('Current view is not supported for repo type:%s',
505 rhodecode_db_repo.repo_type)
503 rhodecode_db_repo.repo_type)
506 #
504 #
507 # h.flash(h.literal(
505 # h.flash(h.literal(
508 # _('Action not supported for %s.' % rhodecode_repo.alias)),
506 # _('Action not supported for %s.' % rhodecode_repo.alias)),
509 # category='warning')
507 # category='warning')
510 # return redirect(
508 # return redirect(
511 # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
509 # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
512
510
513 return False
511 return False
514
512
515
513
516 class RepoGroupRoutePredicate(object):
514 class RepoGroupRoutePredicate(object):
517 def __init__(self, val, config):
515 def __init__(self, val, config):
518 self.val = val
516 self.val = val
519
517
520 def text(self):
518 def text(self):
521 return 'repo_group_route = %s' % self.val
519 return 'repo_group_route = %s' % self.val
522
520
523 phash = text
521 phash = text
524
522
525 def __call__(self, info, request):
523 def __call__(self, info, request):
526 if hasattr(request, 'vcs_call'):
524 if hasattr(request, 'vcs_call'):
527 # skip vcs calls
525 # skip vcs calls
528 return
526 return
529
527
530 repo_group_name = info['match']['repo_group_name']
528 repo_group_name = info['match']['repo_group_name']
531 repo_group_model = repo_group.RepoGroupModel()
529 repo_group_model = repo_group.RepoGroupModel()
532 by_name_match = repo_group_model.get_by_group_name(
530 by_name_match = repo_group_model.get_by_group_name(
533 repo_group_name, cache=True)
531 repo_group_name, cache=True)
534
532
535 if by_name_match:
533 if by_name_match:
536 # register this as request object we can re-use later
534 # register this as request object we can re-use later
537 request.db_repo_group = by_name_match
535 request.db_repo_group = by_name_match
538 return True
536 return True
539
537
540 return False
538 return False
541
539
542
540
543 class UserGroupRoutePredicate(object):
541 class UserGroupRoutePredicate(object):
544 def __init__(self, val, config):
542 def __init__(self, val, config):
545 self.val = val
543 self.val = val
546
544
547 def text(self):
545 def text(self):
548 return 'user_group_route = %s' % self.val
546 return 'user_group_route = %s' % self.val
549
547
550 phash = text
548 phash = text
551
549
552 def __call__(self, info, request):
550 def __call__(self, info, request):
553 if hasattr(request, 'vcs_call'):
551 if hasattr(request, 'vcs_call'):
554 # skip vcs calls
552 # skip vcs calls
555 return
553 return
556
554
557 user_group_id = info['match']['user_group_id']
555 user_group_id = info['match']['user_group_id']
558 user_group_model = user_group.UserGroup()
556 user_group_model = user_group.UserGroup()
559 by_id_match = user_group_model.get(
557 by_id_match = user_group_model.get(
560 user_group_id, cache=True)
558 user_group_id, cache=True)
561
559
562 if by_id_match:
560 if by_id_match:
563 # register this as request object we can re-use later
561 # register this as request object we can re-use later
564 request.db_user_group = by_id_match
562 request.db_user_group = by_id_match
565 return True
563 return True
566
564
567 return False
565 return False
568
566
569
567
570 class UserRoutePredicateBase(object):
568 class UserRoutePredicateBase(object):
571 supports_default = None
569 supports_default = None
572
570
573 def __init__(self, val, config):
571 def __init__(self, val, config):
574 self.val = val
572 self.val = val
575
573
576 def text(self):
574 def text(self):
577 raise NotImplementedError()
575 raise NotImplementedError()
578
576
579 def __call__(self, info, request):
577 def __call__(self, info, request):
580 if hasattr(request, 'vcs_call'):
578 if hasattr(request, 'vcs_call'):
581 # skip vcs calls
579 # skip vcs calls
582 return
580 return
583
581
584 user_id = info['match']['user_id']
582 user_id = info['match']['user_id']
585 user_model = user.User()
583 user_model = user.User()
586 by_id_match = user_model.get(
584 by_id_match = user_model.get(
587 user_id, cache=True)
585 user_id, cache=True)
588
586
589 if by_id_match:
587 if by_id_match:
590 # register this as request object we can re-use later
588 # register this as request object we can re-use later
591 request.db_user = by_id_match
589 request.db_user = by_id_match
592 request.db_user_supports_default = self.supports_default
590 request.db_user_supports_default = self.supports_default
593 return True
591 return True
594
592
595 return False
593 return False
596
594
597
595
598 class UserRoutePredicate(UserRoutePredicateBase):
596 class UserRoutePredicate(UserRoutePredicateBase):
599 supports_default = False
597 supports_default = False
600
598
601 def text(self):
599 def text(self):
602 return 'user_route = %s' % self.val
600 return 'user_route = %s' % self.val
603
601
604 phash = text
602 phash = text
605
603
606
604
607 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
605 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
608 supports_default = True
606 supports_default = True
609
607
610 def text(self):
608 def text(self):
611 return 'user_with_default_route = %s' % self.val
609 return 'user_with_default_route = %s' % self.val
612
610
613 phash = text
611 phash = text
614
612
615
613
616 def includeme(config):
614 def includeme(config):
617 config.add_route_predicate(
615 config.add_route_predicate(
618 'repo_route', RepoRoutePredicate)
616 'repo_route', RepoRoutePredicate)
619 config.add_route_predicate(
617 config.add_route_predicate(
620 'repo_accepted_types', RepoTypeRoutePredicate)
618 'repo_accepted_types', RepoTypeRoutePredicate)
621 config.add_route_predicate(
619 config.add_route_predicate(
622 'repo_group_route', RepoGroupRoutePredicate)
620 'repo_group_route', RepoGroupRoutePredicate)
623 config.add_route_predicate(
621 config.add_route_predicate(
624 'user_group_route', UserGroupRoutePredicate)
622 'user_group_route', UserGroupRoutePredicate)
625 config.add_route_predicate(
623 config.add_route_predicate(
626 'user_route_with_default', UserRouteWithDefaultPredicate)
624 'user_route_with_default', UserRouteWithDefaultPredicate)
627 config.add_route_predicate(
625 config.add_route_predicate(
628 'user_route', UserRoutePredicate) No newline at end of file
626 'user_route', UserRoutePredicate)
General Comments 0
You need to be logged in to leave comments. Login now