wcs/wcs/admin/settings.ptl

898 lines
35 KiB
Plaintext

# w.c.s. - web application for online forms
# Copyright (C) 2005-2010 Entr'ouvert
#
# 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 2 of the License, or
# (at your option) any later version.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import cStringIO
import cPickle
import random
import re
import os
try:
import lasso
except ImportError:
lasso = None
import zipfile
import base64
try:
import elementtree.ElementTree as ET
except ImportError:
try:
import xml.etree.ElementTree as ET
except ImportError:
ET = None
from quixote import get_publisher, get_request, get_response, redirect
from quixote.directory import Directory, AccessControlled
from qommon import misc, get_cfg
from qommon import errors
from qommon.form import *
from qommon.sms import SMS
from qommon.admin.menu import html_top, command_icon, error_page
from qommon.admin.certificates import CertificatesDirectory, m2crypto
from qommon.admin.cfg import cfg_submit
from qommon.admin.emails import EmailsDirectory
from qommon.admin.texts import TextsDirectory
from qommon.admin.settings import SettingsDirectory as QommonSettingsDirectory
import qommon.ident
import qommon.template
from formdef import FormDef
from fields import FieldWidget, FieldDefPage, FieldsDirectory
class UserFormDirectory(Directory):
_q_exports = ['']
class IdentificationDirectory(Directory):
_q_exports = ['']
def _q_index [html] (self):
get_response().breadcrumb.append( ('identification/', _('Identification')) )
identification_cfg = get_cfg('identification', {})
form = Form(enctype='multipart/form-data')
methods = [ ('password', _('Simple local username / password')), ]
if lasso is not None:
methods.insert(0,
('idp', _('Delegated to Liberty/SAML2 identity provider')))
form.add(CheckboxesWidget, 'methods', title = _('Methods'),
value = identification_cfg.get('methods'),
elements = methods,
inline = False,
required = True)
form.add(CheckboxWidget, 'use_user_hash', title=_('One-way association between user and forms'),
value=bool(identification_cfg.get('use_user_hash', False)),
required=False)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('..')
if form.is_submitted() and not form.has_errors():
cfg_submit(form, 'identification', ['methods', 'use_user_hash'])
if not identification_cfg.get('user_hash_secret_key') and form.get_widget('use_user_hash').parse():
identification_cfg = get_cfg('identification', {})
identification_cfg[str('user_hash_secret_key')] = \
str(random.SystemRandom().getrandbits(64))
get_publisher().cfg[str('identification')] = identification_cfg
get_publisher().write_cfg()
if not form.has_errors():
return redirect('..')
html_top('settings', title = _('Identification'))
'<h2>%s</h2>' % _('Identification')
if lasso is None:
cls = 'infonotice'
if identification_cfg.get('methods') and 'idp' in identification_cfg.get('methods'):
cls = 'errornotice'
'<p class="%s">%s</p>' % (cls, _('Delegated to Liberty/SAML2 identity provider \
authentication is unavailable. Lasso must be installed to use it.'))
form.render()
def _q_lookup(self, component):
get_response().breadcrumb.append( ('identification/', _('Identification')) )
return qommon.ident.get_method_admin_directory(component)
class UserFieldDefPage(FieldDefPage):
section = 'settings'
wsf_support = False
class UserFieldsDirectory(FieldsDirectory):
_q_exports = ['', 'update_order', 'new', 'mapping']
section = 'settings'
field_def_page_class = UserFieldDefPage
support_import = False
blacklisted_types = ['page']
def index_bottom [html] (self):
'<h2>%s</h2>' % _('Fields Mapping')
form = self.mapping_form()
form.render()
def mapping_form(self):
users_cfg = get_cfg('users', {})
options = [(None, _('None'), '')] + [
(x.id, x.label, x.id) for x in self.objectdef.fields]
form = Form(action = 'mapping', enctype='multipart/form-data')
field_name_value = users_cfg.get('field_name')
if type(field_name_value) is str:
field_name_value = [field_name_value]
form.add(WidgetList, 'field_name', title = _('Field(s) for Name'),
element_type = SingleSelectWidget, value = field_name_value,
element_kwargs = {
'render_br': False,
'options': options})
form.add(SingleSelectWidget, 'field_email', title = _('Field for Email'),
value = users_cfg.get('field_email'),
options = options)
form.add_submit('submit', _('Submit'))
return form
def mapping(self):
form = self.mapping_form()
cfg_submit(form, 'users', ['field_name', 'field_email'])
return redirect('.')
class UserFieldsFormDef(FormDef):
'''Class to handle custom user fields, it loads and saves from/to
an XML string stored in the configuration (at users/formdef)'''
def __init__(self):
self.name = _('Custom User Fields')
users_cfg = get_cfg('users', {})
xml_import = users_cfg.get('formdef')
self.fields = [] # make sure fields is a list
if xml_import:
try:
tree = ET.fromstring(xml_import)
except:
pass
else:
obj = FormDef.import_from_xml_tree(tree, include_id=True)
self.fields = obj.fields
else:
# compatibility with older location
filename = os.path.join(get_publisher().app_dir, 'config', 'user')
if os.path.exists(filename):
try:
formdef = FormDef.get_filename(filename)
except KeyError:
pass
else:
self.fields = formdef.fields
# and remove old file, to keep clean
self.store()
os.unlink(filename)
def store(self):
xml_export = self.export_to_xml(include_id=True)
users_cfg = get_cfg('users', {})
users_cfg['formdef'] = ET.tostring(xml_export)
get_publisher().cfg['users'] = users_cfg
get_publisher().write_cfg()
class UsersDirectory(Directory):
_q_exports = ['', 'fields']
def _q_index(self):
return redirect('fields/')
def _q_traverse(self, path):
get_response().breadcrumb.append(('users/', _('Users')))
filename = os.path.join(get_publisher().app_dir, 'config', 'user')
self.fields = UserFieldsDirectory(UserFieldsFormDef())
return Directory._q_traverse(self, path)
class SettingsDirectory(QommonSettingsDirectory):
_q_exports = ['', 'themes', 'users',
'template', 'misc', 'emails', 'debug_options', 'language',
('import', 'p_import'), 'export', 'identification', 'sitename',
'sms', 'certificates', 'texts', 'utf8switch', 'upload_theme',
'session', 'download_theme', 'smstest', 'postgresql']
certificates = CertificatesDirectory()
emails = EmailsDirectory()
identification = IdentificationDirectory()
users = UsersDirectory()
texts = TextsDirectory()
def _q_index [html] (self):
html_top('settings', title = _('Settings'))
'<div class="splitcontent-left">'
if get_publisher().has_site_option('postgresql'):
'<div class="bo-block">'
'<h2>%s</h2>' % _('Storage')
'<dl> <dt><a href="postgresql">%s</a></dt> <dd>%s</dd> </dl>' % (
_('PostgreSQL Settings'),
_('Configure access to PostgreSQL database'))
'</div>'
'<div class="bo-block">'
'<h2>%s</h2>' % _('Security')
'<dl> <dt><a href="identification/">%s</a></dt> <dd>%s</dd>' % (
_('Identification'), _('Configure identification parameters'))
identification_cfg = get_cfg('identification', {})
for method in identification_cfg.get('methods', []):
try:
method_admin = qommon.ident.get_method_admin_directory(method)
except AttributeError:
continue
'<dl> <dt><a href="identification/%s/">%s</a></dt> <dd>%s</dd>' % (
method, _(method_admin.title), _(method_admin.label))
'<dl> <dt><a href="session">%s</a></dt> <dd>%s</dd>' % (
_('Session'), _('Configure session management'))
if m2crypto:
'<dl> <dt><a href="certificates/">%s</a></dt> <dd>%s</dd>' % (
_('Certificates'), _('Configure certificate authorities'))
'</div>'
'<div class="bo-block">'
'<h2>%s</h2>' % _('Import / Export')
'<dl>'
'<dt><a href="import">%s</a></dt> <dd>%s</dd>' % (
_('Import'), _('Import data from another site'))
'<dt><a href="export">%s</a></dt> <dd>%s</dd>' % (
_('Export'), _('Export data for another site'))
'</dl>'
'</div>'
'<div class="bo-block">'
'<h2>%s</h2>' % _('Misc')
'<dl>'
'<dt><a href="misc">%s</a></dt> <dd>%s</dd>' % (
_('Misc'), _('Configure misc options'))
'<dt><a href="debug_options">%s</a></dt> <dd>%s</dd>' % (
_('Debug Options'), _('Configure options useful for debugging'))
'</dl>'
'</div>'
'</div>'
'<div class="splitcontent-right">'
'<div class="bo-block">'
'<h2>%s</h2>' % _('Customisation')
if not get_cfg('misc', {}).get('charset'):
'<div class="infonotice">'
'<p>'
_('This site is still using ISO-8859-15 as its character set; '\
'it is advised to update to UTF-8.')
' '
'<a href="utf8switch">%s</a>' % _('Switch to UTF-8 encoding')
'</p>'
'</div>'
'<dl>'
'<dt><a href="sitename">%s</a></dt> <dd>%s</dd>' % (
_('Site Name and Addresses'), _('Configure site name and addresses'))
'<dt><a href="language">%s</a></dt> <dd>%s</dd>' % (
_('Language'), _('Configure site language'))
'<dt><a href="themes">%s</a></dt> <dd>%s</dd>' % (
_('Theme'), _('Configure theme'))
'<dt><a href="template">%s</a></dt> <dd>%s</dd>' % (
_('Template'), _('Configure template'))
'<dt><a href="users/">%s</a></dt> <dd>%s</dd>' % (
_('Users'), _('Configure users'))
'<dt><a href="emails/">%s</a></dt> <dd>%s</dd>' % (
_('Emails'), _('Configure email settings'))
if get_publisher().use_sms_feature:
'<dt><a href="sms">%s</a></dt> <dd>%s</dd>' % (
_('SMS'), _('Configure SMS settings'))
if self.texts.texts_dict:
'<dt><a href="texts/">%s</a></dt> <dd>%s</dd>' % (
_('Texts'), _('Configure text that appears on some pages'))
'</dl>'
'</div>'
'</div>'
def themes [html] (self):
request = get_request()
if not request.form.has_key('theme'):
current_theme = get_cfg('branding', {}).get('theme', 'default')
get_response().breadcrumb.append(('themes', _('Themes')))
html_top('settings', title = _('Themes'))
"<h2>%s</h2>" % _('Themes')
get_session().display_message()
'<a rel="popup" href="upload_theme">%s</a>' % _('Upload New Theme')
'<form action="themes" enctype="multipart/form-data" method="post">'
themes = qommon.template.get_themes()
'<ul class="biglist themes">'
for theme, (label, desc, author, icon) in sorted(themes.items()):
if current_theme == theme:
checked = ' checked="checked"'
else:
checked = ''
'<li>'
'<strong class="label">'
' <input name="theme" value="%s" type="radio"%s>%s</input></strong>' % (
theme, checked, label)
if icon:
'<img src="/themes/%s/icon.png" alt="" class="theme-icon" />' % theme
'<p class="details">%s' % desc
' [<a href="download_theme?theme=%s">%s</a>]' % (theme, _('download'))
if author:
'<br/>by %s' % author
'</p>'
'</li>'
'</ul>'
'<div class="buttons">'
'<input type="submit" name="submit" value="%s" />' % _('Submit')
'</div>'
'</form>'
else:
themes = qommon.template.get_themes()
if themes.has_key(str(request.form['theme'])):
branding_cfg = get_cfg('branding', {})
branding_cfg[str('theme')] = str(request.form['theme'])
get_publisher().cfg[str('branding')] = branding_cfg
get_publisher().write_cfg()
return redirect('.')
def download_theme(self):
theme_id = get_request().form.get('theme')
if not theme_id:
return redirect('themes')
theme_directory = qommon.template.get_theme_directory(theme_id)
if not theme_directory:
return redirect('themes')
parent_theme_directory = os.path.dirname(theme_directory)
c = cStringIO.StringIO()
z = zipfile.ZipFile(c, 'w')
for base, dirnames, filenames in os.walk(theme_directory):
basetheme = base[len(parent_theme_directory)+1:]
for filename in filenames:
z.write(os.path.join(base, filename), os.path.join(basetheme, filename))
z.close()
response = get_response()
response.set_content_type('application/zip')
response.set_header('content-disposition', 'attachment; filename=%s.zip' % theme_id)
return c.getvalue()
def upload_theme [html] (self):
form = Form(enctype='multipart/form-data')
form.add(FileWidget, 'file', title = _('Theme'), required = True)
form.add_submit('submit', _('Upload'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
try:
return self.upload_theme_submit(form)
except ValueError:
form.get_widget('file').set_error(_('Invalid Theme'))
get_response().breadcrumb.append( ('upload_theme', _('Upload Theme')) )
html_top('forms', title = _('Upload Theme'))
'<h2>%s</h2>' % _('Upload Theme')
form.render()
def upload_theme_submit(self, form):
try:
z = zipfile.ZipFile(form.get_widget('file').parse().fp, 'r')
except:
get_session().message = ('error', _('Failed to read theme file.'))
return redirect('themes')
theme_dir = os.path.join(get_publisher().app_dir, 'themes')
# TODO: should check and read desc.xml first; and if theme already
# exists, it should remove the whole directory
for f in z.namelist():
if f[-1] == '/':
continue
path = os.path.join(theme_dir, f)
data = z.read(f)
if not os.path.exists(os.path.dirname(path)):
os.makedirs(os.path.dirname(path))
open(path, 'w').write(data)
z.close()
return redirect('themes')
def template [html] (self):
from qommon.template import get_default_ezt_template
default_template_ezt = get_default_ezt_template()
branding_cfg = get_cfg('branding', {})
template = branding_cfg.get('template', default_template_ezt)
form = Form(enctype="multipart/form-data")
form.add(TextWidget, 'template', title = _('Site Template'), value = template,
cols = 80, rows = 25)
form.add_submit('submit', _('Submit'))
form.add_submit('restore-default', _('Restore default template'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if form.get_submit() == 'cancel':
return redirect('.')
if form.get_submit() == 'restore-default':
self.template_submit()
return redirect('.')
if form.is_submitted() and not form.has_errors():
self.template_submit(form)
return redirect('.')
get_response().breadcrumb.append(('template', _('Template')))
html_top('settings', title = _('Template'))
'<h2>%s</h2>' % _('Template')
form.render()
def template_submit(self, form = None):
from qommon.template import DEFAULT_TEMPLATE_EZT, get_default_ezt_template
theme_default_template_ezt = get_default_ezt_template()
get_publisher().reload_cfg()
branding_cfg = get_cfg('branding', {})
if not form:
template = None
else:
template = form.get_widget('template').parse()
if template in (DEFAULT_TEMPLATE_EZT, theme_default_template_ezt) or not template:
if branding_cfg.has_key('template'):
del branding_cfg['template']
else:
branding_cfg['template'] = template
get_publisher().cfg['branding'] = branding_cfg
get_publisher().write_cfg()
def misc [html] (self):
misc_cfg = get_cfg('misc', {})
form = Form(enctype="multipart/form-data")
form.add(CheckboxWidget, 'do-not-token',
title = _('Do not show anything about identification tokens'),
value = misc_cfg.get('do-not-token', False))
form.add(CheckboxWidget, 'include-user-details',
title = _('Show user details on public pages'),
value = misc_cfg.get('include-user-details', False))
form.add(WidgetDict, 'namespaces',
title = _('Namespaces for prefilling'),
value = misc_cfg.get('namespaces', {}))
form.add_submit("submit", _("Submit"))
form.add_submit("cancel", _("Cancel"))
if form.get_widget('cancel').parse():
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('misc', _('Misc')))
html_top('settings', title = _('Misc'))
'<h2>%s</h2>' % _('Misc')
form.render()
else:
cfg_submit(form, 'misc', ('do-not-token', 'include-user-details','namespaces'))
redirect('.')
def export [html] (self):
form = Form(enctype="multipart/form-data")
form.add(CheckboxWidget, 'formdefs', title = _('Forms'), value = True)
form.add(CheckboxWidget, 'workflows', title = _('Workflows'), value = True)
form.add(CheckboxWidget, 'roles', title = _('Roles'), value = True)
form.add(CheckboxWidget, 'categories', title = _('Categories'), value = True)
form.add(CheckboxWidget, 'settings', title = _('Settings'), value = False)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if not form.is_submitted():
get_response().breadcrumb.append(('export', _('Export')))
html_top('settings', title = _('Export'))
'<h2>%s</h2>' % _('Export')
form.render()
else:
return self.export_submit(form)
def export_submit [plain] (self, form):
dirs = []
for w in ('formdefs', 'workflows', 'roles', 'categories'):
if form.get_widget(w) and form.get_widget(w).parse():
dirs.append(w)
if not dirs and not form.get_widget('settings').parse():
return redirect('.')
c = cStringIO.StringIO()
z = zipfile.ZipFile(c, 'w')
app_dir = get_publisher().app_dir
for d in dirs:
path = os.path.join(app_dir, d)
if not os.path.exists(path):
continue
for f in os.listdir(path):
z.write(os.path.join(path, f), os.path.join(d, f))
if form.get_widget('settings').parse():
z.write(os.path.join(app_dir, 'config.pck'), 'config.pck')
for f in os.listdir(app_dir):
if f.startswith('idp-') and os.path.splitext(f)[-1] in ('.pem', '.xml'):
z.write(os.path.join(app_dir, f), f)
if os.path.exists(os.path.join(app_dir, 'config')):
for f in os.listdir(os.path.join(app_dir, 'config')):
z.write(os.path.join(app_dir, 'config', f), os.path.join('config', f))
z.close()
response = get_response()
response.set_content_type('application/x-wcs')
response.set_header('content-disposition', 'attachment; filename=export.wcs')
return c.getvalue()
def p_import [html] (self):
form = Form(enctype='multipart/form-data')
form.add(FileWidget, 'file', title = _('File'), required = True)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('import', _('Import')))
html_top('settings', title = _('Import'))
'<h2>%s</h2>' % _('Import')
form.render()
else:
try:
results = self.import_submit(form)
except zipfile.BadZipfile:
results = None
html_top('settings', title = _('Import'))
'<h2>%s</h2>' % _('Import')
if results:
'<p>%s</p>' % _('Imported successfully:')
'<ul>'
if results['formdefs']:
'<li>%d %s</li>' % (results['formdefs'], _('forms'))
if results['workflows']:
'<li>%d %s</li>' % (results['workflows'], _('workflows'))
if results['roles']:
'<li>%d %s</li>' % (results['roles'], _('roles'))
if results['categories']:
'<li>%d %s</li>' % (results['categories'], _('categories'))
if results['settings']:
'<li>%s</li>' % _('Settings')
'</ul>'
else:
'<p>%s</p>' % _('Error: Not a valid export file')
'<a href=".">%s</a>' % _('Back')
def import_submit(self, form):
z = zipfile.ZipFile(form.get_widget('file').parse().fp, 'r')
app_dir = get_publisher().app_dir
results = {'formdefs': 0, 'workflows': 0, 'categories': 0, 'roles': 0, 'settings': 0}
for f in z.namelist():
path = os.path.join(app_dir, f)
data = z.read(f)
if not os.path.exists(os.path.dirname(path)):
os.mkdir(os.path.dirname(path))
if f == 'config.pck':
results['settings'] = 1
d = cPickle.loads(data)
if get_publisher().cfg.has_key('sp'):
current_sp = get_publisher().cfg['sp']
else:
current_sp = None
get_publisher().cfg = d
if current_sp:
get_publisher().cfg['sp'] = current_sp
elif get_publisher().cfg.has_key('sp'):
del get_publisher().cfg['sp']
get_publisher().write_cfg()
continue
open(path, 'w').write(data)
if results.has_key(os.path.split(f)[0]):
results[os.path.split(f)[0]] += 1
# rebuild indexes for imported objects
for k, v in results.items():
if k == 'settings':
continue
if v == 0:
continue
klass = None
if k == 'formdefs':
from formdef import FormDef
klass = FormDef
elif k == 'categories':
from categories import Category
klass = Category
elif k == 'roles':
from roles import Role
klass = Role
elif k == 'workflows':
from workflows import Workflow
klass = Workflow
if klass:
klass.rebuild_indexes()
z.close()
return results
def sitename [html] (self):
form = Form(enctype='multipart/form-data')
misc_cfg = get_cfg('misc', {})
form.add(StringWidget, 'sitename', title = _('Site Name'),
value = misc_cfg.get('sitename', ''))
form.add(StringWidget, 'frontoffice-url', size=32,
title = _('Frontoffice base URL'),
value = misc_cfg.get('frontoffice-url', ''))
form.add(StringWidget, 'backoffice-url', size=32,
title = _('Backoffice base URL'),
value = misc_cfg.get('backoffice-url', ''))
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('sitename', _('Site Name and Addresses')))
html_top('settings', title = _('Site Name and Addresses'))
'<h2>%s</h2>' % _('Site Name and Addresses')
form.render()
else:
cfg_submit(form, 'misc', ['sitename', 'frontoffice-url', 'backoffice-url'])
redirect('.')
def sms [html] (self):
get_response().breadcrumb.append(('sms', _('SMS')))
html_top('settings', title = _('SMS'))
'<h2>%s</h2>' % _('SMS Options')
sms_cfg = get_cfg('sms', {})
mode = sms_cfg.get('mode', 'none')
sms = SMS.get_sms_class(mode)
if sms:
'<ul>'
try:
try:
'<li>%s %s</li>' % (_('SMS Credit:'), sms.get_money_left())
except NotImplementedError:
pass
try:
'<li>%s %s</li>' % (_('SMS Left:'), sms.get_sms_left())
except NotImplementedError:
pass
except errors.SMSError:
"<p>%s</li>" % _("Connection with SMS provider failed")
'</ul>'
form = Form(enctype='multipart/form-data')
form.add(SingleSelectWidget, 'mode', title = _('SMS Mode'),
value = mode,
options = [(str('none'), _('No support'), str('none'))]+
[(str(k), _(SMS.providers.get(k)[0]), str(k)) for k in SMS.providers.keys()])
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if sms:
for widget, name, title in sms.parameters:
form.add(widget, name, title=_(title),
value=sms_cfg.get(name, ''),
required=True)
if form.get_submit() and not form.has_errors():
cfg_submit(form, 'sms', ['mode'] + [x[1] for x in sms.parameters])
if mode != form.get_widget('mode').parse():
return redirect('sms')
else:
return redirect('.')
elif mode != form.get_widget('mode').parse():
cfg_submit(form, 'sms', ['mode',])
return redirect('sms')
else:
if form.get_submit() and form.get_widget('mode').parse() == str('none'):
return redirect('.')
if form.get_submit() and not form.has_errors():
cfg_submit(form, 'sms', ['mode',])
return redirect('sms')
else:
form.render()
if mode != 'none':
'<p><a href="smstest">%s</a></p>' % _('SMS Test')
def smstest [html] (self):
form = Form(enctype='multipart/form-data', action='smstest')
form.add(StringWidget, 'sender', title=_('Sender'), required=True)
form.add(StringWidget, 'destinations', title=_('Destinations'), required=True)
form.add(StringWidget, 'text', title=_('Text'), required=True)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('sms')
get_response().breadcrumb.append(('sms', _('SMS')))
get_response().breadcrumb.append(('smstest', _('SMS Test')))
html_top('settings', title = _('SMS Test'))
'<h2>%s</h2>' % _('SMS Test')
form.render()
if form.get_submit() and not form.has_errors():
sms_cfg = get_cfg('sms', {})
mode = sms_cfg.get('mode', 'none')
sms = SMS.get_sms_class(mode)
sender = str(form.get_widget('sender').parse())
destinations = str(form.get_widget('destinations').parse()).split(str(','))
text = str(form.get_widget('text').parse())
try:
sms.send(sender, destinations, text)
except Exception, e:
'<pre>'
repr(e)
'</pre>'
else:
'<p>'
_('Success')
'</p>'
def utf8switch(self):
def toutf8(x):
if x is None:
return None
return unicode(x, 'iso-8859-1').encode('utf-8')
all_elems = []
from formdef import FormDef
for formdef in FormDef.select():
formdef.name = toutf8(formdef.name)
for field in formdef.fields:
for attr in ('label', 'hint', 'condition', 'items'):
if hasattr(field, attr) and type(getattr(field, attr)) is str:
setattr(field, attr, toutf8(getattr(field, attr)))
elif hasattr(field, attr) and type(getattr(field, attr)) is list:
setattr(field, attr, [toutf8(x) for x in getattr(field, attr)])
if hasattr(field, 'prefill') and getattr(field, 'prefill'):
if field.prefill.get('type') == 'string':
field.prefill['value'] = toutf8(field.prefill.get('value'))
form_data_class = formdef.data_class()
for form in form_data_class.select():
for k, v in form.data.items():
if type(v) is str:
form.data[k] = toutf8(v)
if form.evolution:
for evo in form.evolution:
if evo.comment:
evo.comment = toutf8(evo.comment)
all_elems.append(form)
all_elems.append(formdef)
from workflows import Workflow
for workflow in Workflow.select():
workflow.name = toutf8(workflow.name)
if workflow.possible_status:
for status in workflow.possible_status:
status.name = toutf8(status.name)
if not status.items:
continue
for item in status.items:
for attr in ('label', 'subject', 'body', 'message'):
if hasattr(item, attr) and type(getattr(item, attr)) is str:
setattr(item, attr, toutf8(getattr(item, attr)))
all_elems.append(workflow)
from categories import Category
for category in Category.select():
category.name = toutf8(category.name)
category.description = toutf8(category.description)
all_elems.append(category)
from roles import Role
for role in Role.select():
role.name = toutf8(role.name)
role.details = toutf8(role.details)
all_elems.append(role)
for user in get_publisher().user_class.select():
user.name = toutf8(user.name)
if hasattr(user, 'formdata') and user.formdata:
for k, v in user.formdata.items():
if type(v) is str:
user.formdata[k] = toutf8(v)
all_elems.append(user)
for cfg_section in get_publisher().cfg.values():
for k, v in cfg_section.items():
if type(v) is str:
cfg_section[k] = toutf8(v)
for elem in all_elems:
elem.store()
misc_cfg = get_cfg('misc', {})
misc_cfg['charset'] = 'utf-8'
get_publisher().cfg['misc'] = misc_cfg
get_publisher().write_cfg()
redirect('.')
def postgresql [html] (self):
if not get_publisher().has_site_option('postgresql'):
raise errors.TraversalError()
postgresql_cfg = get_cfg('postgresql', {})
form = Form(enctype='multipart/form-data')
form.add(StringWidget, 'dbname',
title=_('Database Name'), required=True,
value=postgresql_cfg.get('dbname'))
form.add(StringWidget, 'user',
title=_('User'), required=True,
value=postgresql_cfg.get('user'),
hint=_('User name used to authenticate'))
form.add(PasswordWidget, 'password',
title=_('Password'), required=True,
value=postgresql_cfg.get('password'),
hint=_('Password used to authenticate'))
form.add(StringWidget, 'host',
title=_('Host'), required=True,
value=postgresql_cfg.get('host', 'localhost'),
hint=_('Database host address'))
form.add(IntWidget, 'port',
title=_('Port'), required=True,
value=int(postgresql_cfg.get('port', 5432)),
hint=_('Connection port number'))
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('postgresql', _('PostgreSQL Settings')))
html_top('settings', title=_('PostgreSQL Settings'))
'<h2>%s</h2>' % _('PostgreSQL Settings')
form.render()
else:
cfg_submit(form, 'postgresql', ['dbname', 'user', 'password',
'host', 'port'])
import sql
sql.do_user_table()
redirect('.')