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