##// END OF EJS Templates
predicates: skip route matching for vcs type calls.
marcink -
r1778:fa40b185 default
parent child Browse files
Show More
@@ -1,338 +1,350 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 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 from pylons import tmpl_context as c
23 from pylons import tmpl_context as c
24 from pyramid.httpexceptions import HTTPFound
24 from pyramid.httpexceptions import HTTPFound
25
25
26 from rhodecode.lib import helpers as h
26 from rhodecode.lib import helpers as h
27 from rhodecode.lib.utils import PartialRenderer
27 from rhodecode.lib.utils import PartialRenderer
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.lib.ext_json import json
30 from rhodecode.lib.ext_json import json
31 from rhodecode.model import repo
31 from rhodecode.model import repo
32 from rhodecode.model import repo_group
32 from rhodecode.model import repo_group
33 from rhodecode.model.db import User
33 from rhodecode.model.db import User
34 from rhodecode.model.scm import ScmModel
34 from rhodecode.model.scm import ScmModel
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 ADMIN_PREFIX = '/_admin'
39 ADMIN_PREFIX = '/_admin'
40 STATIC_FILE_PREFIX = '/_static'
40 STATIC_FILE_PREFIX = '/_static'
41
41
42
42
43 def add_route_with_slash(config,name, pattern, **kw):
43 def add_route_with_slash(config,name, pattern, **kw):
44 config.add_route(name, pattern, **kw)
44 config.add_route(name, pattern, **kw)
45 if not pattern.endswith('/'):
45 if not pattern.endswith('/'):
46 config.add_route(name + '_slash', pattern + '/', **kw)
46 config.add_route(name + '_slash', pattern + '/', **kw)
47
47
48
48
49 def get_format_ref_id(repo):
49 def get_format_ref_id(repo):
50 """Returns a `repo` specific reference formatter function"""
50 """Returns a `repo` specific reference formatter function"""
51 if h.is_svn(repo):
51 if h.is_svn(repo):
52 return _format_ref_id_svn
52 return _format_ref_id_svn
53 else:
53 else:
54 return _format_ref_id
54 return _format_ref_id
55
55
56
56
57 def _format_ref_id(name, raw_id):
57 def _format_ref_id(name, raw_id):
58 """Default formatting of a given reference `name`"""
58 """Default formatting of a given reference `name`"""
59 return name
59 return name
60
60
61
61
62 def _format_ref_id_svn(name, raw_id):
62 def _format_ref_id_svn(name, raw_id):
63 """Special way of formatting a reference for Subversion including path"""
63 """Special way of formatting a reference for Subversion including path"""
64 return '%s@%s' % (name, raw_id)
64 return '%s@%s' % (name, raw_id)
65
65
66
66
67 class TemplateArgs(StrictAttributeDict):
67 class TemplateArgs(StrictAttributeDict):
68 pass
68 pass
69
69
70
70
71 class BaseAppView(object):
71 class BaseAppView(object):
72
72
73 def __init__(self, context, request):
73 def __init__(self, context, request):
74 self.request = request
74 self.request = request
75 self.context = context
75 self.context = context
76 self.session = request.session
76 self.session = request.session
77 self._rhodecode_user = request.user # auth user
77 self._rhodecode_user = request.user # auth user
78 self._rhodecode_db_user = self._rhodecode_user.get_instance()
78 self._rhodecode_db_user = self._rhodecode_user.get_instance()
79 self._maybe_needs_password_change(
79 self._maybe_needs_password_change(
80 request.matched_route.name, self._rhodecode_db_user)
80 request.matched_route.name, self._rhodecode_db_user)
81
81
82 def _maybe_needs_password_change(self, view_name, user_obj):
82 def _maybe_needs_password_change(self, view_name, user_obj):
83 log.debug('Checking if user %s needs password change on view %s',
83 log.debug('Checking if user %s needs password change on view %s',
84 user_obj, view_name)
84 user_obj, view_name)
85 skip_user_views = [
85 skip_user_views = [
86 'logout', 'login',
86 'logout', 'login',
87 'my_account_password', 'my_account_password_update'
87 'my_account_password', 'my_account_password_update'
88 ]
88 ]
89
89
90 if not user_obj:
90 if not user_obj:
91 return
91 return
92
92
93 if user_obj.username == User.DEFAULT_USER:
93 if user_obj.username == User.DEFAULT_USER:
94 return
94 return
95
95
96 now = time.time()
96 now = time.time()
97 should_change = user_obj.user_data.get('force_password_change')
97 should_change = user_obj.user_data.get('force_password_change')
98 change_after = safe_int(should_change) or 0
98 change_after = safe_int(should_change) or 0
99 if should_change and now > change_after:
99 if should_change and now > change_after:
100 log.debug('User %s requires password change', user_obj)
100 log.debug('User %s requires password change', user_obj)
101 h.flash('You are required to change your password', 'warning',
101 h.flash('You are required to change your password', 'warning',
102 ignore_duplicate=True)
102 ignore_duplicate=True)
103
103
104 if view_name not in skip_user_views:
104 if view_name not in skip_user_views:
105 raise HTTPFound(
105 raise HTTPFound(
106 self.request.route_path('my_account_password'))
106 self.request.route_path('my_account_password'))
107
107
108 def _get_local_tmpl_context(self):
108 def _get_local_tmpl_context(self):
109 c = TemplateArgs()
109 c = TemplateArgs()
110 c.auth_user = self.request.user
110 c.auth_user = self.request.user
111 return c
111 return c
112
112
113 def _register_global_c(self, tmpl_args):
113 def _register_global_c(self, tmpl_args):
114 """
114 """
115 Registers attributes to pylons global `c`
115 Registers attributes to pylons global `c`
116 """
116 """
117 # TODO(marcink): remove once pyramid migration is finished
117 # TODO(marcink): remove once pyramid migration is finished
118 for k, v in tmpl_args.items():
118 for k, v in tmpl_args.items():
119 setattr(c, k, v)
119 setattr(c, k, v)
120
120
121 def _get_template_context(self, tmpl_args):
121 def _get_template_context(self, tmpl_args):
122 self._register_global_c(tmpl_args)
122 self._register_global_c(tmpl_args)
123
123
124 local_tmpl_args = {
124 local_tmpl_args = {
125 'defaults': {},
125 'defaults': {},
126 'errors': {},
126 'errors': {},
127 }
127 }
128 local_tmpl_args.update(tmpl_args)
128 local_tmpl_args.update(tmpl_args)
129 return local_tmpl_args
129 return local_tmpl_args
130
130
131 def load_default_context(self):
131 def load_default_context(self):
132 """
132 """
133 example:
133 example:
134
134
135 def load_default_context(self):
135 def load_default_context(self):
136 c = self._get_local_tmpl_context()
136 c = self._get_local_tmpl_context()
137 c.custom_var = 'foobar'
137 c.custom_var = 'foobar'
138 self._register_global_c(c)
138 self._register_global_c(c)
139 return c
139 return c
140 """
140 """
141 raise NotImplementedError('Needs implementation in view class')
141 raise NotImplementedError('Needs implementation in view class')
142
142
143
143
144 class RepoAppView(BaseAppView):
144 class RepoAppView(BaseAppView):
145
145
146 def __init__(self, context, request):
146 def __init__(self, context, request):
147 super(RepoAppView, self).__init__(context, request)
147 super(RepoAppView, self).__init__(context, request)
148 self.db_repo = request.db_repo
148 self.db_repo = request.db_repo
149 self.db_repo_name = self.db_repo.repo_name
149 self.db_repo_name = self.db_repo.repo_name
150 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
150 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
151
151
152 def _handle_missing_requirements(self, error):
152 def _handle_missing_requirements(self, error):
153 log.error(
153 log.error(
154 'Requirements are missing for repository %s: %s',
154 'Requirements are missing for repository %s: %s',
155 self.db_repo_name, error.message)
155 self.db_repo_name, error.message)
156
156
157 def _get_local_tmpl_context(self):
157 def _get_local_tmpl_context(self):
158 c = super(RepoAppView, self)._get_local_tmpl_context()
158 c = super(RepoAppView, self)._get_local_tmpl_context()
159 # register common vars for this type of view
159 # register common vars for this type of view
160 c.rhodecode_db_repo = self.db_repo
160 c.rhodecode_db_repo = self.db_repo
161 c.repo_name = self.db_repo_name
161 c.repo_name = self.db_repo_name
162 c.repository_pull_requests = self.db_repo_pull_requests
162 c.repository_pull_requests = self.db_repo_pull_requests
163
163
164 c.repository_requirements_missing = False
164 c.repository_requirements_missing = False
165 try:
165 try:
166 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
166 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
167 except RepositoryRequirementError as e:
167 except RepositoryRequirementError as e:
168 c.repository_requirements_missing = True
168 c.repository_requirements_missing = True
169 self._handle_missing_requirements(e)
169 self._handle_missing_requirements(e)
170
170
171 return c
171 return c
172
172
173
173
174 class DataGridAppView(object):
174 class DataGridAppView(object):
175 """
175 """
176 Common class to have re-usable grid rendering components
176 Common class to have re-usable grid rendering components
177 """
177 """
178
178
179 def _extract_ordering(self, request, column_map=None):
179 def _extract_ordering(self, request, column_map=None):
180 column_map = column_map or {}
180 column_map = column_map or {}
181 column_index = safe_int(request.GET.get('order[0][column]'))
181 column_index = safe_int(request.GET.get('order[0][column]'))
182 order_dir = request.GET.get(
182 order_dir = request.GET.get(
183 'order[0][dir]', 'desc')
183 'order[0][dir]', 'desc')
184 order_by = request.GET.get(
184 order_by = request.GET.get(
185 'columns[%s][data][sort]' % column_index, 'name_raw')
185 'columns[%s][data][sort]' % column_index, 'name_raw')
186
186
187 # translate datatable to DB columns
187 # translate datatable to DB columns
188 order_by = column_map.get(order_by) or order_by
188 order_by = column_map.get(order_by) or order_by
189
189
190 search_q = request.GET.get('search[value]')
190 search_q = request.GET.get('search[value]')
191 return search_q, order_by, order_dir
191 return search_q, order_by, order_dir
192
192
193 def _extract_chunk(self, request):
193 def _extract_chunk(self, request):
194 start = safe_int(request.GET.get('start'), 0)
194 start = safe_int(request.GET.get('start'), 0)
195 length = safe_int(request.GET.get('length'), 25)
195 length = safe_int(request.GET.get('length'), 25)
196 draw = safe_int(request.GET.get('draw'))
196 draw = safe_int(request.GET.get('draw'))
197 return draw, start, length
197 return draw, start, length
198
198
199
199
200 class BaseReferencesView(RepoAppView):
200 class BaseReferencesView(RepoAppView):
201 """
201 """
202 Base for reference view for branches, tags and bookmarks.
202 Base for reference view for branches, tags and bookmarks.
203 """
203 """
204 def load_default_context(self):
204 def load_default_context(self):
205 c = self._get_local_tmpl_context()
205 c = self._get_local_tmpl_context()
206
206
207 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
207 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
208 c.repo_info = self.db_repo
208 c.repo_info = self.db_repo
209
209
210 self._register_global_c(c)
210 self._register_global_c(c)
211 return c
211 return c
212
212
213 def load_refs_context(self, ref_items, partials_template):
213 def load_refs_context(self, ref_items, partials_template):
214 _render = PartialRenderer(partials_template)
214 _render = PartialRenderer(partials_template)
215 _data = []
215 _data = []
216 pre_load = ["author", "date", "message"]
216 pre_load = ["author", "date", "message"]
217
217
218 is_svn = h.is_svn(self.rhodecode_vcs_repo)
218 is_svn = h.is_svn(self.rhodecode_vcs_repo)
219 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
219 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
220
220
221 for ref_name, commit_id in ref_items:
221 for ref_name, commit_id in ref_items:
222 commit = self.rhodecode_vcs_repo.get_commit(
222 commit = self.rhodecode_vcs_repo.get_commit(
223 commit_id=commit_id, pre_load=pre_load)
223 commit_id=commit_id, pre_load=pre_load)
224
224
225 # TODO: johbo: Unify generation of reference links
225 # TODO: johbo: Unify generation of reference links
226 use_commit_id = '/' in ref_name or is_svn
226 use_commit_id = '/' in ref_name or is_svn
227 files_url = h.url(
227 files_url = h.url(
228 'files_home',
228 'files_home',
229 repo_name=c.repo_name,
229 repo_name=c.repo_name,
230 f_path=ref_name if is_svn else '',
230 f_path=ref_name if is_svn else '',
231 revision=commit_id if use_commit_id else ref_name,
231 revision=commit_id if use_commit_id else ref_name,
232 at=ref_name)
232 at=ref_name)
233
233
234 _data.append({
234 _data.append({
235 "name": _render('name', ref_name, files_url),
235 "name": _render('name', ref_name, files_url),
236 "name_raw": ref_name,
236 "name_raw": ref_name,
237 "date": _render('date', commit.date),
237 "date": _render('date', commit.date),
238 "date_raw": datetime_to_time(commit.date),
238 "date_raw": datetime_to_time(commit.date),
239 "author": _render('author', commit.author),
239 "author": _render('author', commit.author),
240 "commit": _render(
240 "commit": _render(
241 'commit', commit.message, commit.raw_id, commit.idx),
241 'commit', commit.message, commit.raw_id, commit.idx),
242 "commit_raw": commit.idx,
242 "commit_raw": commit.idx,
243 "compare": _render(
243 "compare": _render(
244 'compare', format_ref_id(ref_name, commit.raw_id)),
244 'compare', format_ref_id(ref_name, commit.raw_id)),
245 })
245 })
246 c.has_references = bool(_data)
246 c.has_references = bool(_data)
247 c.data = json.dumps(_data)
247 c.data = json.dumps(_data)
248
248
249
249
250 class RepoRoutePredicate(object):
250 class RepoRoutePredicate(object):
251 def __init__(self, val, config):
251 def __init__(self, val, config):
252 self.val = val
252 self.val = val
253
253
254 def text(self):
254 def text(self):
255 return 'repo_route = %s' % self.val
255 return 'repo_route = %s' % self.val
256
256
257 phash = text
257 phash = text
258
258
259 def __call__(self, info, request):
259 def __call__(self, info, request):
260
261 if hasattr(request, 'vcs_call'):
262 # skip vcs calls
263 return
264
260 repo_name = info['match']['repo_name']
265 repo_name = info['match']['repo_name']
261 repo_model = repo.RepoModel()
266 repo_model = repo.RepoModel()
262 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
267 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
263
268
264 if by_name_match:
269 if by_name_match:
265 # register this as request object we can re-use later
270 # register this as request object we can re-use later
266 request.db_repo = by_name_match
271 request.db_repo = by_name_match
267 return True
272 return True
268
273
269 by_id_match = repo_model.get_repo_by_id(repo_name)
274 by_id_match = repo_model.get_repo_by_id(repo_name)
270 if by_id_match:
275 if by_id_match:
271 request.db_repo = by_id_match
276 request.db_repo = by_id_match
272 return True
277 return True
273
278
274 return False
279 return False
275
280
276
281
277 class RepoTypeRoutePredicate(object):
282 class RepoTypeRoutePredicate(object):
278 def __init__(self, val, config):
283 def __init__(self, val, config):
279 self.val = val or ['hg', 'git', 'svn']
284 self.val = val or ['hg', 'git', 'svn']
280
285
281 def text(self):
286 def text(self):
282 return 'repo_accepted_type = %s' % self.val
287 return 'repo_accepted_type = %s' % self.val
283
288
284 phash = text
289 phash = text
285
290
286 def __call__(self, info, request):
291 def __call__(self, info, request):
292 if hasattr(request, 'vcs_call'):
293 # skip vcs calls
294 return
287
295
288 rhodecode_db_repo = request.db_repo
296 rhodecode_db_repo = request.db_repo
289
297
290 log.debug(
298 log.debug(
291 '%s checking repo type for %s in %s',
299 '%s checking repo type for %s in %s',
292 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
300 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
293
301
294 if rhodecode_db_repo.repo_type in self.val:
302 if rhodecode_db_repo.repo_type in self.val:
295 return True
303 return True
296 else:
304 else:
297 log.warning('Current view is not supported for repo type:%s',
305 log.warning('Current view is not supported for repo type:%s',
298 rhodecode_db_repo.repo_type)
306 rhodecode_db_repo.repo_type)
299 #
307 #
300 # h.flash(h.literal(
308 # h.flash(h.literal(
301 # _('Action not supported for %s.' % rhodecode_repo.alias)),
309 # _('Action not supported for %s.' % rhodecode_repo.alias)),
302 # category='warning')
310 # category='warning')
303 # return redirect(
311 # return redirect(
304 # url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
312 # url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
305
313
306 return False
314 return False
307
315
308
316
309 class RepoGroupRoutePredicate(object):
317 class RepoGroupRoutePredicate(object):
310 def __init__(self, val, config):
318 def __init__(self, val, config):
311 self.val = val
319 self.val = val
312
320
313 def text(self):
321 def text(self):
314 return 'repo_group_route = %s' % self.val
322 return 'repo_group_route = %s' % self.val
315
323
316 phash = text
324 phash = text
317
325
318 def __call__(self, info, request):
326 def __call__(self, info, request):
327 if hasattr(request, 'vcs_call'):
328 # skip vcs calls
329 return
330
319 repo_group_name = info['match']['repo_group_name']
331 repo_group_name = info['match']['repo_group_name']
320 repo_group_model = repo_group.RepoGroupModel()
332 repo_group_model = repo_group.RepoGroupModel()
321 by_name_match = repo_group_model.get_by_group_name(
333 by_name_match = repo_group_model.get_by_group_name(
322 repo_group_name, cache=True)
334 repo_group_name, cache=True)
323
335
324 if by_name_match:
336 if by_name_match:
325 # register this as request object we can re-use later
337 # register this as request object we can re-use later
326 request.db_repo_group = by_name_match
338 request.db_repo_group = by_name_match
327 return True
339 return True
328
340
329 return False
341 return False
330
342
331
343
332 def includeme(config):
344 def includeme(config):
333 config.add_route_predicate(
345 config.add_route_predicate(
334 'repo_route', RepoRoutePredicate)
346 'repo_route', RepoRoutePredicate)
335 config.add_route_predicate(
347 config.add_route_predicate(
336 'repo_accepted_types', RepoTypeRoutePredicate)
348 'repo_accepted_types', RepoTypeRoutePredicate)
337 config.add_route_predicate(
349 config.add_route_predicate(
338 'repo_group_route', RepoGroupRoutePredicate)
350 'repo_group_route', RepoGroupRoutePredicate)
General Comments 0
You need to be logged in to leave comments. Login now