##// END OF EJS Templates
routing: skip advanced delete for repo creating so we can remove stuck repositories.
marcink -
r2913:3474cae9 default
parent child Browse files
Show More
@@ -1,638 +1,645 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 if hasattr(request, 'vcs_call'):
464 if hasattr(request, 'vcs_call'):
465 # skip vcs calls
465 # skip vcs calls
466 return
466 return
467
467
468 repo_name = info['match']['repo_name']
468 repo_name = info['match']['repo_name']
469 repo_model = repo.RepoModel()
469 repo_model = repo.RepoModel()
470
470
471 by_name_match = repo_model.get_by_repo_name(repo_name, cache=False)
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(route_info, db_repo):
474 skip_views = ['edit_repo_advanced_delete']
475 route = route_info['route']
476 # we should skip delete view so we can actually "remove" repositories
477 # if they get stuck in creating state.
478 if route.name in skip_views:
479 return
480
474 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
481 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
475 repo_creating_url = request.route_path(
482 repo_creating_url = request.route_path(
476 'repo_creating', repo_name=db_repo.repo_name)
483 'repo_creating', repo_name=db_repo.repo_name)
477 raise HTTPFound(repo_creating_url)
484 raise HTTPFound(repo_creating_url)
478
485
479 if by_name_match:
486 if by_name_match:
480 # register this as request object we can re-use later
487 # register this as request object we can re-use later
481 request.db_repo = by_name_match
488 request.db_repo = by_name_match
482 redirect_if_creating(by_name_match)
489 redirect_if_creating(info, by_name_match)
483 return True
490 return True
484
491
485 by_id_match = repo_model.get_repo_by_id(repo_name)
492 by_id_match = repo_model.get_repo_by_id(repo_name)
486 if by_id_match:
493 if by_id_match:
487 request.db_repo = by_id_match
494 request.db_repo = by_id_match
488 redirect_if_creating(by_id_match)
495 redirect_if_creating(info, by_id_match)
489 return True
496 return True
490
497
491 return False
498 return False
492
499
493
500
494 class RepoTypeRoutePredicate(object):
501 class RepoTypeRoutePredicate(object):
495 def __init__(self, val, config):
502 def __init__(self, val, config):
496 self.val = val or ['hg', 'git', 'svn']
503 self.val = val or ['hg', 'git', 'svn']
497
504
498 def text(self):
505 def text(self):
499 return 'repo_accepted_type = %s' % self.val
506 return 'repo_accepted_type = %s' % self.val
500
507
501 phash = text
508 phash = text
502
509
503 def __call__(self, info, request):
510 def __call__(self, info, request):
504 if hasattr(request, 'vcs_call'):
511 if hasattr(request, 'vcs_call'):
505 # skip vcs calls
512 # skip vcs calls
506 return
513 return
507
514
508 rhodecode_db_repo = request.db_repo
515 rhodecode_db_repo = request.db_repo
509
516
510 log.debug(
517 log.debug(
511 '%s checking repo type for %s in %s',
518 '%s checking repo type for %s in %s',
512 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
519 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
513
520
514 if rhodecode_db_repo.repo_type in self.val:
521 if rhodecode_db_repo.repo_type in self.val:
515 return True
522 return True
516 else:
523 else:
517 log.warning('Current view is not supported for repo type:%s',
524 log.warning('Current view is not supported for repo type:%s',
518 rhodecode_db_repo.repo_type)
525 rhodecode_db_repo.repo_type)
519
526
520 # h.flash(h.literal(
527 # h.flash(h.literal(
521 # _('Action not supported for %s.' % rhodecode_repo.alias)),
528 # _('Action not supported for %s.' % rhodecode_repo.alias)),
522 # category='warning')
529 # category='warning')
523 # return redirect(
530 # return redirect(
524 # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
531 # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
525
532
526 return False
533 return False
527
534
528
535
529 class RepoGroupRoutePredicate(object):
536 class RepoGroupRoutePredicate(object):
530 def __init__(self, val, config):
537 def __init__(self, val, config):
531 self.val = val
538 self.val = val
532
539
533 def text(self):
540 def text(self):
534 return 'repo_group_route = %s' % self.val
541 return 'repo_group_route = %s' % self.val
535
542
536 phash = text
543 phash = text
537
544
538 def __call__(self, info, request):
545 def __call__(self, info, request):
539 if hasattr(request, 'vcs_call'):
546 if hasattr(request, 'vcs_call'):
540 # skip vcs calls
547 # skip vcs calls
541 return
548 return
542
549
543 repo_group_name = info['match']['repo_group_name']
550 repo_group_name = info['match']['repo_group_name']
544 repo_group_model = repo_group.RepoGroupModel()
551 repo_group_model = repo_group.RepoGroupModel()
545 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
552 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
546
553
547 if by_name_match:
554 if by_name_match:
548 # register this as request object we can re-use later
555 # register this as request object we can re-use later
549 request.db_repo_group = by_name_match
556 request.db_repo_group = by_name_match
550 return True
557 return True
551
558
552 return False
559 return False
553
560
554
561
555 class UserGroupRoutePredicate(object):
562 class UserGroupRoutePredicate(object):
556 def __init__(self, val, config):
563 def __init__(self, val, config):
557 self.val = val
564 self.val = val
558
565
559 def text(self):
566 def text(self):
560 return 'user_group_route = %s' % self.val
567 return 'user_group_route = %s' % self.val
561
568
562 phash = text
569 phash = text
563
570
564 def __call__(self, info, request):
571 def __call__(self, info, request):
565 if hasattr(request, 'vcs_call'):
572 if hasattr(request, 'vcs_call'):
566 # skip vcs calls
573 # skip vcs calls
567 return
574 return
568
575
569 user_group_id = info['match']['user_group_id']
576 user_group_id = info['match']['user_group_id']
570 user_group_model = user_group.UserGroup()
577 user_group_model = user_group.UserGroup()
571 by_id_match = user_group_model.get(user_group_id, cache=False)
578 by_id_match = user_group_model.get(user_group_id, cache=False)
572
579
573 if by_id_match:
580 if by_id_match:
574 # register this as request object we can re-use later
581 # register this as request object we can re-use later
575 request.db_user_group = by_id_match
582 request.db_user_group = by_id_match
576 return True
583 return True
577
584
578 return False
585 return False
579
586
580
587
581 class UserRoutePredicateBase(object):
588 class UserRoutePredicateBase(object):
582 supports_default = None
589 supports_default = None
583
590
584 def __init__(self, val, config):
591 def __init__(self, val, config):
585 self.val = val
592 self.val = val
586
593
587 def text(self):
594 def text(self):
588 raise NotImplementedError()
595 raise NotImplementedError()
589
596
590 def __call__(self, info, request):
597 def __call__(self, info, request):
591 if hasattr(request, 'vcs_call'):
598 if hasattr(request, 'vcs_call'):
592 # skip vcs calls
599 # skip vcs calls
593 return
600 return
594
601
595 user_id = info['match']['user_id']
602 user_id = info['match']['user_id']
596 user_model = user.User()
603 user_model = user.User()
597 by_id_match = user_model.get(user_id, cache=False)
604 by_id_match = user_model.get(user_id, cache=False)
598
605
599 if by_id_match:
606 if by_id_match:
600 # register this as request object we can re-use later
607 # register this as request object we can re-use later
601 request.db_user = by_id_match
608 request.db_user = by_id_match
602 request.db_user_supports_default = self.supports_default
609 request.db_user_supports_default = self.supports_default
603 return True
610 return True
604
611
605 return False
612 return False
606
613
607
614
608 class UserRoutePredicate(UserRoutePredicateBase):
615 class UserRoutePredicate(UserRoutePredicateBase):
609 supports_default = False
616 supports_default = False
610
617
611 def text(self):
618 def text(self):
612 return 'user_route = %s' % self.val
619 return 'user_route = %s' % self.val
613
620
614 phash = text
621 phash = text
615
622
616
623
617 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
624 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
618 supports_default = True
625 supports_default = True
619
626
620 def text(self):
627 def text(self):
621 return 'user_with_default_route = %s' % self.val
628 return 'user_with_default_route = %s' % self.val
622
629
623 phash = text
630 phash = text
624
631
625
632
626 def includeme(config):
633 def includeme(config):
627 config.add_route_predicate(
634 config.add_route_predicate(
628 'repo_route', RepoRoutePredicate)
635 'repo_route', RepoRoutePredicate)
629 config.add_route_predicate(
636 config.add_route_predicate(
630 'repo_accepted_types', RepoTypeRoutePredicate)
637 'repo_accepted_types', RepoTypeRoutePredicate)
631 config.add_route_predicate(
638 config.add_route_predicate(
632 'repo_group_route', RepoGroupRoutePredicate)
639 'repo_group_route', RepoGroupRoutePredicate)
633 config.add_route_predicate(
640 config.add_route_predicate(
634 'user_group_route', UserGroupRoutePredicate)
641 'user_group_route', UserGroupRoutePredicate)
635 config.add_route_predicate(
642 config.add_route_predicate(
636 'user_route_with_default', UserRouteWithDefaultPredicate)
643 'user_route_with_default', UserRouteWithDefaultPredicate)
637 config.add_route_predicate(
644 config.add_route_predicate(
638 'user_route', UserRoutePredicate) No newline at end of file
645 'user_route', UserRoutePredicate)
General Comments 0
You need to be logged in to leave comments. Login now