##// END OF EJS Templates
settings: reduce number of settings fetch since it uses locking for cache invalidation and is generally slow....
marcink -
r3855:e1ec64bd default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,518 +1,519 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2019 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 re
22 22 import logging
23 23 import formencode
24 24 import formencode.htmlfill
25 25 import datetime
26 26 from pyramid.interfaces import IRoutesMapper
27 27
28 28 from pyramid.view import view_config
29 29 from pyramid.httpexceptions import HTTPFound
30 30 from pyramid.renderers import render
31 31 from pyramid.response import Response
32 32
33 33 from rhodecode.apps._base import BaseAppView, DataGridAppView
34 34 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
35 35 from rhodecode import events
36 36
37 37 from rhodecode.lib import helpers as h
38 38 from rhodecode.lib.auth import (
39 39 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
40 40 from rhodecode.lib.utils2 import aslist, safe_unicode
41 41 from rhodecode.model.db import (
42 42 or_, coalesce, User, UserIpMap, UserSshKeys)
43 43 from rhodecode.model.forms import (
44 44 ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
45 45 from rhodecode.model.meta import Session
46 46 from rhodecode.model.permission import PermissionModel
47 47 from rhodecode.model.settings import SettingsModel
48 48
49 49
50 50 log = logging.getLogger(__name__)
51 51
52 52
53 53 class AdminPermissionsView(BaseAppView, DataGridAppView):
54 54 def load_default_context(self):
55 55 c = self._get_local_tmpl_context()
56 56 PermissionModel().set_global_permission_choices(
57 57 c, gettext_translator=self.request.translate)
58 58 return c
59 59
60 60 @LoginRequired()
61 61 @HasPermissionAllDecorator('hg.admin')
62 62 @view_config(
63 63 route_name='admin_permissions_application', request_method='GET',
64 64 renderer='rhodecode:templates/admin/permissions/permissions.mako')
65 65 def permissions_application(self):
66 66 c = self.load_default_context()
67 67 c.active = 'application'
68 68
69 69 c.user = User.get_default_user(refresh=True)
70 70
71 app_settings = SettingsModel().get_all_settings()
71 app_settings = c.rc_config
72
72 73 defaults = {
73 74 'anonymous': c.user.active,
74 75 'default_register_message': app_settings.get(
75 76 'rhodecode_register_message')
76 77 }
77 78 defaults.update(c.user.get_default_perms())
78 79
79 80 data = render('rhodecode:templates/admin/permissions/permissions.mako',
80 81 self._get_template_context(c), self.request)
81 82 html = formencode.htmlfill.render(
82 83 data,
83 84 defaults=defaults,
84 85 encoding="UTF-8",
85 86 force_defaults=False
86 87 )
87 88 return Response(html)
88 89
89 90 @LoginRequired()
90 91 @HasPermissionAllDecorator('hg.admin')
91 92 @CSRFRequired()
92 93 @view_config(
93 94 route_name='admin_permissions_application_update', request_method='POST',
94 95 renderer='rhodecode:templates/admin/permissions/permissions.mako')
95 96 def permissions_application_update(self):
96 97 _ = self.request.translate
97 98 c = self.load_default_context()
98 99 c.active = 'application'
99 100
100 101 _form = ApplicationPermissionsForm(
101 102 self.request.translate,
102 103 [x[0] for x in c.register_choices],
103 104 [x[0] for x in c.password_reset_choices],
104 105 [x[0] for x in c.extern_activate_choices])()
105 106
106 107 try:
107 108 form_result = _form.to_python(dict(self.request.POST))
108 109 form_result.update({'perm_user_name': User.DEFAULT_USER})
109 110 PermissionModel().update_application_permissions(form_result)
110 111
111 112 settings = [
112 113 ('register_message', 'default_register_message'),
113 114 ]
114 115 for setting, form_key in settings:
115 116 sett = SettingsModel().create_or_update_setting(
116 117 setting, form_result[form_key])
117 118 Session().add(sett)
118 119
119 120 Session().commit()
120 121 h.flash(_('Application permissions updated successfully'),
121 122 category='success')
122 123
123 124 except formencode.Invalid as errors:
124 125 defaults = errors.value
125 126
126 127 data = render(
127 128 'rhodecode:templates/admin/permissions/permissions.mako',
128 129 self._get_template_context(c), self.request)
129 130 html = formencode.htmlfill.render(
130 131 data,
131 132 defaults=defaults,
132 133 errors=errors.error_dict or {},
133 134 prefix_error=False,
134 135 encoding="UTF-8",
135 136 force_defaults=False
136 137 )
137 138 return Response(html)
138 139
139 140 except Exception:
140 141 log.exception("Exception during update of permissions")
141 142 h.flash(_('Error occurred during update of permissions'),
142 143 category='error')
143 144
144 145 affected_user_ids = [User.get_default_user().user_id]
145 146 events.trigger(events.UserPermissionsChange(affected_user_ids))
146 147
147 148 raise HTTPFound(h.route_path('admin_permissions_application'))
148 149
149 150 @LoginRequired()
150 151 @HasPermissionAllDecorator('hg.admin')
151 152 @view_config(
152 153 route_name='admin_permissions_object', request_method='GET',
153 154 renderer='rhodecode:templates/admin/permissions/permissions.mako')
154 155 def permissions_objects(self):
155 156 c = self.load_default_context()
156 157 c.active = 'objects'
157 158
158 159 c.user = User.get_default_user(refresh=True)
159 160 defaults = {}
160 161 defaults.update(c.user.get_default_perms())
161 162
162 163 data = render(
163 164 'rhodecode:templates/admin/permissions/permissions.mako',
164 165 self._get_template_context(c), self.request)
165 166 html = formencode.htmlfill.render(
166 167 data,
167 168 defaults=defaults,
168 169 encoding="UTF-8",
169 170 force_defaults=False
170 171 )
171 172 return Response(html)
172 173
173 174 @LoginRequired()
174 175 @HasPermissionAllDecorator('hg.admin')
175 176 @CSRFRequired()
176 177 @view_config(
177 178 route_name='admin_permissions_object_update', request_method='POST',
178 179 renderer='rhodecode:templates/admin/permissions/permissions.mako')
179 180 def permissions_objects_update(self):
180 181 _ = self.request.translate
181 182 c = self.load_default_context()
182 183 c.active = 'objects'
183 184
184 185 _form = ObjectPermissionsForm(
185 186 self.request.translate,
186 187 [x[0] for x in c.repo_perms_choices],
187 188 [x[0] for x in c.group_perms_choices],
188 189 [x[0] for x in c.user_group_perms_choices],
189 190 )()
190 191
191 192 try:
192 193 form_result = _form.to_python(dict(self.request.POST))
193 194 form_result.update({'perm_user_name': User.DEFAULT_USER})
194 195 PermissionModel().update_object_permissions(form_result)
195 196
196 197 Session().commit()
197 198 h.flash(_('Object permissions updated successfully'),
198 199 category='success')
199 200
200 201 except formencode.Invalid as errors:
201 202 defaults = errors.value
202 203
203 204 data = render(
204 205 'rhodecode:templates/admin/permissions/permissions.mako',
205 206 self._get_template_context(c), self.request)
206 207 html = formencode.htmlfill.render(
207 208 data,
208 209 defaults=defaults,
209 210 errors=errors.error_dict or {},
210 211 prefix_error=False,
211 212 encoding="UTF-8",
212 213 force_defaults=False
213 214 )
214 215 return Response(html)
215 216 except Exception:
216 217 log.exception("Exception during update of permissions")
217 218 h.flash(_('Error occurred during update of permissions'),
218 219 category='error')
219 220
220 221 affected_user_ids = [User.get_default_user().user_id]
221 222 events.trigger(events.UserPermissionsChange(affected_user_ids))
222 223
223 224 raise HTTPFound(h.route_path('admin_permissions_object'))
224 225
225 226 @LoginRequired()
226 227 @HasPermissionAllDecorator('hg.admin')
227 228 @view_config(
228 229 route_name='admin_permissions_branch', request_method='GET',
229 230 renderer='rhodecode:templates/admin/permissions/permissions.mako')
230 231 def permissions_branch(self):
231 232 c = self.load_default_context()
232 233 c.active = 'branch'
233 234
234 235 c.user = User.get_default_user(refresh=True)
235 236 defaults = {}
236 237 defaults.update(c.user.get_default_perms())
237 238
238 239 data = render(
239 240 'rhodecode:templates/admin/permissions/permissions.mako',
240 241 self._get_template_context(c), self.request)
241 242 html = formencode.htmlfill.render(
242 243 data,
243 244 defaults=defaults,
244 245 encoding="UTF-8",
245 246 force_defaults=False
246 247 )
247 248 return Response(html)
248 249
249 250 @LoginRequired()
250 251 @HasPermissionAllDecorator('hg.admin')
251 252 @view_config(
252 253 route_name='admin_permissions_global', request_method='GET',
253 254 renderer='rhodecode:templates/admin/permissions/permissions.mako')
254 255 def permissions_global(self):
255 256 c = self.load_default_context()
256 257 c.active = 'global'
257 258
258 259 c.user = User.get_default_user(refresh=True)
259 260 defaults = {}
260 261 defaults.update(c.user.get_default_perms())
261 262
262 263 data = render(
263 264 'rhodecode:templates/admin/permissions/permissions.mako',
264 265 self._get_template_context(c), self.request)
265 266 html = formencode.htmlfill.render(
266 267 data,
267 268 defaults=defaults,
268 269 encoding="UTF-8",
269 270 force_defaults=False
270 271 )
271 272 return Response(html)
272 273
273 274 @LoginRequired()
274 275 @HasPermissionAllDecorator('hg.admin')
275 276 @CSRFRequired()
276 277 @view_config(
277 278 route_name='admin_permissions_global_update', request_method='POST',
278 279 renderer='rhodecode:templates/admin/permissions/permissions.mako')
279 280 def permissions_global_update(self):
280 281 _ = self.request.translate
281 282 c = self.load_default_context()
282 283 c.active = 'global'
283 284
284 285 _form = UserPermissionsForm(
285 286 self.request.translate,
286 287 [x[0] for x in c.repo_create_choices],
287 288 [x[0] for x in c.repo_create_on_write_choices],
288 289 [x[0] for x in c.repo_group_create_choices],
289 290 [x[0] for x in c.user_group_create_choices],
290 291 [x[0] for x in c.fork_choices],
291 292 [x[0] for x in c.inherit_default_permission_choices])()
292 293
293 294 try:
294 295 form_result = _form.to_python(dict(self.request.POST))
295 296 form_result.update({'perm_user_name': User.DEFAULT_USER})
296 297 PermissionModel().update_user_permissions(form_result)
297 298
298 299 Session().commit()
299 300 h.flash(_('Global permissions updated successfully'),
300 301 category='success')
301 302
302 303 except formencode.Invalid as errors:
303 304 defaults = errors.value
304 305
305 306 data = render(
306 307 'rhodecode:templates/admin/permissions/permissions.mako',
307 308 self._get_template_context(c), self.request)
308 309 html = formencode.htmlfill.render(
309 310 data,
310 311 defaults=defaults,
311 312 errors=errors.error_dict or {},
312 313 prefix_error=False,
313 314 encoding="UTF-8",
314 315 force_defaults=False
315 316 )
316 317 return Response(html)
317 318 except Exception:
318 319 log.exception("Exception during update of permissions")
319 320 h.flash(_('Error occurred during update of permissions'),
320 321 category='error')
321 322
322 323 affected_user_ids = [User.get_default_user().user_id]
323 324 events.trigger(events.UserPermissionsChange(affected_user_ids))
324 325
325 326 raise HTTPFound(h.route_path('admin_permissions_global'))
326 327
327 328 @LoginRequired()
328 329 @HasPermissionAllDecorator('hg.admin')
329 330 @view_config(
330 331 route_name='admin_permissions_ips', request_method='GET',
331 332 renderer='rhodecode:templates/admin/permissions/permissions.mako')
332 333 def permissions_ips(self):
333 334 c = self.load_default_context()
334 335 c.active = 'ips'
335 336
336 337 c.user = User.get_default_user(refresh=True)
337 338 c.user_ip_map = (
338 339 UserIpMap.query().filter(UserIpMap.user == c.user).all())
339 340
340 341 return self._get_template_context(c)
341 342
342 343 @LoginRequired()
343 344 @HasPermissionAllDecorator('hg.admin')
344 345 @view_config(
345 346 route_name='admin_permissions_overview', request_method='GET',
346 347 renderer='rhodecode:templates/admin/permissions/permissions.mako')
347 348 def permissions_overview(self):
348 349 c = self.load_default_context()
349 350 c.active = 'perms'
350 351
351 352 c.user = User.get_default_user(refresh=True)
352 353 c.perm_user = c.user.AuthUser()
353 354 return self._get_template_context(c)
354 355
355 356 @LoginRequired()
356 357 @HasPermissionAllDecorator('hg.admin')
357 358 @view_config(
358 359 route_name='admin_permissions_auth_token_access', request_method='GET',
359 360 renderer='rhodecode:templates/admin/permissions/permissions.mako')
360 361 def auth_token_access(self):
361 362 from rhodecode import CONFIG
362 363
363 364 c = self.load_default_context()
364 365 c.active = 'auth_token_access'
365 366
366 367 c.user = User.get_default_user(refresh=True)
367 368 c.perm_user = c.user.AuthUser()
368 369
369 370 mapper = self.request.registry.queryUtility(IRoutesMapper)
370 371 c.view_data = []
371 372
372 373 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
373 374 introspector = self.request.registry.introspector
374 375
375 376 view_intr = {}
376 377 for view_data in introspector.get_category('views'):
377 378 intr = view_data['introspectable']
378 379
379 380 if 'route_name' in intr and intr['attr']:
380 381 view_intr[intr['route_name']] = '{}:{}'.format(
381 382 str(intr['derived_callable'].func_name), intr['attr']
382 383 )
383 384
384 385 c.whitelist_key = 'api_access_controllers_whitelist'
385 386 c.whitelist_file = CONFIG.get('__file__')
386 387 whitelist_views = aslist(
387 388 CONFIG.get(c.whitelist_key), sep=',')
388 389
389 390 for route_info in mapper.get_routes():
390 391 if not route_info.name.startswith('__'):
391 392 routepath = route_info.pattern
392 393
393 394 def replace(matchobj):
394 395 if matchobj.group(1):
395 396 return "{%s}" % matchobj.group(1).split(':')[0]
396 397 else:
397 398 return "{%s}" % matchobj.group(2)
398 399
399 400 routepath = _argument_prog.sub(replace, routepath)
400 401
401 402 if not routepath.startswith('/'):
402 403 routepath = '/' + routepath
403 404
404 405 view_fqn = view_intr.get(route_info.name, 'NOT AVAILABLE')
405 406 active = view_fqn in whitelist_views
406 407 c.view_data.append((route_info.name, view_fqn, routepath, active))
407 408
408 409 c.whitelist_views = whitelist_views
409 410 return self._get_template_context(c)
410 411
411 412 def ssh_enabled(self):
412 413 return self.request.registry.settings.get(
413 414 'ssh.generate_authorized_keyfile')
414 415
415 416 @LoginRequired()
416 417 @HasPermissionAllDecorator('hg.admin')
417 418 @view_config(
418 419 route_name='admin_permissions_ssh_keys', request_method='GET',
419 420 renderer='rhodecode:templates/admin/permissions/permissions.mako')
420 421 def ssh_keys(self):
421 422 c = self.load_default_context()
422 423 c.active = 'ssh_keys'
423 424 c.ssh_enabled = self.ssh_enabled()
424 425 return self._get_template_context(c)
425 426
426 427 @LoginRequired()
427 428 @HasPermissionAllDecorator('hg.admin')
428 429 @view_config(
429 430 route_name='admin_permissions_ssh_keys_data', request_method='GET',
430 431 renderer='json_ext', xhr=True)
431 432 def ssh_keys_data(self):
432 433 _ = self.request.translate
433 434 self.load_default_context()
434 435 column_map = {
435 436 'fingerprint': 'ssh_key_fingerprint',
436 437 'username': User.username
437 438 }
438 439 draw, start, limit = self._extract_chunk(self.request)
439 440 search_q, order_by, order_dir = self._extract_ordering(
440 441 self.request, column_map=column_map)
441 442
442 443 ssh_keys_data_total_count = UserSshKeys.query()\
443 444 .count()
444 445
445 446 # json generate
446 447 base_q = UserSshKeys.query().join(UserSshKeys.user)
447 448
448 449 if search_q:
449 450 like_expression = u'%{}%'.format(safe_unicode(search_q))
450 451 base_q = base_q.filter(or_(
451 452 User.username.ilike(like_expression),
452 453 UserSshKeys.ssh_key_fingerprint.ilike(like_expression),
453 454 ))
454 455
455 456 users_data_total_filtered_count = base_q.count()
456 457
457 458 sort_col = self._get_order_col(order_by, UserSshKeys)
458 459 if sort_col:
459 460 if order_dir == 'asc':
460 461 # handle null values properly to order by NULL last
461 462 if order_by in ['created_on']:
462 463 sort_col = coalesce(sort_col, datetime.date.max)
463 464 sort_col = sort_col.asc()
464 465 else:
465 466 # handle null values properly to order by NULL last
466 467 if order_by in ['created_on']:
467 468 sort_col = coalesce(sort_col, datetime.date.min)
468 469 sort_col = sort_col.desc()
469 470
470 471 base_q = base_q.order_by(sort_col)
471 472 base_q = base_q.offset(start).limit(limit)
472 473
473 474 ssh_keys = base_q.all()
474 475
475 476 ssh_keys_data = []
476 477 for ssh_key in ssh_keys:
477 478 ssh_keys_data.append({
478 479 "username": h.gravatar_with_user(self.request, ssh_key.user.username),
479 480 "fingerprint": ssh_key.ssh_key_fingerprint,
480 481 "description": ssh_key.description,
481 482 "created_on": h.format_date(ssh_key.created_on),
482 483 "accessed_on": h.format_date(ssh_key.accessed_on),
483 484 "action": h.link_to(
484 485 _('Edit'), h.route_path('edit_user_ssh_keys',
485 486 user_id=ssh_key.user.user_id))
486 487 })
487 488
488 489 data = ({
489 490 'draw': draw,
490 491 'data': ssh_keys_data,
491 492 'recordsTotal': ssh_keys_data_total_count,
492 493 'recordsFiltered': users_data_total_filtered_count,
493 494 })
494 495
495 496 return data
496 497
497 498 @LoginRequired()
498 499 @HasPermissionAllDecorator('hg.admin')
499 500 @CSRFRequired()
500 501 @view_config(
501 502 route_name='admin_permissions_ssh_keys_update', request_method='POST',
502 503 renderer='rhodecode:templates/admin/permissions/permissions.mako')
503 504 def ssh_keys_update(self):
504 505 _ = self.request.translate
505 506 self.load_default_context()
506 507
507 508 ssh_enabled = self.ssh_enabled()
508 509 key_file = self.request.registry.settings.get(
509 510 'ssh.authorized_keys_file_path')
510 511 if ssh_enabled:
511 512 events.trigger(SshKeyFileChangeEvent(), self.request.registry)
512 513 h.flash(_('Updated SSH keys file: {}').format(key_file),
513 514 category='success')
514 515 else:
515 516 h.flash(_('SSH key support is disabled in .ini file'),
516 517 category='warning')
517 518
518 519 raise HTTPFound(h.route_path('admin_permissions_ssh_keys'))
@@ -1,780 +1,780 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2019 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
22 22 import logging
23 23 import collections
24 24
25 25 import datetime
26 26 import formencode
27 27 import formencode.htmlfill
28 28
29 29 import rhodecode
30 30 from pyramid.view import view_config
31 31 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
32 32 from pyramid.renderers import render
33 33 from pyramid.response import Response
34 34
35 35 from rhodecode.apps._base import BaseAppView
36 36 from rhodecode.apps._base.navigation import navigation_list
37 37 from rhodecode.apps.svn_support.config_keys import generate_config
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import (
40 40 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
41 41 from rhodecode.lib.celerylib import tasks, run_task
42 42 from rhodecode.lib.utils import repo2db_mapper
43 43 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict
44 44 from rhodecode.lib.index import searcher_from_config
45 45
46 46 from rhodecode.model.db import RhodeCodeUi, Repository
47 47 from rhodecode.model.forms import (ApplicationSettingsForm,
48 48 ApplicationUiSettingsForm, ApplicationVisualisationForm,
49 49 LabsSettingsForm, IssueTrackerPatternsForm)
50 50 from rhodecode.model.repo_group import RepoGroupModel
51 51
52 52 from rhodecode.model.scm import ScmModel
53 53 from rhodecode.model.notification import EmailNotificationModel
54 54 from rhodecode.model.meta import Session
55 55 from rhodecode.model.settings import (
56 56 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
57 57 SettingsModel)
58 58
59 59
60 60 log = logging.getLogger(__name__)
61 61
62 62
63 63 class AdminSettingsView(BaseAppView):
64 64
65 65 def load_default_context(self):
66 66 c = self._get_local_tmpl_context()
67 67 c.labs_active = str2bool(
68 68 rhodecode.CONFIG.get('labs_settings_active', 'true'))
69 69 c.navlist = navigation_list(self.request)
70 70
71 71 return c
72 72
73 73 @classmethod
74 74 def _get_ui_settings(cls):
75 75 ret = RhodeCodeUi.query().all()
76 76
77 77 if not ret:
78 78 raise Exception('Could not get application ui settings !')
79 79 settings = {}
80 80 for each in ret:
81 81 k = each.ui_key
82 82 v = each.ui_value
83 83 if k == '/':
84 84 k = 'root_path'
85 85
86 86 if k in ['push_ssl', 'publish', 'enabled']:
87 87 v = str2bool(v)
88 88
89 89 if k.find('.') != -1:
90 90 k = k.replace('.', '_')
91 91
92 92 if each.ui_section in ['hooks', 'extensions']:
93 93 v = each.ui_active
94 94
95 95 settings[each.ui_section + '_' + k] = v
96 96 return settings
97 97
98 98 @classmethod
99 99 def _form_defaults(cls):
100 100 defaults = SettingsModel().get_all_settings()
101 101 defaults.update(cls._get_ui_settings())
102 102
103 103 defaults.update({
104 104 'new_svn_branch': '',
105 105 'new_svn_tag': '',
106 106 })
107 107 return defaults
108 108
109 109 @LoginRequired()
110 110 @HasPermissionAllDecorator('hg.admin')
111 111 @view_config(
112 112 route_name='admin_settings_vcs', request_method='GET',
113 113 renderer='rhodecode:templates/admin/settings/settings.mako')
114 114 def settings_vcs(self):
115 115 c = self.load_default_context()
116 116 c.active = 'vcs'
117 117 model = VcsSettingsModel()
118 118 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
119 119 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
120 120
121 121 settings = self.request.registry.settings
122 122 c.svn_proxy_generate_config = settings[generate_config]
123 123
124 124 defaults = self._form_defaults()
125 125
126 126 model.create_largeobjects_dirs_if_needed(defaults['paths_root_path'])
127 127
128 128 data = render('rhodecode:templates/admin/settings/settings.mako',
129 129 self._get_template_context(c), self.request)
130 130 html = formencode.htmlfill.render(
131 131 data,
132 132 defaults=defaults,
133 133 encoding="UTF-8",
134 134 force_defaults=False
135 135 )
136 136 return Response(html)
137 137
138 138 @LoginRequired()
139 139 @HasPermissionAllDecorator('hg.admin')
140 140 @CSRFRequired()
141 141 @view_config(
142 142 route_name='admin_settings_vcs_update', request_method='POST',
143 143 renderer='rhodecode:templates/admin/settings/settings.mako')
144 144 def settings_vcs_update(self):
145 145 _ = self.request.translate
146 146 c = self.load_default_context()
147 147 c.active = 'vcs'
148 148
149 149 model = VcsSettingsModel()
150 150 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
151 151 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
152 152
153 153 settings = self.request.registry.settings
154 154 c.svn_proxy_generate_config = settings[generate_config]
155 155
156 156 application_form = ApplicationUiSettingsForm(self.request.translate)()
157 157
158 158 try:
159 159 form_result = application_form.to_python(dict(self.request.POST))
160 160 except formencode.Invalid as errors:
161 161 h.flash(
162 162 _("Some form inputs contain invalid data."),
163 163 category='error')
164 164 data = render('rhodecode:templates/admin/settings/settings.mako',
165 165 self._get_template_context(c), self.request)
166 166 html = formencode.htmlfill.render(
167 167 data,
168 168 defaults=errors.value,
169 169 errors=errors.error_dict or {},
170 170 prefix_error=False,
171 171 encoding="UTF-8",
172 172 force_defaults=False
173 173 )
174 174 return Response(html)
175 175
176 176 try:
177 177 if c.visual.allow_repo_location_change:
178 178 model.update_global_path_setting(form_result['paths_root_path'])
179 179
180 180 model.update_global_ssl_setting(form_result['web_push_ssl'])
181 181 model.update_global_hook_settings(form_result)
182 182
183 183 model.create_or_update_global_svn_settings(form_result)
184 184 model.create_or_update_global_hg_settings(form_result)
185 185 model.create_or_update_global_git_settings(form_result)
186 186 model.create_or_update_global_pr_settings(form_result)
187 187 except Exception:
188 188 log.exception("Exception while updating settings")
189 189 h.flash(_('Error occurred during updating '
190 190 'application settings'), category='error')
191 191 else:
192 192 Session().commit()
193 193 h.flash(_('Updated VCS settings'), category='success')
194 194 raise HTTPFound(h.route_path('admin_settings_vcs'))
195 195
196 196 data = render('rhodecode:templates/admin/settings/settings.mako',
197 197 self._get_template_context(c), self.request)
198 198 html = formencode.htmlfill.render(
199 199 data,
200 200 defaults=self._form_defaults(),
201 201 encoding="UTF-8",
202 202 force_defaults=False
203 203 )
204 204 return Response(html)
205 205
206 206 @LoginRequired()
207 207 @HasPermissionAllDecorator('hg.admin')
208 208 @CSRFRequired()
209 209 @view_config(
210 210 route_name='admin_settings_vcs_svn_pattern_delete', request_method='POST',
211 211 renderer='json_ext', xhr=True)
212 212 def settings_vcs_delete_svn_pattern(self):
213 213 delete_pattern_id = self.request.POST.get('delete_svn_pattern')
214 214 model = VcsSettingsModel()
215 215 try:
216 216 model.delete_global_svn_pattern(delete_pattern_id)
217 217 except SettingNotFound:
218 218 log.exception(
219 219 'Failed to delete svn_pattern with id %s', delete_pattern_id)
220 220 raise HTTPNotFound()
221 221
222 222 Session().commit()
223 223 return True
224 224
225 225 @LoginRequired()
226 226 @HasPermissionAllDecorator('hg.admin')
227 227 @view_config(
228 228 route_name='admin_settings_mapping', request_method='GET',
229 229 renderer='rhodecode:templates/admin/settings/settings.mako')
230 230 def settings_mapping(self):
231 231 c = self.load_default_context()
232 232 c.active = 'mapping'
233 233
234 234 data = render('rhodecode:templates/admin/settings/settings.mako',
235 235 self._get_template_context(c), self.request)
236 236 html = formencode.htmlfill.render(
237 237 data,
238 238 defaults=self._form_defaults(),
239 239 encoding="UTF-8",
240 240 force_defaults=False
241 241 )
242 242 return Response(html)
243 243
244 244 @LoginRequired()
245 245 @HasPermissionAllDecorator('hg.admin')
246 246 @CSRFRequired()
247 247 @view_config(
248 248 route_name='admin_settings_mapping_update', request_method='POST',
249 249 renderer='rhodecode:templates/admin/settings/settings.mako')
250 250 def settings_mapping_update(self):
251 251 _ = self.request.translate
252 252 c = self.load_default_context()
253 253 c.active = 'mapping'
254 254 rm_obsolete = self.request.POST.get('destroy', False)
255 255 invalidate_cache = self.request.POST.get('invalidate', False)
256 256 log.debug(
257 257 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
258 258
259 259 if invalidate_cache:
260 260 log.debug('invalidating all repositories cache')
261 261 for repo in Repository.get_all():
262 262 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
263 263
264 264 filesystem_repos = ScmModel().repo_scan()
265 265 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
266 266 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
267 267 h.flash(_('Repositories successfully '
268 268 'rescanned added: %s ; removed: %s') %
269 269 (_repr(added), _repr(removed)),
270 270 category='success')
271 271 raise HTTPFound(h.route_path('admin_settings_mapping'))
272 272
273 273 @LoginRequired()
274 274 @HasPermissionAllDecorator('hg.admin')
275 275 @view_config(
276 276 route_name='admin_settings', request_method='GET',
277 277 renderer='rhodecode:templates/admin/settings/settings.mako')
278 278 @view_config(
279 279 route_name='admin_settings_global', request_method='GET',
280 280 renderer='rhodecode:templates/admin/settings/settings.mako')
281 281 def settings_global(self):
282 282 c = self.load_default_context()
283 283 c.active = 'global'
284 284 c.personal_repo_group_default_pattern = RepoGroupModel()\
285 285 .get_personal_group_name_pattern()
286 286
287 287 data = render('rhodecode:templates/admin/settings/settings.mako',
288 288 self._get_template_context(c), self.request)
289 289 html = formencode.htmlfill.render(
290 290 data,
291 291 defaults=self._form_defaults(),
292 292 encoding="UTF-8",
293 293 force_defaults=False
294 294 )
295 295 return Response(html)
296 296
297 297 @LoginRequired()
298 298 @HasPermissionAllDecorator('hg.admin')
299 299 @CSRFRequired()
300 300 @view_config(
301 301 route_name='admin_settings_update', request_method='POST',
302 302 renderer='rhodecode:templates/admin/settings/settings.mako')
303 303 @view_config(
304 304 route_name='admin_settings_global_update', request_method='POST',
305 305 renderer='rhodecode:templates/admin/settings/settings.mako')
306 306 def settings_global_update(self):
307 307 _ = self.request.translate
308 308 c = self.load_default_context()
309 309 c.active = 'global'
310 310 c.personal_repo_group_default_pattern = RepoGroupModel()\
311 311 .get_personal_group_name_pattern()
312 312 application_form = ApplicationSettingsForm(self.request.translate)()
313 313 try:
314 314 form_result = application_form.to_python(dict(self.request.POST))
315 315 except formencode.Invalid as errors:
316 316 h.flash(
317 317 _("Some form inputs contain invalid data."),
318 318 category='error')
319 319 data = render('rhodecode:templates/admin/settings/settings.mako',
320 320 self._get_template_context(c), self.request)
321 321 html = formencode.htmlfill.render(
322 322 data,
323 323 defaults=errors.value,
324 324 errors=errors.error_dict or {},
325 325 prefix_error=False,
326 326 encoding="UTF-8",
327 327 force_defaults=False
328 328 )
329 329 return Response(html)
330 330
331 331 settings = [
332 332 ('title', 'rhodecode_title', 'unicode'),
333 333 ('realm', 'rhodecode_realm', 'unicode'),
334 334 ('pre_code', 'rhodecode_pre_code', 'unicode'),
335 335 ('post_code', 'rhodecode_post_code', 'unicode'),
336 336 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
337 337 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
338 338 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
339 339 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
340 340 ]
341 341 try:
342 342 for setting, form_key, type_ in settings:
343 343 sett = SettingsModel().create_or_update_setting(
344 344 setting, form_result[form_key], type_)
345 345 Session().add(sett)
346 346
347 347 Session().commit()
348 348 SettingsModel().invalidate_settings_cache()
349 349 h.flash(_('Updated application settings'), category='success')
350 350 except Exception:
351 351 log.exception("Exception while updating application settings")
352 352 h.flash(
353 353 _('Error occurred during updating application settings'),
354 354 category='error')
355 355
356 356 raise HTTPFound(h.route_path('admin_settings_global'))
357 357
358 358 @LoginRequired()
359 359 @HasPermissionAllDecorator('hg.admin')
360 360 @view_config(
361 361 route_name='admin_settings_visual', request_method='GET',
362 362 renderer='rhodecode:templates/admin/settings/settings.mako')
363 363 def settings_visual(self):
364 364 c = self.load_default_context()
365 365 c.active = 'visual'
366 366
367 367 data = render('rhodecode:templates/admin/settings/settings.mako',
368 368 self._get_template_context(c), self.request)
369 369 html = formencode.htmlfill.render(
370 370 data,
371 371 defaults=self._form_defaults(),
372 372 encoding="UTF-8",
373 373 force_defaults=False
374 374 )
375 375 return Response(html)
376 376
377 377 @LoginRequired()
378 378 @HasPermissionAllDecorator('hg.admin')
379 379 @CSRFRequired()
380 380 @view_config(
381 381 route_name='admin_settings_visual_update', request_method='POST',
382 382 renderer='rhodecode:templates/admin/settings/settings.mako')
383 383 def settings_visual_update(self):
384 384 _ = self.request.translate
385 385 c = self.load_default_context()
386 386 c.active = 'visual'
387 387 application_form = ApplicationVisualisationForm(self.request.translate)()
388 388 try:
389 389 form_result = application_form.to_python(dict(self.request.POST))
390 390 except formencode.Invalid as errors:
391 391 h.flash(
392 392 _("Some form inputs contain invalid data."),
393 393 category='error')
394 394 data = render('rhodecode:templates/admin/settings/settings.mako',
395 395 self._get_template_context(c), self.request)
396 396 html = formencode.htmlfill.render(
397 397 data,
398 398 defaults=errors.value,
399 399 errors=errors.error_dict or {},
400 400 prefix_error=False,
401 401 encoding="UTF-8",
402 402 force_defaults=False
403 403 )
404 404 return Response(html)
405 405
406 406 try:
407 407 settings = [
408 408 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
409 409 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
410 410 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
411 411 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
412 412 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
413 413 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
414 414 ('show_version', 'rhodecode_show_version', 'bool'),
415 415 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
416 416 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
417 417 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
418 418 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
419 419 ('clone_uri_ssh_tmpl', 'rhodecode_clone_uri_ssh_tmpl', 'unicode'),
420 420 ('support_url', 'rhodecode_support_url', 'unicode'),
421 421 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
422 422 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
423 423 ]
424 424 for setting, form_key, type_ in settings:
425 425 sett = SettingsModel().create_or_update_setting(
426 426 setting, form_result[form_key], type_)
427 427 Session().add(sett)
428 428
429 429 Session().commit()
430 430 SettingsModel().invalidate_settings_cache()
431 431 h.flash(_('Updated visualisation settings'), category='success')
432 432 except Exception:
433 433 log.exception("Exception updating visualization settings")
434 434 h.flash(_('Error occurred during updating '
435 435 'visualisation settings'),
436 436 category='error')
437 437
438 438 raise HTTPFound(h.route_path('admin_settings_visual'))
439 439
440 440 @LoginRequired()
441 441 @HasPermissionAllDecorator('hg.admin')
442 442 @view_config(
443 443 route_name='admin_settings_issuetracker', request_method='GET',
444 444 renderer='rhodecode:templates/admin/settings/settings.mako')
445 445 def settings_issuetracker(self):
446 446 c = self.load_default_context()
447 447 c.active = 'issuetracker'
448 defaults = SettingsModel().get_all_settings()
448 defaults = c.rc_config
449 449
450 450 entry_key = 'rhodecode_issuetracker_pat_'
451 451
452 452 c.issuetracker_entries = {}
453 453 for k, v in defaults.items():
454 454 if k.startswith(entry_key):
455 455 uid = k[len(entry_key):]
456 456 c.issuetracker_entries[uid] = None
457 457
458 458 for uid in c.issuetracker_entries:
459 459 c.issuetracker_entries[uid] = AttributeDict({
460 460 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
461 461 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
462 462 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
463 463 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
464 464 })
465 465
466 466 return self._get_template_context(c)
467 467
468 468 @LoginRequired()
469 469 @HasPermissionAllDecorator('hg.admin')
470 470 @CSRFRequired()
471 471 @view_config(
472 472 route_name='admin_settings_issuetracker_test', request_method='POST',
473 473 renderer='string', xhr=True)
474 474 def settings_issuetracker_test(self):
475 475 return h.urlify_commit_message(
476 476 self.request.POST.get('test_text', ''),
477 477 'repo_group/test_repo1')
478 478
479 479 @LoginRequired()
480 480 @HasPermissionAllDecorator('hg.admin')
481 481 @CSRFRequired()
482 482 @view_config(
483 483 route_name='admin_settings_issuetracker_update', request_method='POST',
484 484 renderer='rhodecode:templates/admin/settings/settings.mako')
485 485 def settings_issuetracker_update(self):
486 486 _ = self.request.translate
487 487 self.load_default_context()
488 488 settings_model = IssueTrackerSettingsModel()
489 489
490 490 try:
491 491 form = IssueTrackerPatternsForm(self.request.translate)()
492 492 data = form.to_python(self.request.POST)
493 493 except formencode.Invalid as errors:
494 494 log.exception('Failed to add new pattern')
495 495 error = errors
496 496 h.flash(_('Invalid issue tracker pattern: {}'.format(error)),
497 497 category='error')
498 498 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
499 499
500 500 if data:
501 501 for uid in data.get('delete_patterns', []):
502 502 settings_model.delete_entries(uid)
503 503
504 504 for pattern in data.get('patterns', []):
505 505 for setting, value, type_ in pattern:
506 506 sett = settings_model.create_or_update_setting(
507 507 setting, value, type_)
508 508 Session().add(sett)
509 509
510 510 Session().commit()
511 511
512 512 SettingsModel().invalidate_settings_cache()
513 513 h.flash(_('Updated issue tracker entries'), category='success')
514 514 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
515 515
516 516 @LoginRequired()
517 517 @HasPermissionAllDecorator('hg.admin')
518 518 @CSRFRequired()
519 519 @view_config(
520 520 route_name='admin_settings_issuetracker_delete', request_method='POST',
521 521 renderer='rhodecode:templates/admin/settings/settings.mako')
522 522 def settings_issuetracker_delete(self):
523 523 _ = self.request.translate
524 524 self.load_default_context()
525 525 uid = self.request.POST.get('uid')
526 526 try:
527 527 IssueTrackerSettingsModel().delete_entries(uid)
528 528 except Exception:
529 529 log.exception('Failed to delete issue tracker setting %s', uid)
530 530 raise HTTPNotFound()
531 531 h.flash(_('Removed issue tracker entry'), category='success')
532 532 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
533 533
534 534 @LoginRequired()
535 535 @HasPermissionAllDecorator('hg.admin')
536 536 @view_config(
537 537 route_name='admin_settings_email', request_method='GET',
538 538 renderer='rhodecode:templates/admin/settings/settings.mako')
539 539 def settings_email(self):
540 540 c = self.load_default_context()
541 541 c.active = 'email'
542 542 c.rhodecode_ini = rhodecode.CONFIG
543 543
544 544 data = render('rhodecode:templates/admin/settings/settings.mako',
545 545 self._get_template_context(c), self.request)
546 546 html = formencode.htmlfill.render(
547 547 data,
548 548 defaults=self._form_defaults(),
549 549 encoding="UTF-8",
550 550 force_defaults=False
551 551 )
552 552 return Response(html)
553 553
554 554 @LoginRequired()
555 555 @HasPermissionAllDecorator('hg.admin')
556 556 @CSRFRequired()
557 557 @view_config(
558 558 route_name='admin_settings_email_update', request_method='POST',
559 559 renderer='rhodecode:templates/admin/settings/settings.mako')
560 560 def settings_email_update(self):
561 561 _ = self.request.translate
562 562 c = self.load_default_context()
563 563 c.active = 'email'
564 564
565 565 test_email = self.request.POST.get('test_email')
566 566
567 567 if not test_email:
568 568 h.flash(_('Please enter email address'), category='error')
569 569 raise HTTPFound(h.route_path('admin_settings_email'))
570 570
571 571 email_kwargs = {
572 572 'date': datetime.datetime.now(),
573 573 'user': c.rhodecode_user,
574 574 'rhodecode_version': c.rhodecode_version
575 575 }
576 576
577 577 (subject, headers, email_body,
578 578 email_body_plaintext) = EmailNotificationModel().render_email(
579 579 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
580 580
581 581 recipients = [test_email] if test_email else None
582 582
583 583 run_task(tasks.send_email, recipients, subject,
584 584 email_body_plaintext, email_body)
585 585
586 586 h.flash(_('Send email task created'), category='success')
587 587 raise HTTPFound(h.route_path('admin_settings_email'))
588 588
589 589 @LoginRequired()
590 590 @HasPermissionAllDecorator('hg.admin')
591 591 @view_config(
592 592 route_name='admin_settings_hooks', request_method='GET',
593 593 renderer='rhodecode:templates/admin/settings/settings.mako')
594 594 def settings_hooks(self):
595 595 c = self.load_default_context()
596 596 c.active = 'hooks'
597 597
598 598 model = SettingsModel()
599 599 c.hooks = model.get_builtin_hooks()
600 600 c.custom_hooks = model.get_custom_hooks()
601 601
602 602 data = render('rhodecode:templates/admin/settings/settings.mako',
603 603 self._get_template_context(c), self.request)
604 604 html = formencode.htmlfill.render(
605 605 data,
606 606 defaults=self._form_defaults(),
607 607 encoding="UTF-8",
608 608 force_defaults=False
609 609 )
610 610 return Response(html)
611 611
612 612 @LoginRequired()
613 613 @HasPermissionAllDecorator('hg.admin')
614 614 @CSRFRequired()
615 615 @view_config(
616 616 route_name='admin_settings_hooks_update', request_method='POST',
617 617 renderer='rhodecode:templates/admin/settings/settings.mako')
618 618 @view_config(
619 619 route_name='admin_settings_hooks_delete', request_method='POST',
620 620 renderer='rhodecode:templates/admin/settings/settings.mako')
621 621 def settings_hooks_update(self):
622 622 _ = self.request.translate
623 623 c = self.load_default_context()
624 624 c.active = 'hooks'
625 625 if c.visual.allow_custom_hooks_settings:
626 626 ui_key = self.request.POST.get('new_hook_ui_key')
627 627 ui_value = self.request.POST.get('new_hook_ui_value')
628 628
629 629 hook_id = self.request.POST.get('hook_id')
630 630 new_hook = False
631 631
632 632 model = SettingsModel()
633 633 try:
634 634 if ui_value and ui_key:
635 635 model.create_or_update_hook(ui_key, ui_value)
636 636 h.flash(_('Added new hook'), category='success')
637 637 new_hook = True
638 638 elif hook_id:
639 639 RhodeCodeUi.delete(hook_id)
640 640 Session().commit()
641 641
642 642 # check for edits
643 643 update = False
644 644 _d = self.request.POST.dict_of_lists()
645 645 for k, v in zip(_d.get('hook_ui_key', []),
646 646 _d.get('hook_ui_value_new', [])):
647 647 model.create_or_update_hook(k, v)
648 648 update = True
649 649
650 650 if update and not new_hook:
651 651 h.flash(_('Updated hooks'), category='success')
652 652 Session().commit()
653 653 except Exception:
654 654 log.exception("Exception during hook creation")
655 655 h.flash(_('Error occurred during hook creation'),
656 656 category='error')
657 657
658 658 raise HTTPFound(h.route_path('admin_settings_hooks'))
659 659
660 660 @LoginRequired()
661 661 @HasPermissionAllDecorator('hg.admin')
662 662 @view_config(
663 663 route_name='admin_settings_search', request_method='GET',
664 664 renderer='rhodecode:templates/admin/settings/settings.mako')
665 665 def settings_search(self):
666 666 c = self.load_default_context()
667 667 c.active = 'search'
668 668
669 669 c.searcher = searcher_from_config(self.request.registry.settings)
670 670 c.statistics = c.searcher.statistics(self.request.translate)
671 671
672 672 return self._get_template_context(c)
673 673
674 674 @LoginRequired()
675 675 @HasPermissionAllDecorator('hg.admin')
676 676 @view_config(
677 677 route_name='admin_settings_automation', request_method='GET',
678 678 renderer='rhodecode:templates/admin/settings/settings.mako')
679 679 def settings_automation(self):
680 680 c = self.load_default_context()
681 681 c.active = 'automation'
682 682
683 683 return self._get_template_context(c)
684 684
685 685 @LoginRequired()
686 686 @HasPermissionAllDecorator('hg.admin')
687 687 @view_config(
688 688 route_name='admin_settings_labs', request_method='GET',
689 689 renderer='rhodecode:templates/admin/settings/settings.mako')
690 690 def settings_labs(self):
691 691 c = self.load_default_context()
692 692 if not c.labs_active:
693 693 raise HTTPFound(h.route_path('admin_settings'))
694 694
695 695 c.active = 'labs'
696 696 c.lab_settings = _LAB_SETTINGS
697 697
698 698 data = render('rhodecode:templates/admin/settings/settings.mako',
699 699 self._get_template_context(c), self.request)
700 700 html = formencode.htmlfill.render(
701 701 data,
702 702 defaults=self._form_defaults(),
703 703 encoding="UTF-8",
704 704 force_defaults=False
705 705 )
706 706 return Response(html)
707 707
708 708 @LoginRequired()
709 709 @HasPermissionAllDecorator('hg.admin')
710 710 @CSRFRequired()
711 711 @view_config(
712 712 route_name='admin_settings_labs_update', request_method='POST',
713 713 renderer='rhodecode:templates/admin/settings/settings.mako')
714 714 def settings_labs_update(self):
715 715 _ = self.request.translate
716 716 c = self.load_default_context()
717 717 c.active = 'labs'
718 718
719 719 application_form = LabsSettingsForm(self.request.translate)()
720 720 try:
721 721 form_result = application_form.to_python(dict(self.request.POST))
722 722 except formencode.Invalid as errors:
723 723 h.flash(
724 724 _("Some form inputs contain invalid data."),
725 725 category='error')
726 726 data = render('rhodecode:templates/admin/settings/settings.mako',
727 727 self._get_template_context(c), self.request)
728 728 html = formencode.htmlfill.render(
729 729 data,
730 730 defaults=errors.value,
731 731 errors=errors.error_dict or {},
732 732 prefix_error=False,
733 733 encoding="UTF-8",
734 734 force_defaults=False
735 735 )
736 736 return Response(html)
737 737
738 738 try:
739 739 session = Session()
740 740 for setting in _LAB_SETTINGS:
741 741 setting_name = setting.key[len('rhodecode_'):]
742 742 sett = SettingsModel().create_or_update_setting(
743 743 setting_name, form_result[setting.key], setting.type)
744 744 session.add(sett)
745 745
746 746 except Exception:
747 747 log.exception('Exception while updating lab settings')
748 748 h.flash(_('Error occurred during updating labs settings'),
749 749 category='error')
750 750 else:
751 751 Session().commit()
752 752 SettingsModel().invalidate_settings_cache()
753 753 h.flash(_('Updated Labs settings'), category='success')
754 754 raise HTTPFound(h.route_path('admin_settings_labs'))
755 755
756 756 data = render('rhodecode:templates/admin/settings/settings.mako',
757 757 self._get_template_context(c), self.request)
758 758 html = formencode.htmlfill.render(
759 759 data,
760 760 defaults=self._form_defaults(),
761 761 encoding="UTF-8",
762 762 force_defaults=False
763 763 )
764 764 return Response(html)
765 765
766 766
767 767 # :param key: name of the setting including the 'rhodecode_' prefix
768 768 # :param type: the RhodeCodeSetting type to use.
769 769 # :param group: the i18ned group in which we should dispaly this setting
770 770 # :param label: the i18ned label we should display for this setting
771 771 # :param help: the i18ned help we should dispaly for this setting
772 772 LabSetting = collections.namedtuple(
773 773 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
774 774
775 775
776 776 # This list has to be kept in sync with the form
777 777 # rhodecode.model.forms.LabsSettingsForm.
778 778 _LAB_SETTINGS = [
779 779
780 780 ]
@@ -1,592 +1,592 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2019 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 """
22 22 The base Controller API
23 23 Provides the BaseController class for subclassing. And usage in different
24 24 controllers
25 25 """
26 26
27 27 import logging
28 28 import socket
29 29
30 30 import markupsafe
31 31 import ipaddress
32 32
33 33 from paste.auth.basic import AuthBasicAuthenticator
34 34 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception
35 35 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
36 36
37 37 import rhodecode
38 38 from rhodecode.apps._base import TemplateArgs
39 39 from rhodecode.authentication.base import VCS_TYPE
40 40 from rhodecode.lib import auth, utils2
41 41 from rhodecode.lib import helpers as h
42 42 from rhodecode.lib.auth import AuthUser, CookieStoreWrapper
43 43 from rhodecode.lib.exceptions import UserCreationError
44 44 from rhodecode.lib.utils import (password_changed, get_enabled_hook_classes)
45 45 from rhodecode.lib.utils2 import (
46 46 str2bool, safe_unicode, AttributeDict, safe_int, sha1, aslist, safe_str)
47 47 from rhodecode.model.db import Repository, User, ChangesetComment, UserBookmark
48 48 from rhodecode.model.notification import NotificationModel
49 49 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
50 50
51 51 log = logging.getLogger(__name__)
52 52
53 53
54 54 def _filter_proxy(ip):
55 55 """
56 56 Passed in IP addresses in HEADERS can be in a special format of multiple
57 57 ips. Those comma separated IPs are passed from various proxies in the
58 58 chain of request processing. The left-most being the original client.
59 59 We only care about the first IP which came from the org. client.
60 60
61 61 :param ip: ip string from headers
62 62 """
63 63 if ',' in ip:
64 64 _ips = ip.split(',')
65 65 _first_ip = _ips[0].strip()
66 66 log.debug('Got multiple IPs %s, using %s', ','.join(_ips), _first_ip)
67 67 return _first_ip
68 68 return ip
69 69
70 70
71 71 def _filter_port(ip):
72 72 """
73 73 Removes a port from ip, there are 4 main cases to handle here.
74 74 - ipv4 eg. 127.0.0.1
75 75 - ipv6 eg. ::1
76 76 - ipv4+port eg. 127.0.0.1:8080
77 77 - ipv6+port eg. [::1]:8080
78 78
79 79 :param ip:
80 80 """
81 81 def is_ipv6(ip_addr):
82 82 if hasattr(socket, 'inet_pton'):
83 83 try:
84 84 socket.inet_pton(socket.AF_INET6, ip_addr)
85 85 except socket.error:
86 86 return False
87 87 else:
88 88 # fallback to ipaddress
89 89 try:
90 90 ipaddress.IPv6Address(safe_unicode(ip_addr))
91 91 except Exception:
92 92 return False
93 93 return True
94 94
95 95 if ':' not in ip: # must be ipv4 pure ip
96 96 return ip
97 97
98 98 if '[' in ip and ']' in ip: # ipv6 with port
99 99 return ip.split(']')[0][1:].lower()
100 100
101 101 # must be ipv6 or ipv4 with port
102 102 if is_ipv6(ip):
103 103 return ip
104 104 else:
105 105 ip, _port = ip.split(':')[:2] # means ipv4+port
106 106 return ip
107 107
108 108
109 109 def get_ip_addr(environ):
110 110 proxy_key = 'HTTP_X_REAL_IP'
111 111 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
112 112 def_key = 'REMOTE_ADDR'
113 113 _filters = lambda x: _filter_port(_filter_proxy(x))
114 114
115 115 ip = environ.get(proxy_key)
116 116 if ip:
117 117 return _filters(ip)
118 118
119 119 ip = environ.get(proxy_key2)
120 120 if ip:
121 121 return _filters(ip)
122 122
123 123 ip = environ.get(def_key, '0.0.0.0')
124 124 return _filters(ip)
125 125
126 126
127 127 def get_server_ip_addr(environ, log_errors=True):
128 128 hostname = environ.get('SERVER_NAME')
129 129 try:
130 130 return socket.gethostbyname(hostname)
131 131 except Exception as e:
132 132 if log_errors:
133 133 # in some cases this lookup is not possible, and we don't want to
134 134 # make it an exception in logs
135 135 log.exception('Could not retrieve server ip address: %s', e)
136 136 return hostname
137 137
138 138
139 139 def get_server_port(environ):
140 140 return environ.get('SERVER_PORT')
141 141
142 142
143 143 def get_access_path(environ):
144 144 path = environ.get('PATH_INFO')
145 145 org_req = environ.get('pylons.original_request')
146 146 if org_req:
147 147 path = org_req.environ.get('PATH_INFO')
148 148 return path
149 149
150 150
151 151 def get_user_agent(environ):
152 152 return environ.get('HTTP_USER_AGENT')
153 153
154 154
155 155 def vcs_operation_context(
156 156 environ, repo_name, username, action, scm, check_locking=True,
157 157 is_shadow_repo=False, check_branch_perms=False, detect_force_push=False):
158 158 """
159 159 Generate the context for a vcs operation, e.g. push or pull.
160 160
161 161 This context is passed over the layers so that hooks triggered by the
162 162 vcs operation know details like the user, the user's IP address etc.
163 163
164 164 :param check_locking: Allows to switch of the computation of the locking
165 165 data. This serves mainly the need of the simplevcs middleware to be
166 166 able to disable this for certain operations.
167 167
168 168 """
169 169 # Tri-state value: False: unlock, None: nothing, True: lock
170 170 make_lock = None
171 171 locked_by = [None, None, None]
172 172 is_anonymous = username == User.DEFAULT_USER
173 173 user = User.get_by_username(username)
174 174 if not is_anonymous and check_locking:
175 175 log.debug('Checking locking on repository "%s"', repo_name)
176 176 repo = Repository.get_by_repo_name(repo_name)
177 177 make_lock, __, locked_by = repo.get_locking_state(
178 178 action, user.user_id)
179 179 user_id = user.user_id
180 180 settings_model = VcsSettingsModel(repo=repo_name)
181 181 ui_settings = settings_model.get_ui_settings()
182 182
183 183 # NOTE(marcink): This should be also in sync with
184 184 # rhodecode/apps/ssh_support/lib/backends/base.py:update_environment scm_data
185 185 store = [x for x in ui_settings if x.key == '/']
186 186 repo_store = ''
187 187 if store:
188 188 repo_store = store[0].value
189 189
190 190 scm_data = {
191 191 'ip': get_ip_addr(environ),
192 192 'username': username,
193 193 'user_id': user_id,
194 194 'action': action,
195 195 'repository': repo_name,
196 196 'scm': scm,
197 197 'config': rhodecode.CONFIG['__file__'],
198 198 'repo_store': repo_store,
199 199 'make_lock': make_lock,
200 200 'locked_by': locked_by,
201 201 'server_url': utils2.get_server_url(environ),
202 202 'user_agent': get_user_agent(environ),
203 203 'hooks': get_enabled_hook_classes(ui_settings),
204 204 'is_shadow_repo': is_shadow_repo,
205 205 'detect_force_push': detect_force_push,
206 206 'check_branch_perms': check_branch_perms,
207 207 }
208 208 return scm_data
209 209
210 210
211 211 class BasicAuth(AuthBasicAuthenticator):
212 212
213 213 def __init__(self, realm, authfunc, registry, auth_http_code=None,
214 214 initial_call_detection=False, acl_repo_name=None):
215 215 self.realm = realm
216 216 self.initial_call = initial_call_detection
217 217 self.authfunc = authfunc
218 218 self.registry = registry
219 219 self.acl_repo_name = acl_repo_name
220 220 self._rc_auth_http_code = auth_http_code
221 221
222 222 def _get_response_from_code(self, http_code):
223 223 try:
224 224 return get_exception(safe_int(http_code))
225 225 except Exception:
226 226 log.exception('Failed to fetch response for code %s', http_code)
227 227 return HTTPForbidden
228 228
229 229 def get_rc_realm(self):
230 230 return safe_str(self.registry.rhodecode_settings.get('rhodecode_realm'))
231 231
232 232 def build_authentication(self):
233 233 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
234 234 if self._rc_auth_http_code and not self.initial_call:
235 235 # return alternative HTTP code if alternative http return code
236 236 # is specified in RhodeCode config, but ONLY if it's not the
237 237 # FIRST call
238 238 custom_response_klass = self._get_response_from_code(
239 239 self._rc_auth_http_code)
240 240 return custom_response_klass(headers=head)
241 241 return HTTPUnauthorized(headers=head)
242 242
243 243 def authenticate(self, environ):
244 244 authorization = AUTHORIZATION(environ)
245 245 if not authorization:
246 246 return self.build_authentication()
247 247 (authmeth, auth) = authorization.split(' ', 1)
248 248 if 'basic' != authmeth.lower():
249 249 return self.build_authentication()
250 250 auth = auth.strip().decode('base64')
251 251 _parts = auth.split(':', 1)
252 252 if len(_parts) == 2:
253 253 username, password = _parts
254 254 auth_data = self.authfunc(
255 255 username, password, environ, VCS_TYPE,
256 256 registry=self.registry, acl_repo_name=self.acl_repo_name)
257 257 if auth_data:
258 258 return {'username': username, 'auth_data': auth_data}
259 259 if username and password:
260 260 # we mark that we actually executed authentication once, at
261 261 # that point we can use the alternative auth code
262 262 self.initial_call = False
263 263
264 264 return self.build_authentication()
265 265
266 266 __call__ = authenticate
267 267
268 268
269 269 def calculate_version_hash(config):
270 270 return sha1(
271 271 config.get('beaker.session.secret', '') +
272 272 rhodecode.__version__)[:8]
273 273
274 274
275 275 def get_current_lang(request):
276 276 # NOTE(marcink): remove after pyramid move
277 277 try:
278 278 return translation.get_lang()[0]
279 279 except:
280 280 pass
281 281
282 282 return getattr(request, '_LOCALE_', request.locale_name)
283 283
284 284
285 285 def attach_context_attributes(context, request, user_id=None):
286 286 """
287 287 Attach variables into template context called `c`.
288 288 """
289 289 config = request.registry.settings
290 290
291 291 rc_config = SettingsModel().get_all_settings(cache=True)
292
292 context.rc_config = rc_config
293 293 context.rhodecode_version = rhodecode.__version__
294 294 context.rhodecode_edition = config.get('rhodecode.edition')
295 295 # unique secret + version does not leak the version but keep consistency
296 296 context.rhodecode_version_hash = calculate_version_hash(config)
297 297
298 298 # Default language set for the incoming request
299 299 context.language = get_current_lang(request)
300 300
301 301 # Visual options
302 302 context.visual = AttributeDict({})
303 303
304 304 # DB stored Visual Items
305 305 context.visual.show_public_icon = str2bool(
306 306 rc_config.get('rhodecode_show_public_icon'))
307 307 context.visual.show_private_icon = str2bool(
308 308 rc_config.get('rhodecode_show_private_icon'))
309 309 context.visual.stylify_metatags = str2bool(
310 310 rc_config.get('rhodecode_stylify_metatags'))
311 311 context.visual.dashboard_items = safe_int(
312 312 rc_config.get('rhodecode_dashboard_items', 100))
313 313 context.visual.admin_grid_items = safe_int(
314 314 rc_config.get('rhodecode_admin_grid_items', 100))
315 315 context.visual.show_revision_number = str2bool(
316 316 rc_config.get('rhodecode_show_revision_number', True))
317 317 context.visual.show_sha_length = safe_int(
318 318 rc_config.get('rhodecode_show_sha_length', 100))
319 319 context.visual.repository_fields = str2bool(
320 320 rc_config.get('rhodecode_repository_fields'))
321 321 context.visual.show_version = str2bool(
322 322 rc_config.get('rhodecode_show_version'))
323 323 context.visual.use_gravatar = str2bool(
324 324 rc_config.get('rhodecode_use_gravatar'))
325 325 context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url')
326 326 context.visual.default_renderer = rc_config.get(
327 327 'rhodecode_markup_renderer', 'rst')
328 328 context.visual.comment_types = ChangesetComment.COMMENT_TYPES
329 329 context.visual.rhodecode_support_url = \
330 330 rc_config.get('rhodecode_support_url') or h.route_url('rhodecode_support')
331 331
332 332 context.visual.affected_files_cut_off = 60
333 333
334 334 context.pre_code = rc_config.get('rhodecode_pre_code')
335 335 context.post_code = rc_config.get('rhodecode_post_code')
336 336 context.rhodecode_name = rc_config.get('rhodecode_title')
337 337 context.default_encodings = aslist(config.get('default_encoding'), sep=',')
338 338 # if we have specified default_encoding in the request, it has more
339 339 # priority
340 340 if request.GET.get('default_encoding'):
341 341 context.default_encodings.insert(0, request.GET.get('default_encoding'))
342 342 context.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl')
343 343 context.clone_uri_ssh_tmpl = rc_config.get('rhodecode_clone_uri_ssh_tmpl')
344 344
345 345 # INI stored
346 346 context.labs_active = str2bool(
347 347 config.get('labs_settings_active', 'false'))
348 348 context.ssh_enabled = str2bool(
349 349 config.get('ssh.generate_authorized_keyfile', 'false'))
350 350 context.ssh_key_generator_enabled = str2bool(
351 351 config.get('ssh.enable_ui_key_generator', 'true'))
352 352
353 353 context.visual.allow_repo_location_change = str2bool(
354 354 config.get('allow_repo_location_change', True))
355 355 context.visual.allow_custom_hooks_settings = str2bool(
356 356 config.get('allow_custom_hooks_settings', True))
357 357 context.debug_style = str2bool(config.get('debug_style', False))
358 358
359 359 context.rhodecode_instanceid = config.get('instance_id')
360 360
361 361 context.visual.cut_off_limit_diff = safe_int(
362 362 config.get('cut_off_limit_diff'))
363 363 context.visual.cut_off_limit_file = safe_int(
364 364 config.get('cut_off_limit_file'))
365 365
366 366 # AppEnlight
367 367 context.appenlight_enabled = str2bool(config.get('appenlight', 'false'))
368 368 context.appenlight_api_public_key = config.get(
369 369 'appenlight.api_public_key', '')
370 370 context.appenlight_server_url = config.get('appenlight.server_url', '')
371 371
372 372 diffmode = {
373 373 "unified": "unified",
374 374 "sideside": "sideside"
375 375 }.get(request.GET.get('diffmode'))
376 376
377 377 is_api = hasattr(request, 'rpc_user')
378 378 session_attrs = {
379 379 # defaults
380 380 "clone_url_format": "http",
381 381 "diffmode": "sideside"
382 382 }
383 383
384 384 if not is_api:
385 385 # don't access pyramid session for API calls
386 386 if diffmode and diffmode != request.session.get('rc_user_session_attr.diffmode'):
387 387 request.session['rc_user_session_attr.diffmode'] = diffmode
388 388
389 389 # session settings per user
390 390
391 391 for k, v in request.session.items():
392 392 pref = 'rc_user_session_attr.'
393 393 if k and k.startswith(pref):
394 394 k = k[len(pref):]
395 395 session_attrs[k] = v
396 396
397 397 context.user_session_attrs = session_attrs
398 398
399 399 # JS template context
400 400 context.template_context = {
401 401 'repo_name': None,
402 402 'repo_type': None,
403 403 'repo_landing_commit': None,
404 404 'rhodecode_user': {
405 405 'username': None,
406 406 'email': None,
407 407 'notification_status': False
408 408 },
409 409 'session_attrs': session_attrs,
410 410 'visual': {
411 411 'default_renderer': None
412 412 },
413 413 'commit_data': {
414 414 'commit_id': None
415 415 },
416 416 'pull_request_data': {'pull_request_id': None},
417 417 'timeago': {
418 418 'refresh_time': 120 * 1000,
419 419 'cutoff_limit': 1000 * 60 * 60 * 24 * 7
420 420 },
421 421 'pyramid_dispatch': {
422 422
423 423 },
424 424 'extra': {'plugins': {}}
425 425 }
426 426 # END CONFIG VARS
427 427 if is_api:
428 428 csrf_token = None
429 429 else:
430 430 csrf_token = auth.get_csrf_token(session=request.session)
431 431
432 432 context.csrf_token = csrf_token
433 433 context.backends = rhodecode.BACKENDS.keys()
434 434 context.backends.sort()
435 435 unread_count = 0
436 436 user_bookmark_list = []
437 437 if user_id:
438 438 unread_count = NotificationModel().get_unread_cnt_for_user(user_id)
439 439 user_bookmark_list = UserBookmark.get_bookmarks_for_user(user_id)
440 440 context.unread_notifications = unread_count
441 441 context.bookmark_items = user_bookmark_list
442 442
443 443 # web case
444 444 if hasattr(request, 'user'):
445 445 context.auth_user = request.user
446 446 context.rhodecode_user = request.user
447 447
448 448 # api case
449 449 if hasattr(request, 'rpc_user'):
450 450 context.auth_user = request.rpc_user
451 451 context.rhodecode_user = request.rpc_user
452 452
453 453 # attach the whole call context to the request
454 454 request.call_context = context
455 455
456 456
457 457 def get_auth_user(request):
458 458 environ = request.environ
459 459 session = request.session
460 460
461 461 ip_addr = get_ip_addr(environ)
462 462 # make sure that we update permissions each time we call controller
463 463 _auth_token = (request.GET.get('auth_token', '') or
464 464 request.GET.get('api_key', ''))
465 465
466 466 if _auth_token:
467 467 # when using API_KEY we assume user exists, and
468 468 # doesn't need auth based on cookies.
469 469 auth_user = AuthUser(api_key=_auth_token, ip_addr=ip_addr)
470 470 authenticated = False
471 471 else:
472 472 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
473 473 try:
474 474 auth_user = AuthUser(user_id=cookie_store.get('user_id', None),
475 475 ip_addr=ip_addr)
476 476 except UserCreationError as e:
477 477 h.flash(e, 'error')
478 478 # container auth or other auth functions that create users
479 479 # on the fly can throw this exception signaling that there's
480 480 # issue with user creation, explanation should be provided
481 481 # in Exception itself. We then create a simple blank
482 482 # AuthUser
483 483 auth_user = AuthUser(ip_addr=ip_addr)
484 484
485 485 # in case someone changes a password for user it triggers session
486 486 # flush and forces a re-login
487 487 if password_changed(auth_user, session):
488 488 session.invalidate()
489 489 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
490 490 auth_user = AuthUser(ip_addr=ip_addr)
491 491
492 492 authenticated = cookie_store.get('is_authenticated')
493 493
494 494 if not auth_user.is_authenticated and auth_user.is_user_object:
495 495 # user is not authenticated and not empty
496 496 auth_user.set_authenticated(authenticated)
497 497
498 498 return auth_user
499 499
500 500
501 501 def h_filter(s):
502 502 """
503 503 Custom filter for Mako templates. Mako by standard uses `markupsafe.escape`
504 504 we wrap this with additional functionality that converts None to empty
505 505 strings
506 506 """
507 507 if s is None:
508 508 return markupsafe.Markup()
509 509 return markupsafe.escape(s)
510 510
511 511
512 512 def add_events_routes(config):
513 513 """
514 514 Adds routing that can be used in events. Because some events are triggered
515 515 outside of pyramid context, we need to bootstrap request with some
516 516 routing registered
517 517 """
518 518
519 519 from rhodecode.apps._base import ADMIN_PREFIX
520 520
521 521 config.add_route(name='home', pattern='/')
522 522
523 523 config.add_route(name='login', pattern=ADMIN_PREFIX + '/login')
524 524 config.add_route(name='logout', pattern=ADMIN_PREFIX + '/logout')
525 525 config.add_route(name='repo_summary', pattern='/{repo_name}')
526 526 config.add_route(name='repo_summary_explicit', pattern='/{repo_name}/summary')
527 527 config.add_route(name='repo_group_home', pattern='/{repo_group_name}')
528 528
529 529 config.add_route(name='pullrequest_show',
530 530 pattern='/{repo_name}/pull-request/{pull_request_id}')
531 531 config.add_route(name='pull_requests_global',
532 532 pattern='/pull-request/{pull_request_id}')
533 533 config.add_route(name='repo_commit',
534 534 pattern='/{repo_name}/changeset/{commit_id}')
535 535
536 536 config.add_route(name='repo_files',
537 537 pattern='/{repo_name}/files/{commit_id}/{f_path}')
538 538
539 539
540 540 def bootstrap_config(request):
541 541 import pyramid.testing
542 542 registry = pyramid.testing.Registry('RcTestRegistry')
543 543
544 544 config = pyramid.testing.setUp(registry=registry, request=request)
545 545
546 546 # allow pyramid lookup in testing
547 547 config.include('pyramid_mako')
548 548 config.include('rhodecode.lib.rc_beaker')
549 549 config.include('rhodecode.lib.rc_cache')
550 550
551 551 add_events_routes(config)
552 552
553 553 return config
554 554
555 555
556 556 def bootstrap_request(**kwargs):
557 557 import pyramid.testing
558 558
559 559 class TestRequest(pyramid.testing.DummyRequest):
560 560 application_url = kwargs.pop('application_url', 'http://example.com')
561 561 host = kwargs.pop('host', 'example.com:80')
562 562 domain = kwargs.pop('domain', 'example.com')
563 563
564 564 def translate(self, msg):
565 565 return msg
566 566
567 567 def plularize(self, singular, plural, n):
568 568 return singular
569 569
570 570 def get_partial_renderer(self, tmpl_name):
571 571
572 572 from rhodecode.lib.partial_renderer import get_partial_renderer
573 573 return get_partial_renderer(request=self, tmpl_name=tmpl_name)
574 574
575 575 _call_context = TemplateArgs()
576 576 _call_context.visual = TemplateArgs()
577 577 _call_context.visual.show_sha_length = 12
578 578 _call_context.visual.show_revision_number = True
579 579
580 580 @property
581 581 def call_context(self):
582 582 return self._call_context
583 583
584 584 class TestDummySession(pyramid.testing.DummySession):
585 585 def save(*arg, **kw):
586 586 pass
587 587
588 588 request = TestRequest(**kwargs)
589 589 request.session = TestDummySession()
590 590
591 591 return request
592 592
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now