settings.py
579 lines
| 22.9 KiB
| text/x-python
|
PythonLexer
r779 | # -*- coding: utf-8 -*- | |||
r1206 | # This program is free software: you can redistribute it and/or modify | |||
# it under the terms of the GNU General Public License as published by | ||||
# the Free Software Foundation, either version 3 of the License, or | ||||
# (at your option) any later version. | ||||
r1203 | # | |||
r547 | # This program is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
r1203 | # | |||
r547 | # You should have received a copy of the GNU General Public License | |||
r1206 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
r4116 | """ | ||
rhodecode.controllers.admin.settings | ||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
r779 | ||||
|
r4116 | settings controller for rhodecode admin | ||
:created_on: Jul 14, 2010 | ||||
:author: marcink | ||||
:copyright: (c) 2013 RhodeCode GmbH. | ||||
:license: GPLv3, see LICENSE for more details. | ||||
""" | ||||
import time | ||||
r890 | import logging | |||
import traceback | ||||
import formencode | ||||
r547 | from formencode import htmlfill | |||
|
r4116 | from pylons import request, tmpl_context as c, url, config | ||
from pylons.controllers.util import redirect | ||||
r547 | from pylons.i18n.translation import _ | |||
r890 | ||||
r547 | from rhodecode.lib import helpers as h | |||
|
r4116 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator | ||
r547 | from rhodecode.lib.base import BaseController, render | |||
r705 | from rhodecode.lib.celerylib import tasks, run_task | |||
r4090 | from rhodecode.lib.exceptions import HgsubversionImportError | |||
|
r4116 | from rhodecode.lib.utils import repo2db_mapper, set_rhodecode_config | ||
from rhodecode.model.db import RhodeCodeUi, Repository, RhodeCodeSetting | ||||
from rhodecode.model.forms import ApplicationSettingsForm, \ | ||||
r2674 | ApplicationUiSettingsForm, ApplicationVisualisationForm | |||
|
r4116 | from rhodecode.model.license import LicenseModel | ||
from rhodecode.model.scm import ScmModel | ||||
r1718 | from rhodecode.model.notification import EmailNotificationModel | |||
r1749 | from rhodecode.model.meta import Session | |||
|
r4116 | from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str | ||
r3154 | from rhodecode.lib.compat import json | |||
r547 | log = logging.getLogger(__name__) | |||
class SettingsController(BaseController): | ||||
"""REST Controller styled on the Atom Publishing Protocol""" | ||||
# To properly map this controller, ensure your config/routing.py | ||||
# file has a resource setup: | ||||
r1203 | # map.resource('setting', 'settings', controller='admin/settings', | |||
r547 | # path_prefix='/admin', name_prefix='admin_') | |||
@LoginRequired() | ||||
def __before__(self): | ||||
r3712 | super(SettingsController, self).__before__() | |||
r629 | ||||
|
r4116 | def _get_hg_ui_settings(self): | ||
ret = RhodeCodeUi.query().all() | ||||
r2192 | ||||
|
r4116 | if not ret: | ||
raise Exception('Could not get application ui settings !') | ||||
settings = {} | ||||
for each in ret: | ||||
k = each.ui_key | ||||
v = each.ui_value | ||||
if k == '/': | ||||
k = 'root_path' | ||||
r629 | ||||
|
r4116 | if k == 'push_ssl': | ||
v = str2bool(v) | ||||
if k.find('.') != -1: | ||||
k = k.replace('.', '_') | ||||
r629 | ||||
|
r4116 | if each.ui_section in ['hooks', 'extensions']: | ||
v = each.ui_active | ||||
settings[each.ui_section + '_' + k] = v | ||||
return settings | ||||
r629 | ||||
r547 | @HasPermissionAllDecorator('hg.admin') | |||
|
r4116 | def settings_vcs(self): | ||
"""GET /admin/settings: All items in the collection""" | ||||
# url('admin_settings') | ||||
c.active = 'vcs' | ||||
if request.POST: | ||||
r2662 | application_form = ApplicationUiSettingsForm()() | |||
try: | ||||
form_result = application_form.to_python(dict(request.POST)) | ||||
r564 | except formencode.Invalid, errors: | |||
r547 | return htmlfill.render( | |||
render('admin/settings/settings.html'), | ||||
defaults=errors.value, | ||||
errors=errors.error_dict or {}, | ||||
prefix_error=False, | ||||
r2662 | encoding="UTF-8" | |||
) | ||||
r629 | ||||
r547 | try: | |||
r2708 | sett = RhodeCodeUi.get_by_key('push_ssl') | |||
sett.ui_value = form_result['web_push_ssl'] | ||||
Session().add(sett) | ||||
r3920 | if c.visual.allow_repo_location_change: | |||
sett = RhodeCodeUi.get_by_key('/') | ||||
sett.ui_value = form_result['paths_root_path'] | ||||
Session().add(sett) | ||||
r629 | ||||
r2662 | #HOOKS | |||
r2708 | sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE) | |||
|
r3570 | sett.ui_active = form_result['hooks_changegroup_update'] | ||
r2708 | Session().add(sett) | |||
r629 | ||||
r2708 | sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_REPO_SIZE) | |||
|
r3570 | sett.ui_active = form_result['hooks_changegroup_repo_size'] | ||
r2708 | Session().add(sett) | |||
sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PUSH) | ||||
|
r3570 | sett.ui_active = form_result['hooks_changegroup_push_logger'] | ||
r2708 | Session().add(sett) | |||
r629 | ||||
r2708 | sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PULL) | |||
|
r3570 | sett.ui_active = form_result['hooks_outgoing_pull_logger'] | ||
r2708 | ||||
Session().add(sett) | ||||
r629 | ||||
r2708 | ## EXTENSIONS | |||
sett = RhodeCodeUi.get_by_key('largefiles') | ||||
r2844 | if not sett: | |||
#make one if it's not there ! | ||||
sett = RhodeCodeUi() | ||||
sett.ui_key = 'largefiles' | ||||
sett.ui_section = 'extensions' | ||||
|
r3570 | sett.ui_active = form_result['extensions_largefiles'] | ||
r2708 | Session().add(sett) | |||
r629 | ||||
r2708 | sett = RhodeCodeUi.get_by_key('hgsubversion') | |||
r2844 | if not sett: | |||
#make one if it's not there ! | ||||
sett = RhodeCodeUi() | ||||
sett.ui_key = 'hgsubversion' | ||||
sett.ui_section = 'extensions' | ||||
|
r3570 | sett.ui_active = form_result['extensions_hgsubversion'] | ||
r4090 | if sett.ui_active: | |||
try: | ||||
|
r4116 | import hgsubversion # pragma: no cover | ||
r4090 | except ImportError: | |||
raise HgsubversionImportError | ||||
r2708 | Session().add(sett) | |||
# sett = RhodeCodeUi.get_by_key('hggit') | ||||
r2844 | # if not sett: | |||
# #make one if it's not there ! | ||||
# sett = RhodeCodeUi() | ||||
# sett.ui_key = 'hggit' | ||||
# sett.ui_section = 'extensions' | ||||
# | ||||
|
r3570 | # sett.ui_active = form_result['extensions_hggit'] | ||
r2708 | # Session().add(sett) | |||
r2662 | Session().commit() | |||
r629 | ||||
r2708 | h.flash(_('Updated VCS settings'), category='success') | |||
r629 | ||||
r4090 | except HgsubversionImportError: | |||
log.error(traceback.format_exc()) | ||||
h.flash(_('Unable to activate hgsubversion support. ' | ||||
'The "hgsubversion" library is missing'), | ||||
category='error') | ||||
r2662 | except Exception: | |||
log.error(traceback.format_exc()) | ||||
|
r3565 | h.flash(_('Error occurred during updating ' | ||
r2662 | 'application settings'), category='error') | |||
r629 | ||||
|
r4116 | defaults = RhodeCodeSetting.get_app_settings() | ||
defaults.update(self._get_hg_ui_settings()) | ||||
return htmlfill.render( | ||||
render('admin/settings/settings.html'), | ||||
defaults=defaults, | ||||
encoding="UTF-8", | ||||
force_defaults=False) | ||||
@HasPermissionAllDecorator('hg.admin') | ||||
def settings_mapping(self): | ||||
"""GET /admin/settings/mapping: All items in the collection""" | ||||
# url('admin_settings_mapping') | ||||
c.active = 'mapping' | ||||
if request.POST: | ||||
rm_obsolete = request.POST.get('destroy', False) | ||||
install_git_hooks = request.POST.get('hooks', False) | ||||
invalidate_cache = request.POST.get('invalidate', False) | ||||
log.debug('rescanning repo location with destroy obsolete=%s and ' | ||||
'install git hooks=%s' % (rm_obsolete,install_git_hooks)) | ||||
if invalidate_cache: | ||||
log.debug('invalidating all repositories cache') | ||||
for repo in Repository.get_all(): | ||||
ScmModel().mark_for_invalidation(repo.repo_name, delete=True) | ||||
filesystem_repos = ScmModel().repo_scan() | ||||
added, removed = repo2db_mapper(filesystem_repos, rm_obsolete, | ||||
install_git_hook=install_git_hooks) | ||||
_repr = lambda l: ', '.join(map(safe_unicode, l)) or '-' | ||||
h.flash(_('Repositories successfully ' | ||||
'rescanned added: %s ; removed: %s') % | ||||
(_repr(added), _repr(removed)), | ||||
category='success') | ||||
return redirect(url('admin_settings_mapping')) | ||||
defaults = RhodeCodeSetting.get_app_settings() | ||||
defaults.update(self._get_hg_ui_settings()) | ||||
return htmlfill.render( | ||||
render('admin/settings/settings.html'), | ||||
defaults=defaults, | ||||
encoding="UTF-8", | ||||
force_defaults=False) | ||||
@HasPermissionAllDecorator('hg.admin') | ||||
def settings_global(self): | ||||
"""GET /admin/settings/global: All items in the collection""" | ||||
# url('admin_settings_global') | ||||
c.active = 'global' | ||||
if request.POST: | ||||
application_form = ApplicationSettingsForm()() | ||||
try: | ||||
form_result = application_form.to_python(dict(request.POST)) | ||||
except formencode.Invalid, errors: | ||||
return htmlfill.render( | ||||
render('admin/settings/settings.html'), | ||||
defaults=errors.value, | ||||
errors=errors.error_dict or {}, | ||||
prefix_error=False, | ||||
encoding="UTF-8") | ||||
try: | ||||
sett1 = RhodeCodeSetting.create_or_update('title', | ||||
form_result['rhodecode_title']) | ||||
Session().add(sett1) | ||||
sett2 = RhodeCodeSetting.create_or_update('realm', | ||||
form_result['rhodecode_realm']) | ||||
Session().add(sett2) | ||||
sett3 = RhodeCodeSetting.create_or_update('ga_code', | ||||
form_result['rhodecode_ga_code']) | ||||
Session().add(sett3) | ||||
sett4 = RhodeCodeSetting.create_or_update('captcha_public_key', | ||||
form_result['rhodecode_captcha_public_key']) | ||||
Session().add(sett4) | ||||
sett5 = RhodeCodeSetting.create_or_update('captcha_private_key', | ||||
form_result['rhodecode_captcha_private_key']) | ||||
Session().add(sett5) | ||||
Session().commit() | ||||
set_rhodecode_config(config) | ||||
h.flash(_('Updated application settings'), category='success') | ||||
except Exception: | ||||
log.error(traceback.format_exc()) | ||||
h.flash(_('Error occurred during updating ' | ||||
'application settings'), | ||||
category='error') | ||||
return redirect(url('admin_settings_global')) | ||||
defaults = RhodeCodeSetting.get_app_settings() | ||||
defaults.update(self._get_hg_ui_settings()) | ||||
return htmlfill.render( | ||||
render('admin/settings/settings.html'), | ||||
defaults=defaults, | ||||
encoding="UTF-8", | ||||
force_defaults=False) | ||||
@HasPermissionAllDecorator('hg.admin') | ||||
def settings_visual(self): | ||||
"""GET /admin/settings/visual: All items in the collection""" | ||||
# url('admin_settings_visual') | ||||
c.active = 'visual' | ||||
if request.POST: | ||||
application_form = ApplicationVisualisationForm()() | ||||
try: | ||||
form_result = application_form.to_python(dict(request.POST)) | ||||
except formencode.Invalid, errors: | ||||
return htmlfill.render( | ||||
render('admin/settings/settings.html'), | ||||
defaults=errors.value, | ||||
errors=errors.error_dict or {}, | ||||
prefix_error=False, | ||||
encoding="UTF-8" | ||||
) | ||||
try: | ||||
settings = [ | ||||
('show_public_icon', 'rhodecode_show_public_icon', 'bool'), | ||||
('show_private_icon', 'rhodecode_show_private_icon', 'bool'), | ||||
('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'), | ||||
('repository_fields', 'rhodecode_repository_fields', 'bool'), | ||||
('dashboard_items', 'rhodecode_dashboard_items', 'int'), | ||||
('admin_grid_items', 'rhodecode_admin_grid_items', 'int'), | ||||
('show_version', 'rhodecode_show_version', 'bool'), | ||||
('use_gravatar', 'rhodecode_use_gravatar', 'bool'), | ||||
('gravatar_url', 'rhodecode_gravatar_url', 'unicode'), | ||||
('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'), | ||||
] | ||||
for setting, form_key, type_ in settings: | ||||
sett = RhodeCodeSetting.create_or_update(setting, | ||||
form_result[form_key], type_) | ||||
Session().add(sett) | ||||
Session().commit() | ||||
set_rhodecode_config(config) | ||||
h.flash(_('Updated visualisation settings'), | ||||
category='success') | ||||
except Exception: | ||||
log.error(traceback.format_exc()) | ||||
h.flash(_('Error occurred during updating ' | ||||
'visualisation settings'), | ||||
category='error') | ||||
return redirect(url('admin_settings_visual')) | ||||
defaults = RhodeCodeSetting.get_app_settings() | ||||
defaults.update(self._get_hg_ui_settings()) | ||||
return htmlfill.render( | ||||
render('admin/settings/settings.html'), | ||||
defaults=defaults, | ||||
encoding="UTF-8", | ||||
force_defaults=False) | ||||
@HasPermissionAllDecorator('hg.admin') | ||||
def settings_email(self): | ||||
"""GET /admin/settings/email: All items in the collection""" | ||||
# url('admin_settings_email') | ||||
c.active = 'email' | ||||
if request.POST: | ||||
test_email = request.POST.get('test_email') | ||||
test_email_subj = 'RhodeCode test email' | ||||
test_email_body = ('RhodeCode Email test, ' | ||||
'RhodeCode version: %s' % c.rhodecode_version) | ||||
if not test_email: | ||||
h.flash(_('Please enter email address'), category='error') | ||||
return redirect(url('admin_settings_email')) | ||||
test_email_html_body = EmailNotificationModel()\ | ||||
.get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT, | ||||
body=test_email_body) | ||||
recipients = [test_email] if test_email else None | ||||
run_task(tasks.send_email, recipients, test_email_subj, | ||||
test_email_body, test_email_html_body) | ||||
h.flash(_('Send email task created'), category='success') | ||||
return redirect(url('admin_settings_email')) | ||||
defaults = RhodeCodeSetting.get_app_settings() | ||||
defaults.update(self._get_hg_ui_settings()) | ||||
import rhodecode | ||||
c.rhodecode_ini = rhodecode.CONFIG | ||||
return htmlfill.render( | ||||
render('admin/settings/settings.html'), | ||||
defaults=defaults, | ||||
encoding="UTF-8", | ||||
force_defaults=False) | ||||
@HasPermissionAllDecorator('hg.admin') | ||||
def settings_hooks(self): | ||||
"""GET /admin/settings/hooks: All items in the collection""" | ||||
# url('admin_settings_hooks') | ||||
c.active = 'hooks' | ||||
if request.POST: | ||||
r4045 | if c.visual.allow_custom_hooks_settings: | |||
ui_key = request.POST.get('new_hook_ui_key') | ||||
ui_value = request.POST.get('new_hook_ui_value') | ||||
|
r4116 | |||
hook_id = request.POST.get('hook_id') | ||||
r4045 | try: | |||
if ui_value and ui_key: | ||||
RhodeCodeUi.create_or_update_hook(ui_key, ui_value) | ||||
|
r4116 | h.flash(_('Added new hook'), category='success') | ||
elif hook_id: | ||||
RhodeCodeUi.delete(hook_id) | ||||
Session().commit() | ||||
r1460 | ||||
r4045 | # check for edits | |||
update = False | ||||
_d = request.POST.dict_of_lists() | ||||
for k, v in zip(_d.get('hook_ui_key', []), | ||||
_d.get('hook_ui_value_new', [])): | ||||
RhodeCodeUi.create_or_update_hook(k, v) | ||||
update = True | ||||
r1460 | ||||
r4045 | if update: | |||
h.flash(_('Updated hooks'), category='success') | ||||
Session().commit() | ||||
except Exception: | ||||
log.error(traceback.format_exc()) | ||||
h.flash(_('Error occurred during hook creation'), | ||||
category='error') | ||||
r1460 | ||||
|
r4116 | return redirect(url('admin_settings_hooks')) | ||
r629 | ||||
|
r4116 | defaults = RhodeCodeSetting.get_app_settings() | ||
defaults.update(self._get_hg_ui_settings()) | ||||
r547 | ||||
r1460 | c.hooks = RhodeCodeUi.get_builtin_hooks() | |||
c.custom_hooks = RhodeCodeUi.get_custom_hooks() | ||||
return htmlfill.render( | ||||
|
r4116 | render('admin/settings/settings.html'), | ||
defaults=defaults, | ||||
r1460 | encoding="UTF-8", | |||
|
r4116 | force_defaults=False) | ||
r1460 | ||||
|
r4116 | @HasPermissionAllDecorator('hg.admin') | ||
def settings_search(self): | ||||
"""GET /admin/settings/search: All items in the collection""" | ||||
# url('admin_settings_search') | ||||
c.active = 'search' | ||||
if request.POST: | ||||
repo_location = self._get_hg_ui_settings()['paths_root_path'] | ||||
full_index = request.POST.get('full_index', False) | ||||
run_task(tasks.whoosh_index, repo_location, full_index) | ||||
h.flash(_('Whoosh reindex task scheduled'), category='success') | ||||
return redirect(url('admin_settings_search')) | ||||
r3159 | ||||
|
r4116 | defaults = RhodeCodeSetting.get_app_settings() | ||
defaults.update(self._get_hg_ui_settings()) | ||||
r3159 | ||||
|
r4116 | return htmlfill.render( | ||
render('admin/settings/settings.html'), | ||||
defaults=defaults, | ||||
encoding="UTF-8", | ||||
force_defaults=False) | ||||
r665 | ||||
|
r4116 | @HasPermissionAllDecorator('hg.admin') | ||
def settings_system(self): | ||||
"""GET /admin/settings/system: All items in the collection""" | ||||
# url('admin_settings_system') | ||||
c.active = 'system' | ||||
r629 | ||||
|
r4116 | defaults = RhodeCodeSetting.get_app_settings() | ||
defaults.update(self._get_hg_ui_settings()) | ||||
r629 | ||||
|
r4116 | import rhodecode | ||
c.rhodecode_ini = rhodecode.CONFIG | ||||
c.rhodecode_update_url = defaults.get('rhodecode_update_url') | ||||
server_info = RhodeCodeSetting.get_server_info() | ||||
for key, val in server_info.iteritems(): | ||||
setattr(c, key, val) | ||||
r3154 | ||||
|
r4116 | return htmlfill.render( | ||
render('admin/settings/settings.html'), | ||||
r547 | defaults=defaults, | |||
encoding="UTF-8", | ||||
|
r4116 | force_defaults=False) | ||
r547 | ||||
|
r4116 | @HasPermissionAllDecorator('hg.admin') | ||
def settings_system_update(self): | ||||
"""GET /admin/settings/system/updates: All items in the collection""" | ||||
# url('admin_settings_system_update') | ||||
import json | ||||
import urllib2 | ||||
from rhodecode.lib.verlib import NormalizedVersion | ||||
from rhodecode import __version__ | ||||
defaults = RhodeCodeSetting.get_app_settings() | ||||
defaults.update(self._get_hg_ui_settings()) | ||||
_update_url = defaults.get('rhodecode_update_url', '') | ||||
_err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s) | ||||
r547 | try: | |||
|
r4116 | import rhodecode | ||
ver = rhodecode.__version__ | ||||
log.debug('Checking for upgrade on `%s` server' % _update_url) | ||||
opener = urllib2.build_opener() | ||||
opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)] | ||||
response = opener.open(_update_url) | ||||
response_data = response.read() | ||||
data = json.loads(response_data) | ||||
except urllib2.URLError, e: | ||||
log.error(traceback.format_exc()) | ||||
return _err('Failed to contact upgrade server: %r' % e) | ||||
except ValueError, e: | ||||
r547 | log.error(traceback.format_exc()) | |||
|
r4116 | return _err('Bad data sent from update server') | ||
latest = data['versions'][0] | ||||
c.update_url = _update_url | ||||
c.latest_data = latest | ||||
c.latest_ver = latest['version'] | ||||
c.cur_ver = __version__ | ||||
c.should_upgrade = False | ||||
if NormalizedVersion(c.latest_ver) > NormalizedVersion(c.cur_ver): | ||||
c.should_upgrade = True | ||||
c.important_notices = latest['general'] | ||||
return render('admin/settings/settings_system_update.html'), | ||||
r629 | ||||
|
r4116 | @HasPermissionAllDecorator('hg.admin') | ||
def settings_license(self): | ||||
"""GET /admin/settings/hooks: All items in the collection""" | ||||
# url('admin_settings_license') | ||||
c.active = 'license' | ||||
if request.POST: | ||||
form_result = request.POST | ||||
try: | ||||
sett1 = RhodeCodeSetting.create_or_update('license_key', | ||||
form_result['rhodecode_license_key'], | ||||
'unicode') | ||||
Session().add(sett1) | ||||
Session().commit() | ||||
set_rhodecode_config(config) | ||||
h.flash(_('Updated license information'), | ||||
category='success') | ||||
r3404 | ||||
|
r4116 | except Exception: | ||
log.error(traceback.format_exc()) | ||||
h.flash(_('Error occurred during updating license info'), | ||||
category='error') | ||||
r3389 | ||||
|
r4116 | return redirect(url('admin_settings_license')) | ||
r3389 | ||||
|
r4116 | defaults = RhodeCodeSetting.get_app_settings() | ||
defaults.update(self._get_hg_ui_settings()) | ||||
r2625 | ||||
|
r4116 | import rhodecode | ||
c.rhodecode_ini = rhodecode.CONFIG | ||||
c.license_token = c.rhodecode_ini.get('license_token') | ||||
c.generated_license_token = LicenseModel.generate_license_token() | ||||
c.license_info = {} | ||||
c.license_loaded = False | ||||
# try to read info about license | ||||
try: | ||||
license_key = defaults.get('rhodecode_license_key') | ||||
if c.license_token and license_key: | ||||
c.license_info = json.loads( | ||||
LicenseModel(key=c.license_token).decrypt(license_key)) | ||||
expires = h.fmt_date(h.time_to_datetime(c.license_info['valid_till'])) | ||||
now = time.time() | ||||
if 0 < (c.license_info['valid_till'] - now) < 60*60*24*7: | ||||
h.flash(_('Your license will expire on %s, please contact ' | ||||
'support to extend your license.' % expires), category='warning') | ||||
if c.license_info['valid_till'] - now < 0: | ||||
h.flash(_('Your license has expired on %s, please contact ' | ||||
'support to extend your license.' % expires), category='error') | ||||
c.license_loaded = True | ||||
except Exception, e: | ||||
log.error(traceback.format_exc()) | ||||
h.flash(_('Unexpected error while reading license key. Please ' | ||||
'make sure your license token and key are correct'), | ||||
category='error') | ||||
r756 | ||||
|
r4116 | return htmlfill.render( | ||
render('admin/settings/settings.html'), | ||||
defaults=defaults, | ||||
encoding="UTF-8", | ||||
force_defaults=False) | ||||