##// END OF EJS Templates
svn-support: Only show 'generate config' button if config generation is enabled.
Martin Bornhold -
r1022:79b4d791 default
parent child Browse files
Show More
@@ -1,797 +1,803 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 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 """
23 23 settings controller for rhodecode admin
24 24 """
25 25
26 26 import collections
27 27 import logging
28 28 import urllib2
29 29
30 30 import datetime
31 31 import formencode
32 32 from formencode import htmlfill
33 33 import packaging.version
34 34 from pylons import request, tmpl_context as c, url, config
35 35 from pylons.controllers.util import redirect
36 36 from pylons.i18n.translation import _, lazy_ugettext
37 from pyramid.threadlocal import get_current_registry
37 38 from webob.exc import HTTPBadRequest
38 39
39 40 import rhodecode
40 41 from rhodecode.admin.navigation import navigation_list
41 42 from rhodecode.lib import auth
42 43 from rhodecode.lib import helpers as h
43 44 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
44 45 from rhodecode.lib.base import BaseController, render
45 46 from rhodecode.lib.celerylib import tasks, run_task
46 47 from rhodecode.lib.utils import repo2db_mapper
47 48 from rhodecode.lib.utils2 import (
48 49 str2bool, safe_unicode, AttributeDict, safe_int)
49 50 from rhodecode.lib.compat import OrderedDict
50 51 from rhodecode.lib.ext_json import json
51 52 from rhodecode.lib.utils import jsonify
52 53
53 54 from rhodecode.model.db import RhodeCodeUi, Repository
54 55 from rhodecode.model.forms import ApplicationSettingsForm, \
55 56 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
56 57 LabsSettingsForm, IssueTrackerPatternsForm
57 58
58 59 from rhodecode.model.scm import ScmModel
59 60 from rhodecode.model.notification import EmailNotificationModel
60 61 from rhodecode.model.meta import Session
61 62 from rhodecode.model.settings import (
62 63 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
63 64 SettingsModel)
64 65
65 66 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
67 from rhodecode.svn_support.config_keys import generate_config
66 68
67 69
68 70 log = logging.getLogger(__name__)
69 71
70 72
71 73 class SettingsController(BaseController):
72 74 """REST Controller styled on the Atom Publishing Protocol"""
73 75 # To properly map this controller, ensure your config/routing.py
74 76 # file has a resource setup:
75 77 # map.resource('setting', 'settings', controller='admin/settings',
76 78 # path_prefix='/admin', name_prefix='admin_')
77 79
78 80 @LoginRequired()
79 81 def __before__(self):
80 82 super(SettingsController, self).__before__()
81 83 c.labs_active = str2bool(
82 84 rhodecode.CONFIG.get('labs_settings_active', 'true'))
83 85 c.navlist = navigation_list(request)
84 86
85 87 def _get_hg_ui_settings(self):
86 88 ret = RhodeCodeUi.query().all()
87 89
88 90 if not ret:
89 91 raise Exception('Could not get application ui settings !')
90 92 settings = {}
91 93 for each in ret:
92 94 k = each.ui_key
93 95 v = each.ui_value
94 96 if k == '/':
95 97 k = 'root_path'
96 98
97 99 if k in ['push_ssl', 'publish']:
98 100 v = str2bool(v)
99 101
100 102 if k.find('.') != -1:
101 103 k = k.replace('.', '_')
102 104
103 105 if each.ui_section in ['hooks', 'extensions']:
104 106 v = each.ui_active
105 107
106 108 settings[each.ui_section + '_' + k] = v
107 109 return settings
108 110
109 111 @HasPermissionAllDecorator('hg.admin')
110 112 @auth.CSRFRequired()
111 113 @jsonify
112 114 def delete_svn_pattern(self):
113 115 if not request.is_xhr:
114 116 raise HTTPBadRequest()
115 117
116 118 delete_pattern_id = request.POST.get('delete_svn_pattern')
117 119 model = VcsSettingsModel()
118 120 try:
119 121 model.delete_global_svn_pattern(delete_pattern_id)
120 122 except SettingNotFound:
121 123 raise HTTPBadRequest()
122 124
123 125 Session().commit()
124 126 return True
125 127
126 128 @HasPermissionAllDecorator('hg.admin')
127 129 @auth.CSRFRequired()
128 130 def settings_vcs_update(self):
129 131 """POST /admin/settings: All items in the collection"""
130 132 # url('admin_settings_vcs')
131 133 c.active = 'vcs'
132 134
133 135 model = VcsSettingsModel()
134 136 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
135 137 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
136 138
137 139 application_form = ApplicationUiSettingsForm()()
138 140
139 141 try:
140 142 form_result = application_form.to_python(dict(request.POST))
141 143 except formencode.Invalid as errors:
142 144 h.flash(
143 145 _("Some form inputs contain invalid data."),
144 146 category='error')
145 147 return htmlfill.render(
146 148 render('admin/settings/settings.html'),
147 149 defaults=errors.value,
148 150 errors=errors.error_dict or {},
149 151 prefix_error=False,
150 152 encoding="UTF-8",
151 153 force_defaults=False
152 154 )
153 155
154 156 try:
155 157 if c.visual.allow_repo_location_change:
156 158 model.update_global_path_setting(
157 159 form_result['paths_root_path'])
158 160
159 161 model.update_global_ssl_setting(form_result['web_push_ssl'])
160 162 model.update_global_hook_settings(form_result)
161 163
162 164 model.create_or_update_global_svn_settings(form_result)
163 165 model.create_or_update_global_hg_settings(form_result)
164 166 model.create_or_update_global_pr_settings(form_result)
165 167 except Exception:
166 168 log.exception("Exception while updating settings")
167 169 h.flash(_('Error occurred during updating '
168 170 'application settings'), category='error')
169 171 else:
170 172 Session().commit()
171 173 h.flash(_('Updated VCS settings'), category='success')
172 174 return redirect(url('admin_settings_vcs'))
173 175
174 176 return htmlfill.render(
175 177 render('admin/settings/settings.html'),
176 178 defaults=self._form_defaults(),
177 179 encoding="UTF-8",
178 180 force_defaults=False)
179 181
180 182 @HasPermissionAllDecorator('hg.admin')
181 183 def settings_vcs(self):
182 184 """GET /admin/settings: All items in the collection"""
183 185 # url('admin_settings_vcs')
184 186 c.active = 'vcs'
185 187 model = VcsSettingsModel()
186 188 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
187 189 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
188 190
191 # TODO: Replace with request.registry after migrating to pyramid.
192 pyramid_settings = get_current_registry().settings
193 c.svn_proxy_generate_config = pyramid_settings[generate_config]
194
189 195 return htmlfill.render(
190 196 render('admin/settings/settings.html'),
191 197 defaults=self._form_defaults(),
192 198 encoding="UTF-8",
193 199 force_defaults=False)
194 200
195 201 @HasPermissionAllDecorator('hg.admin')
196 202 @auth.CSRFRequired()
197 203 def settings_mapping_update(self):
198 204 """POST /admin/settings/mapping: All items in the collection"""
199 205 # url('admin_settings_mapping')
200 206 c.active = 'mapping'
201 207 rm_obsolete = request.POST.get('destroy', False)
202 208 invalidate_cache = request.POST.get('invalidate', False)
203 209 log.debug(
204 210 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
205 211
206 212 if invalidate_cache:
207 213 log.debug('invalidating all repositories cache')
208 214 for repo in Repository.get_all():
209 215 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
210 216
211 217 filesystem_repos = ScmModel().repo_scan()
212 218 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
213 219 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
214 220 h.flash(_('Repositories successfully '
215 221 'rescanned added: %s ; removed: %s') %
216 222 (_repr(added), _repr(removed)),
217 223 category='success')
218 224 return redirect(url('admin_settings_mapping'))
219 225
220 226 @HasPermissionAllDecorator('hg.admin')
221 227 def settings_mapping(self):
222 228 """GET /admin/settings/mapping: All items in the collection"""
223 229 # url('admin_settings_mapping')
224 230 c.active = 'mapping'
225 231
226 232 return htmlfill.render(
227 233 render('admin/settings/settings.html'),
228 234 defaults=self._form_defaults(),
229 235 encoding="UTF-8",
230 236 force_defaults=False)
231 237
232 238 @HasPermissionAllDecorator('hg.admin')
233 239 @auth.CSRFRequired()
234 240 def settings_global_update(self):
235 241 """POST /admin/settings/global: All items in the collection"""
236 242 # url('admin_settings_global')
237 243 c.active = 'global'
238 244 application_form = ApplicationSettingsForm()()
239 245 try:
240 246 form_result = application_form.to_python(dict(request.POST))
241 247 except formencode.Invalid as errors:
242 248 return htmlfill.render(
243 249 render('admin/settings/settings.html'),
244 250 defaults=errors.value,
245 251 errors=errors.error_dict or {},
246 252 prefix_error=False,
247 253 encoding="UTF-8",
248 254 force_defaults=False)
249 255
250 256 try:
251 257 settings = [
252 258 ('title', 'rhodecode_title'),
253 259 ('realm', 'rhodecode_realm'),
254 260 ('pre_code', 'rhodecode_pre_code'),
255 261 ('post_code', 'rhodecode_post_code'),
256 262 ('captcha_public_key', 'rhodecode_captcha_public_key'),
257 263 ('captcha_private_key', 'rhodecode_captcha_private_key'),
258 264 ]
259 265 for setting, form_key in settings:
260 266 sett = SettingsModel().create_or_update_setting(
261 267 setting, form_result[form_key])
262 268 Session().add(sett)
263 269
264 270 Session().commit()
265 271 SettingsModel().invalidate_settings_cache()
266 272 h.flash(_('Updated application settings'), category='success')
267 273 except Exception:
268 274 log.exception("Exception while updating application settings")
269 275 h.flash(
270 276 _('Error occurred during updating application settings'),
271 277 category='error')
272 278
273 279 return redirect(url('admin_settings_global'))
274 280
275 281 @HasPermissionAllDecorator('hg.admin')
276 282 def settings_global(self):
277 283 """GET /admin/settings/global: All items in the collection"""
278 284 # url('admin_settings_global')
279 285 c.active = 'global'
280 286
281 287 return htmlfill.render(
282 288 render('admin/settings/settings.html'),
283 289 defaults=self._form_defaults(),
284 290 encoding="UTF-8",
285 291 force_defaults=False)
286 292
287 293 @HasPermissionAllDecorator('hg.admin')
288 294 @auth.CSRFRequired()
289 295 def settings_visual_update(self):
290 296 """POST /admin/settings/visual: All items in the collection"""
291 297 # url('admin_settings_visual')
292 298 c.active = 'visual'
293 299 application_form = ApplicationVisualisationForm()()
294 300 try:
295 301 form_result = application_form.to_python(dict(request.POST))
296 302 except formencode.Invalid as errors:
297 303 return htmlfill.render(
298 304 render('admin/settings/settings.html'),
299 305 defaults=errors.value,
300 306 errors=errors.error_dict or {},
301 307 prefix_error=False,
302 308 encoding="UTF-8",
303 309 force_defaults=False
304 310 )
305 311
306 312 try:
307 313 settings = [
308 314 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
309 315 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
310 316 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
311 317 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
312 318 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
313 319 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
314 320 ('show_version', 'rhodecode_show_version', 'bool'),
315 321 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
316 322 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
317 323 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
318 324 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
319 325 ('support_url', 'rhodecode_support_url', 'unicode'),
320 326 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
321 327 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
322 328 ]
323 329 for setting, form_key, type_ in settings:
324 330 sett = SettingsModel().create_or_update_setting(
325 331 setting, form_result[form_key], type_)
326 332 Session().add(sett)
327 333
328 334 Session().commit()
329 335 SettingsModel().invalidate_settings_cache()
330 336 h.flash(_('Updated visualisation settings'), category='success')
331 337 except Exception:
332 338 log.exception("Exception updating visualization settings")
333 339 h.flash(_('Error occurred during updating '
334 340 'visualisation settings'),
335 341 category='error')
336 342
337 343 return redirect(url('admin_settings_visual'))
338 344
339 345 @HasPermissionAllDecorator('hg.admin')
340 346 def settings_visual(self):
341 347 """GET /admin/settings/visual: All items in the collection"""
342 348 # url('admin_settings_visual')
343 349 c.active = 'visual'
344 350
345 351 return htmlfill.render(
346 352 render('admin/settings/settings.html'),
347 353 defaults=self._form_defaults(),
348 354 encoding="UTF-8",
349 355 force_defaults=False)
350 356
351 357 @HasPermissionAllDecorator('hg.admin')
352 358 @auth.CSRFRequired()
353 359 def settings_issuetracker_test(self):
354 360 if request.is_xhr:
355 361 return h.urlify_commit_message(
356 362 request.POST.get('test_text', ''),
357 363 'repo_group/test_repo1')
358 364 else:
359 365 raise HTTPBadRequest()
360 366
361 367 @HasPermissionAllDecorator('hg.admin')
362 368 @auth.CSRFRequired()
363 369 def settings_issuetracker_delete(self):
364 370 uid = request.POST.get('uid')
365 371 IssueTrackerSettingsModel().delete_entries(uid)
366 372 h.flash(_('Removed issue tracker entry'), category='success')
367 373 return redirect(url('admin_settings_issuetracker'))
368 374
369 375 @HasPermissionAllDecorator('hg.admin')
370 376 def settings_issuetracker(self):
371 377 """GET /admin/settings/issue-tracker: All items in the collection"""
372 378 # url('admin_settings_issuetracker')
373 379 c.active = 'issuetracker'
374 380 defaults = SettingsModel().get_all_settings()
375 381
376 382 entry_key = 'rhodecode_issuetracker_pat_'
377 383
378 384 c.issuetracker_entries = {}
379 385 for k, v in defaults.items():
380 386 if k.startswith(entry_key):
381 387 uid = k[len(entry_key):]
382 388 c.issuetracker_entries[uid] = None
383 389
384 390 for uid in c.issuetracker_entries:
385 391 c.issuetracker_entries[uid] = AttributeDict({
386 392 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
387 393 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
388 394 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
389 395 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
390 396 })
391 397
392 398 return render('admin/settings/settings.html')
393 399
394 400 @HasPermissionAllDecorator('hg.admin')
395 401 @auth.CSRFRequired()
396 402 def settings_issuetracker_save(self):
397 403 settings_model = IssueTrackerSettingsModel()
398 404
399 405 form = IssueTrackerPatternsForm()().to_python(request.POST)
400 406 if form:
401 407 for uid in form.get('delete_patterns', []):
402 408 settings_model.delete_entries(uid)
403 409
404 410 for pattern in form.get('patterns', []):
405 411 for setting, value, type_ in pattern:
406 412 sett = settings_model.create_or_update_setting(
407 413 setting, value, type_)
408 414 Session().add(sett)
409 415
410 416 Session().commit()
411 417
412 418 SettingsModel().invalidate_settings_cache()
413 419 h.flash(_('Updated issue tracker entries'), category='success')
414 420 return redirect(url('admin_settings_issuetracker'))
415 421
416 422 @HasPermissionAllDecorator('hg.admin')
417 423 @auth.CSRFRequired()
418 424 def settings_email_update(self):
419 425 """POST /admin/settings/email: All items in the collection"""
420 426 # url('admin_settings_email')
421 427 c.active = 'email'
422 428
423 429 test_email = request.POST.get('test_email')
424 430
425 431 if not test_email:
426 432 h.flash(_('Please enter email address'), category='error')
427 433 return redirect(url('admin_settings_email'))
428 434
429 435 email_kwargs = {
430 436 'date': datetime.datetime.now(),
431 437 'user': c.rhodecode_user,
432 438 'rhodecode_version': c.rhodecode_version
433 439 }
434 440
435 441 (subject, headers, email_body,
436 442 email_body_plaintext) = EmailNotificationModel().render_email(
437 443 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
438 444
439 445 recipients = [test_email] if test_email else None
440 446
441 447 run_task(tasks.send_email, recipients, subject,
442 448 email_body_plaintext, email_body)
443 449
444 450 h.flash(_('Send email task created'), category='success')
445 451 return redirect(url('admin_settings_email'))
446 452
447 453 @HasPermissionAllDecorator('hg.admin')
448 454 def settings_email(self):
449 455 """GET /admin/settings/email: All items in the collection"""
450 456 # url('admin_settings_email')
451 457 c.active = 'email'
452 458 c.rhodecode_ini = rhodecode.CONFIG
453 459
454 460 return htmlfill.render(
455 461 render('admin/settings/settings.html'),
456 462 defaults=self._form_defaults(),
457 463 encoding="UTF-8",
458 464 force_defaults=False)
459 465
460 466 @HasPermissionAllDecorator('hg.admin')
461 467 @auth.CSRFRequired()
462 468 def settings_hooks_update(self):
463 469 """POST or DELETE /admin/settings/hooks: All items in the collection"""
464 470 # url('admin_settings_hooks')
465 471 c.active = 'hooks'
466 472 if c.visual.allow_custom_hooks_settings:
467 473 ui_key = request.POST.get('new_hook_ui_key')
468 474 ui_value = request.POST.get('new_hook_ui_value')
469 475
470 476 hook_id = request.POST.get('hook_id')
471 477 new_hook = False
472 478
473 479 model = SettingsModel()
474 480 try:
475 481 if ui_value and ui_key:
476 482 model.create_or_update_hook(ui_key, ui_value)
477 483 h.flash(_('Added new hook'), category='success')
478 484 new_hook = True
479 485 elif hook_id:
480 486 RhodeCodeUi.delete(hook_id)
481 487 Session().commit()
482 488
483 489 # check for edits
484 490 update = False
485 491 _d = request.POST.dict_of_lists()
486 492 for k, v in zip(_d.get('hook_ui_key', []),
487 493 _d.get('hook_ui_value_new', [])):
488 494 model.create_or_update_hook(k, v)
489 495 update = True
490 496
491 497 if update and not new_hook:
492 498 h.flash(_('Updated hooks'), category='success')
493 499 Session().commit()
494 500 except Exception:
495 501 log.exception("Exception during hook creation")
496 502 h.flash(_('Error occurred during hook creation'),
497 503 category='error')
498 504
499 505 return redirect(url('admin_settings_hooks'))
500 506
501 507 @HasPermissionAllDecorator('hg.admin')
502 508 def settings_hooks(self):
503 509 """GET /admin/settings/hooks: All items in the collection"""
504 510 # url('admin_settings_hooks')
505 511 c.active = 'hooks'
506 512
507 513 model = SettingsModel()
508 514 c.hooks = model.get_builtin_hooks()
509 515 c.custom_hooks = model.get_custom_hooks()
510 516
511 517 return htmlfill.render(
512 518 render('admin/settings/settings.html'),
513 519 defaults=self._form_defaults(),
514 520 encoding="UTF-8",
515 521 force_defaults=False)
516 522
517 523 @HasPermissionAllDecorator('hg.admin')
518 524 def settings_search(self):
519 525 """GET /admin/settings/search: All items in the collection"""
520 526 # url('admin_settings_search')
521 527 c.active = 'search'
522 528
523 529 from rhodecode.lib.index import searcher_from_config
524 530 searcher = searcher_from_config(config)
525 531 c.statistics = searcher.statistics()
526 532
527 533 return render('admin/settings/settings.html')
528 534
529 535 @HasPermissionAllDecorator('hg.admin')
530 536 def settings_system(self):
531 537 """GET /admin/settings/system: All items in the collection"""
532 538 # url('admin_settings_system')
533 539 snapshot = str2bool(request.GET.get('snapshot'))
534 540 c.active = 'system'
535 541
536 542 defaults = self._form_defaults()
537 543 c.rhodecode_ini = rhodecode.CONFIG
538 544 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
539 545 server_info = ScmModel().get_server_info(request.environ)
540 546 for key, val in server_info.iteritems():
541 547 setattr(c, key, val)
542 548
543 549 if c.disk['percent'] > 90:
544 550 h.flash(h.literal(_(
545 551 'Critical: your disk space is very low <b>%s%%</b> used' %
546 552 c.disk['percent'])), 'error')
547 553 elif c.disk['percent'] > 70:
548 554 h.flash(h.literal(_(
549 555 'Warning: your disk space is running low <b>%s%%</b> used' %
550 556 c.disk['percent'])), 'warning')
551 557
552 558 try:
553 559 c.uptime_age = h._age(
554 560 h.time_to_datetime(c.boot_time), False, show_suffix=False)
555 561 except TypeError:
556 562 c.uptime_age = c.boot_time
557 563
558 564 try:
559 565 c.system_memory = '%s/%s, %s%% (%s%%) used%s' % (
560 566 h.format_byte_size_binary(c.memory['used']),
561 567 h.format_byte_size_binary(c.memory['total']),
562 568 c.memory['percent2'],
563 569 c.memory['percent'],
564 570 ' %s' % c.memory['error'] if 'error' in c.memory else '')
565 571 except TypeError:
566 572 c.system_memory = 'NOT AVAILABLE'
567 573
568 574 rhodecode_ini_safe = rhodecode.CONFIG.copy()
569 575 blacklist = [
570 576 'rhodecode_license_key',
571 577 'routes.map',
572 578 'pylons.h',
573 579 'pylons.app_globals',
574 580 'pylons.environ_config',
575 581 'sqlalchemy.db1.url',
576 582 ('app_conf', 'sqlalchemy.db1.url')
577 583 ]
578 584 for k in blacklist:
579 585 if isinstance(k, tuple):
580 586 section, key = k
581 587 if section in rhodecode_ini_safe:
582 588 rhodecode_ini_safe[section].pop(key, None)
583 589 else:
584 590 rhodecode_ini_safe.pop(k, None)
585 591
586 592 c.rhodecode_ini_safe = rhodecode_ini_safe
587 593
588 594 # TODO: marcink, figure out how to allow only selected users to do this
589 595 c.allowed_to_snapshot = False
590 596
591 597 if snapshot:
592 598 if c.allowed_to_snapshot:
593 599 return render('admin/settings/settings_system_snapshot.html')
594 600 else:
595 601 h.flash('You are not allowed to do this', category='warning')
596 602
597 603 return htmlfill.render(
598 604 render('admin/settings/settings.html'),
599 605 defaults=defaults,
600 606 encoding="UTF-8",
601 607 force_defaults=False)
602 608
603 609 @staticmethod
604 610 def get_update_data(update_url):
605 611 """Return the JSON update data."""
606 612 ver = rhodecode.__version__
607 613 log.debug('Checking for upgrade on `%s` server', update_url)
608 614 opener = urllib2.build_opener()
609 615 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
610 616 response = opener.open(update_url)
611 617 response_data = response.read()
612 618 data = json.loads(response_data)
613 619
614 620 return data
615 621
616 622 @HasPermissionAllDecorator('hg.admin')
617 623 def settings_system_update(self):
618 624 """GET /admin/settings/system/updates: All items in the collection"""
619 625 # url('admin_settings_system_update')
620 626 defaults = self._form_defaults()
621 627 update_url = defaults.get('rhodecode_update_url', '')
622 628
623 629 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
624 630 try:
625 631 data = self.get_update_data(update_url)
626 632 except urllib2.URLError as e:
627 633 log.exception("Exception contacting upgrade server")
628 634 return _err('Failed to contact upgrade server: %r' % e)
629 635 except ValueError as e:
630 636 log.exception("Bad data sent from update server")
631 637 return _err('Bad data sent from update server')
632 638
633 639 latest = data['versions'][0]
634 640
635 641 c.update_url = update_url
636 642 c.latest_data = latest
637 643 c.latest_ver = latest['version']
638 644 c.cur_ver = rhodecode.__version__
639 645 c.should_upgrade = False
640 646
641 647 if (packaging.version.Version(c.latest_ver) >
642 648 packaging.version.Version(c.cur_ver)):
643 649 c.should_upgrade = True
644 650 c.important_notices = latest['general']
645 651
646 652 return render('admin/settings/settings_system_update.html')
647 653
648 654 @HasPermissionAllDecorator('hg.admin')
649 655 def settings_supervisor(self):
650 656 c.rhodecode_ini = rhodecode.CONFIG
651 657 c.active = 'supervisor'
652 658
653 659 c.supervisor_procs = OrderedDict([
654 660 (SUPERVISOR_MASTER, {}),
655 661 ])
656 662
657 663 c.log_size = 10240
658 664 supervisor = SupervisorModel()
659 665
660 666 _connection = supervisor.get_connection(
661 667 c.rhodecode_ini.get('supervisor.uri'))
662 668 c.connection_error = None
663 669 try:
664 670 _connection.supervisor.getAllProcessInfo()
665 671 except Exception as e:
666 672 c.connection_error = str(e)
667 673 log.exception("Exception reading supervisor data")
668 674 return render('admin/settings/settings.html')
669 675
670 676 groupid = c.rhodecode_ini.get('supervisor.group_id')
671 677
672 678 # feed our group processes to the main
673 679 for proc in supervisor.get_group_processes(_connection, groupid):
674 680 c.supervisor_procs[proc['name']] = {}
675 681
676 682 for k in c.supervisor_procs.keys():
677 683 try:
678 684 # master process info
679 685 if k == SUPERVISOR_MASTER:
680 686 _data = supervisor.get_master_state(_connection)
681 687 _data['name'] = 'supervisor master'
682 688 _data['description'] = 'pid %s, id: %s, ver: %s' % (
683 689 _data['pid'], _data['id'], _data['ver'])
684 690 c.supervisor_procs[k] = _data
685 691 else:
686 692 procid = groupid + ":" + k
687 693 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
688 694 except Exception as e:
689 695 log.exception("Exception reading supervisor data")
690 696 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
691 697
692 698 return render('admin/settings/settings.html')
693 699
694 700 @HasPermissionAllDecorator('hg.admin')
695 701 def settings_supervisor_log(self, procid):
696 702 import rhodecode
697 703 c.rhodecode_ini = rhodecode.CONFIG
698 704 c.active = 'supervisor_tail'
699 705
700 706 supervisor = SupervisorModel()
701 707 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
702 708 groupid = c.rhodecode_ini.get('supervisor.group_id')
703 709 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
704 710
705 711 c.log_size = 10240
706 712 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
707 713 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
708 714
709 715 return render('admin/settings/settings.html')
710 716
711 717 @HasPermissionAllDecorator('hg.admin')
712 718 @auth.CSRFRequired()
713 719 def settings_labs_update(self):
714 720 """POST /admin/settings/labs: All items in the collection"""
715 721 # url('admin_settings/labs', method={'POST'})
716 722 c.active = 'labs'
717 723
718 724 application_form = LabsSettingsForm()()
719 725 try:
720 726 form_result = application_form.to_python(dict(request.POST))
721 727 except formencode.Invalid as errors:
722 728 h.flash(
723 729 _('Some form inputs contain invalid data.'),
724 730 category='error')
725 731 return htmlfill.render(
726 732 render('admin/settings/settings.html'),
727 733 defaults=errors.value,
728 734 errors=errors.error_dict or {},
729 735 prefix_error=False,
730 736 encoding='UTF-8',
731 737 force_defaults=False
732 738 )
733 739
734 740 try:
735 741 session = Session()
736 742 for setting in _LAB_SETTINGS:
737 743 setting_name = setting.key[len('rhodecode_'):]
738 744 sett = SettingsModel().create_or_update_setting(
739 745 setting_name, form_result[setting.key], setting.type)
740 746 session.add(sett)
741 747
742 748 except Exception:
743 749 log.exception('Exception while updating lab settings')
744 750 h.flash(_('Error occurred during updating labs settings'),
745 751 category='error')
746 752 else:
747 753 Session().commit()
748 754 SettingsModel().invalidate_settings_cache()
749 755 h.flash(_('Updated Labs settings'), category='success')
750 756 return redirect(url('admin_settings_labs'))
751 757
752 758 return htmlfill.render(
753 759 render('admin/settings/settings.html'),
754 760 defaults=self._form_defaults(),
755 761 encoding='UTF-8',
756 762 force_defaults=False)
757 763
758 764 @HasPermissionAllDecorator('hg.admin')
759 765 def settings_labs(self):
760 766 """GET /admin/settings/labs: All items in the collection"""
761 767 # url('admin_settings_labs')
762 768 if not c.labs_active:
763 769 redirect(url('admin_settings'))
764 770
765 771 c.active = 'labs'
766 772 c.lab_settings = _LAB_SETTINGS
767 773
768 774 return htmlfill.render(
769 775 render('admin/settings/settings.html'),
770 776 defaults=self._form_defaults(),
771 777 encoding='UTF-8',
772 778 force_defaults=False)
773 779
774 780 def _form_defaults(self):
775 781 defaults = SettingsModel().get_all_settings()
776 782 defaults.update(self._get_hg_ui_settings())
777 783 defaults.update({
778 784 'new_svn_branch': '',
779 785 'new_svn_tag': '',
780 786 })
781 787 return defaults
782 788
783 789
784 790 # :param key: name of the setting including the 'rhodecode_' prefix
785 791 # :param type: the RhodeCodeSetting type to use.
786 792 # :param group: the i18ned group in which we should dispaly this setting
787 793 # :param label: the i18ned label we should display for this setting
788 794 # :param help: the i18ned help we should dispaly for this setting
789 795 LabSetting = collections.namedtuple(
790 796 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
791 797
792 798
793 799 # This list has to be kept in sync with the form
794 800 # rhodecode.model.forms.LabsSettingsForm.
795 801 _LAB_SETTINGS = [
796 802
797 803 ]
@@ -1,270 +1,272 b''
1 1 ## snippet for displaying vcs settings
2 2 ## usage:
3 3 ## <%namespace name="vcss" file="/base/vcssettings.html"/>
4 4 ## ${vcss.vcs_settings_fields()}
5 5
6 6 <%def name="vcs_settings_fields(suffix='', svn_branch_patterns=None, svn_tag_patterns=None, repo_type=None, display_globals=False, allow_repo_location_change=False, **kwargs)">
7 7 % if display_globals:
8 8 <div class="panel panel-default">
9 9 <div class="panel-heading" id="general">
10 10 <h3 class="panel-title">${_('General')}</h3>
11 11 </div>
12 12 <div class="panel-body">
13 13 <div class="field">
14 14 <div class="checkbox">
15 15 ${h.checkbox('web_push_ssl' + suffix, 'True')}
16 16 <label for="web_push_ssl${suffix}">${_('Require SSL for vcs operations')}</label>
17 17 </div>
18 18 <div class="label">
19 19 <span class="help-block">${_('Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable.')}</span>
20 20 </div>
21 21 </div>
22 22 </div>
23 23 </div>
24 24 % endif
25 25
26 26 % if display_globals:
27 27 <div class="panel panel-default">
28 28 <div class="panel-heading">
29 29 <h3 class="panel-title">${_('Main Storage Location')}</h3>
30 30 </div>
31 31 <div class="panel-body">
32 32 <div class="field">
33 33 <div class="inputx locked_input">
34 34 %if allow_repo_location_change:
35 35 ${h.text('paths_root_path',size=59,readonly="readonly", class_="disabled")}
36 36 <span id="path_unlock" class="tooltip"
37 37 title="${h.tooltip(_('Click to unlock. You must restart RhodeCode in order to make this setting take effect.'))}">
38 38 <div class="btn btn-default lock_input_button"><i id="path_unlock_icon" class="icon-lock"></i></div>
39 39 </span>
40 40 %else:
41 41 ${_('Repository location change is disabled. You can enable this by changing the `allow_repo_location_change` inside .ini file.')}
42 42 ## form still requires this but we cannot internally change it anyway
43 43 ${h.hidden('paths_root_path',size=30,readonly="readonly", class_="disabled")}
44 44 %endif
45 45 </div>
46 46 </div>
47 47 <div class="label">
48 48 <span class="help-block">${_('Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required.')}</span>
49 49 </div>
50 50 </div>
51 51 </div>
52 52 % endif
53 53
54 54 % if display_globals or repo_type in ['git', 'hg']:
55 55 <div class="panel panel-default">
56 56 <div class="panel-heading" id="general">
57 57 <h3 class="panel-title">${_('Internal Hooks')}</h3>
58 58 </div>
59 59 <div class="panel-body">
60 60 <div class="field">
61 61 <div class="checkbox">
62 62 ${h.checkbox('hooks_changegroup_repo_size' + suffix, 'True', **kwargs)}
63 63 <label for="hooks_changegroup_repo_size${suffix}">${_('Show repository size after push')}</label>
64 64 </div>
65 65
66 66 <div class="label">
67 67 <span class="help-block">${_('Trigger a hook that calculates repository size after each push.')}</span>
68 68 </div>
69 69 <div class="checkbox">
70 70 ${h.checkbox('hooks_changegroup_push_logger' + suffix, 'True', **kwargs)}
71 71 <label for="hooks_changegroup_push_logger${suffix}">${_('Execute pre/post push hooks')}</label>
72 72 </div>
73 73 <div class="label">
74 74 <span class="help-block">${_('Execute Built in pre/post push hooks. This also executes rcextensions hooks.')}</span>
75 75 </div>
76 76 <div class="checkbox">
77 77 ${h.checkbox('hooks_outgoing_pull_logger' + suffix, 'True', **kwargs)}
78 78 <label for="hooks_outgoing_pull_logger${suffix}">${_('Execute pre/post pull hooks')}</label>
79 79 </div>
80 80 <div class="label">
81 81 <span class="help-block">${_('Execute Built in pre/post pull hooks. This also executes rcextensions hooks.')}</span>
82 82 </div>
83 83 </div>
84 84 </div>
85 85 </div>
86 86 % endif
87 87
88 88 % if display_globals or repo_type in ['hg']:
89 89 <div class="panel panel-default">
90 90 <div class="panel-heading">
91 91 <h3 class="panel-title">${_('Mercurial Settings')}</h3>
92 92 </div>
93 93 <div class="panel-body">
94 94 <div class="checkbox">
95 95 ${h.checkbox('extensions_largefiles' + suffix, 'True', **kwargs)}
96 96 <label for="extensions_largefiles${suffix}">${_('Enable largefiles extension')}</label>
97 97 </div>
98 98 <div class="label">
99 99 <span class="help-block">${_('Enable Largefiles extensions for all repositories.')}</span>
100 100 </div>
101 101 <div class="checkbox">
102 102 ${h.checkbox('phases_publish' + suffix, 'True', **kwargs)}
103 103 <label for="phases_publish${suffix}">${_('Set repositories as publishing') if display_globals else _('Set repository as publishing')}</label>
104 104 </div>
105 105 <div class="label">
106 106 <span class="help-block">${_('When this is enabled all commits in the repository are seen as public commits by clients.')}</span>
107 107 </div>
108 108 % if display_globals:
109 109 <div class="checkbox">
110 110 ${h.checkbox('extensions_hgsubversion' + suffix,'True')}
111 111 <label for="extensions_hgsubversion${suffix}">${_('Enable hgsubversion extension')}</label>
112 112 </div>
113 113 <div class="label">
114 114 <span class="help-block">${_('Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type.')}</span>
115 115 </div>
116 116 % endif
117 117 </div>
118 118 </div>
119 119 ## LABS for HG
120 120 % if c.labs_active:
121 121 <div class="panel panel-danger">
122 122 <div class="panel-heading">
123 123 <h3 class="panel-title">${_('Mercurial Labs Settings')} (${_('These features are considered experimental and may not work as expected.')})</h3>
124 124 </div>
125 125 <div class="panel-body">
126 126
127 127 <div class="checkbox">
128 128 ${h.checkbox('rhodecode_hg_use_rebase_for_merging' + suffix, 'True', **kwargs)}
129 129 <label for="rhodecode_hg_use_rebase_for_merging{suffix}">${_('Use rebase as merge strategy')}</label>
130 130 </div>
131 131 <div class="label">
132 132 <span class="help-block">${_('Use rebase instead of creating a merge commit when merging via web interface.')}</span>
133 133 </div>
134 134
135 135 </div>
136 136 </div>
137 137 % endif
138 138
139 139 % endif
140 140
141 141 % if display_globals:
142 142 <div class="panel panel-default">
143 143 <div class="panel-heading">
144 144 <h3 class="panel-title">${_('Global Subversion Settings')}</h3>
145 145 </div>
146 146 <div class="panel-body">
147 147 <div class="field">
148 148 <div class="checkbox">
149 149 ${h.checkbox('vcs_svn_proxy_http_requests_enabled' + suffix, 'True', **kwargs)}
150 150 <label for="vcs_svn_proxy_http_requests_enabled{suffix}">${_('Proxy subversion HTTP requests')}</label>
151 151 </div>
152 152 <div class="label">
153 153 <span class="help-block">${_('Subversion HTTP Support. Enables communication with SVN over HTTP protocol.')}</span>
154 154 </div>
155 155 </div>
156 156 <div class="field">
157 157 <div class="label">
158 158 <label for="vcs_svn_proxy_http_server_url">${_('Subversion HTTP Server URL')}</label><br/>
159 159 </div>
160 160 <div class="input">
161 161 ${h.text('vcs_svn_proxy_http_server_url',size=59)}
162 162 </div>
163 163 </div>
164 <div class="buttons">
165 <button class="btn btn-primary" id="vcs_svn_generate_cfg">${_('Generate Apache Config')}</button>
166 </div>
164 % if c.svn_proxy_generate_config:
165 <div class="buttons">
166 <button class="btn btn-primary" id="vcs_svn_generate_cfg">${_('Generate Apache Config')}</button>
167 </div>
168 % endif
167 169 </div>
168 170 </div>
169 171 % endif
170 172
171 173 % if display_globals or repo_type in ['svn']:
172 174 <div class="panel panel-default">
173 175 <div class="panel-heading">
174 176 <h3 class="panel-title">${_('Subversion Settings')}</h3>
175 177 </div>
176 178 <div class="panel-body">
177 179 <div class="field">
178 180 <div class="content" >
179 181 <label>${_('Repository patterns')}</label><br/>
180 182 </div>
181 183 </div>
182 184 <div class="label">
183 185 <span class="help-block">${_('Patterns for identifying SVN branches and tags. For recursive search, use "*". Eg.: "/branches/*"')}</span>
184 186 </div>
185 187
186 188 <div class="field branch_patterns">
187 189 <div class="input" >
188 190 <label>${_('Branches')}:</label><br/>
189 191 </div>
190 192 % if svn_branch_patterns:
191 193 % for branch in svn_branch_patterns:
192 194 <div class="input adjacent" id="${'id%s' % branch.ui_id}">
193 195 ${h.hidden('branch_ui_key' + suffix, branch.ui_key)}
194 196 ${h.text('branch_value_%d' % branch.ui_id + suffix, branch.ui_value, size=59, readonly="readonly", class_='disabled')}
195 197 % if kwargs.get('disabled') != 'disabled':
196 198 <span class="btn btn-x" onclick="ajaxDeletePattern(${branch.ui_id},'${'id%s' % branch.ui_id}')">
197 199 ${_('Delete')}
198 200 </span>
199 201 % endif
200 202 </div>
201 203 % endfor
202 204 %endif
203 205 </div>
204 206 % if kwargs.get('disabled') != 'disabled':
205 207 <div class="field branch_patterns">
206 208 <div class="input" >
207 209 ${h.text('new_svn_branch',size=59,placeholder='New branch pattern')}
208 210 </div>
209 211 </div>
210 212 % endif
211 213 <div class="field tag_patterns">
212 214 <div class="input" >
213 215 <label>${_('Tags')}:</label><br/>
214 216 </div>
215 217 % if svn_tag_patterns:
216 218 % for tag in svn_tag_patterns:
217 219 <div class="input" id="${'id%s' % tag.ui_id + suffix}">
218 220 ${h.hidden('tag_ui_key' + suffix, tag.ui_key)}
219 221 ${h.text('tag_ui_value_new_%d' % tag.ui_id + suffix, tag.ui_value, size=59, readonly="readonly", class_='disabled tag_input')}
220 222 % if kwargs.get('disabled') != 'disabled':
221 223 <span class="btn btn-x" onclick="ajaxDeletePattern(${tag.ui_id},'${'id%s' % tag.ui_id}')">
222 224 ${_('Delete')}
223 225 </span>
224 226 %endif
225 227 </div>
226 228 % endfor
227 229 % endif
228 230 </div>
229 231 % if kwargs.get('disabled') != 'disabled':
230 232 <div class="field tag_patterns">
231 233 <div class="input" >
232 234 ${h.text('new_svn_tag' + suffix, size=59, placeholder='New tag pattern')}
233 235 </div>
234 236 </div>
235 237 %endif
236 238 </div>
237 239 </div>
238 240 % else:
239 241 ${h.hidden('new_svn_branch' + suffix, '')}
240 242 ${h.hidden('new_svn_tag' + suffix, '')}
241 243 % endif
242 244
243 245
244 246
245 247
246 248 % if display_globals or repo_type in ['hg', 'git']:
247 249 <div class="panel panel-default">
248 250 <div class="panel-heading">
249 251 <h3 class="panel-title">${_('Pull Request Settings')}</h3>
250 252 </div>
251 253 <div class="panel-body">
252 254 <div class="checkbox">
253 255 ${h.checkbox('rhodecode_pr_merge_enabled' + suffix, 'True', **kwargs)}
254 256 <label for="rhodecode_pr_merge_enabled${suffix}">${_('Enable server-side merge for pull requests')}</label>
255 257 </div>
256 258 <div class="label">
257 259 <span class="help-block">${_('Note: when this feature is enabled, it only runs hooks defined in the rcextension package. Custom hooks added on the Admin -> Settings -> Hooks page will not be run when pull requests are automatically merged from the web interface.')}</span>
258 260 </div>
259 261 <div class="checkbox">
260 262 ${h.checkbox('rhodecode_use_outdated_comments' + suffix, 'True', **kwargs)}
261 263 <label for="rhodecode_use_outdated_comments${suffix}">${_('Invalidate and relocate inline comments during update')}</label>
262 264 </div>
263 265 <div class="label">
264 266 <span class="help-block">${_('During the update of a pull request, the position of inline comments will be updated and outdated inline comments will be hidden.')}</span>
265 267 </div>
266 268 </div>
267 269 </div>
268 270 % endif
269 271
270 272 </%def>
General Comments 0
You need to be logged in to leave comments. Login now