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