This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
asec/extra/modules/boconfig.py

320 lines
12 KiB
Python

# w.c.s. (asec) - w.c.s. extension for poll & survey service
# Copyright (C) 2010-2011 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import imghdr
from quixote import get_request, get_response, get_session, redirect
from quixote.directory import Directory
from quixote.html import TemplateIO, htmltext
from qommon import misc, get_cfg, get_logger
from qommon.admin.cfg import cfg_submit
from qommon.backoffice.menu import html_top
import qommon.ident.password
from qommon.ident.password_accounts import PasswordAccount
import qommon.admin.texts
from qommon.form import *
import quota
def get_logo_url():
pages_data_dir = os.path.join(get_publisher().app_dir, 'pages', 'data')
for f in ('png', 'jpeg', 'gif'):
logo_path = os.path.join(pages_data_dir, 'logo.%s' % f)
if os.path.exists(logo_path):
return '%spages/data/logo.%s' % (get_publisher().get_root_url(), f)
return None
class TextsDirectory(qommon.admin.texts.TextsDirectory):
def html_top(self, title):
html_top('config', title)
class ConfigDirectory(Directory):
_q_exports = ['', 'password', 'contact', 'sitetitle', 'homepage', 'texts',
'appearance', 'logo']
def _q_traverse (self, path):
get_response().breadcrumb.append( ('config/', _('Configuration')) )
self.texts = TextsDirectory()
self.texts.texts_dict = self.texts.texts_dict.copy()
for k in self.texts.texts_dict.keys():
if k not in ('asec-recorded-vote',):
del self.texts.texts_dict[k]
return Directory._q_traverse(self, path)
def _q_index(self):
return redirect('..')
def contact(self):
get_response().breadcrumb.append( ('contact', _('Contact Information')) )
r = TemplateIO(html=True)
form = Form(enctype='multipart/form-data')
user = get_request().user
form.add(StringWidget, 'name', title=_('Name'), required=True, size=30,
value = user.name)
form.add(EmailWidget, 'email', title=_('Email'), required=False, size=30,
value=user.email)
form.add_submit('submit', _('Apply Changes'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
self.contact_submit(form)
return redirect('.')
html_top('config', _('Contact Information'))
r += htmltext('<h2>%s</h2>') % _('Contact Information')
r += form.render()
return r.getvalue()
def contact_submit(self, form):
user = get_request().user
for f in ('name', 'email'):
widget = form.get_widget(f)
if widget:
setattr(user, f, widget.parse())
user.store()
def password(self):
get_response().breadcrumb.append( ('password', _('Password Change')) )
ident_method = get_cfg('identification', {}).get('methods', ['idp'])[0]
if ident_method != 'password':
raise errors.TraversalError()
form = Form(enctype='multipart/form-data')
form.add(PasswordWidget, 'current_password', title=_('Current Password'),
required=True)
form.add(PasswordWidget, 'new_password', title=_('New Password'),
required=True)
form.add(PasswordWidget, 'new2_password', title=_('New Password (confirm)'),
required=True)
form.add_submit('submit', _('Change Password'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
account = PasswordAccount.get(get_session().username)
if not account.is_password_ok(form.get_widget('current_password').parse()):
form.set_error('current_password', _('Wrong Password'))
if form.is_submitted() and not form.has_errors():
qommon.ident.password.check_password(form, 'new_password')
new_password = form.get_widget('new_password').parse()
new2_password = form.get_widget('new2_password').parse()
if new_password != new2_password:
form.set_error('new2_password', _('Passwords do not match'))
if form.is_submitted() and not form.has_errors():
passwords_cfg = get_cfg('passwords', {})
account = PasswordAccount.get(get_session().username)
account.hashing_algo = passwords_cfg.get('hashing_algo')
account.set_password(new_password)
account.store()
return redirect('.')
html_top('config', _('Password Change'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Password Change')
r += form.render()
return r.getvalue()
def sitetitle(self):
get_response().breadcrumb.append( ('sitetitle', _('Site Title')) )
misc_cfg = get_cfg('misc', {})
form = Form(enctype='multipart/form-data')
form.add(StringWidget, 'sitename', title=_('Site Title'),
value=misc_cfg.get('sitename', ''), size=30)
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():
html_top('config', title = _('Site Title'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Site Title')
r += form.render()
return r.getvalue()
else:
cfg_submit(form, 'misc', ['sitename'])
redirect('.')
def homepage(self):
get_response().breadcrumb.append( ('homepage', _('Home Page Text')) )
texts_cfg = get_cfg('texts', {})
form = Form(enctype='multipart/form-data')
form.add(TextWidget, 'welcome-unlogged', title=_('For unlogged users'),
value=texts_cfg.get('text-welcome-unlogged'), cols=80, rows=10)
form.add(TextWidget, 'welcome-logged', title=_('For logged users'),
value=texts_cfg.get('text-welcome-logged'), cols=80, rows=10)
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():
html_top('config', title = _('Home Page Text'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Home Page Text')
r += form.render()
return r.getvalue()
else:
texts_cfg[str('text-welcome-unlogged')] = form.get_widget('welcome-unlogged').parse()
texts_cfg[str('text-welcome-logged')] = form.get_widget('welcome-logged').parse()
get_publisher().cfg[str('texts')] = texts_cfg
get_publisher().write_cfg()
redirect('.')
def appearance(self):
get_response().breadcrumb.append(('appearance', _('Appearance')))
html_top('config', title = _('Appearance'))
r = TemplateIO(html=True)
if quota.can_theme():
r += htmltext("<h2>%s</h2>") % _('Appearance')
r += self.appearance_theme()
if quota.can_logo():
r += self.appearance_logo()
return r.getvalue()
def appearance_theme(self):
request = get_request()
if request.form.has_key('theme'):
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()
current_theme = get_cfg('branding', {}).get('theme', 'default')
r = TemplateIO(html=True)
r += htmltext('<div class="themes">')
r += htmltext('<p>')
r += _('Click on a thumbnail to change the appearance of your site.')
r += htmltext('</p>')
themes = qommon.template.get_themes()
for theme, (label, desc, author, icon) in sorted(themes.items()):
if not theme.startswith(str('asec')):
# ignore themes that were not made for asec
continue
if current_theme == theme:
active = ' active'
else:
active = ''
r += htmltext('<div class="theme%s">') % active
r += htmltext('<a href="appearance?theme=%s">') % theme
r += htmltext('<img src="/themes/%s/icon.png" alt="" class="theme-icon" />') % theme
r += htmltext('</a>')
r += htmltext('</div>')
r += htmltext('<hr class="clear" />')
r += htmltext('</div>')
return r.getvalue()
def appearance_logo(self):
r = TemplateIO(html=True)
r += htmltext('<div id="logo-selection">')
r += htmltext('<h2>%s</h2>') % _('Logo')
r += get_session().display_message()
logo_url = get_logo_url()
if logo_url:
r += htmltext('<img src="%s" />') % logo_url
r += htmltext('<form action="logo" enctype="multipart/form-data" method="post">')
r += htmltext('<input type="file" name="file" />')
if logo_url:
r += htmltext('<input type="submit" name="submit" value="%s" />') % _('Upload New Logo')
r += htmltext('<input type="submit" name="remove" value="%s" />') % _('Remove Current Logo')
else:
r += htmltext('<input type="submit" name="submit" value="%s" />') % _('Upload Logo')
r += htmltext('</form>')
r += htmltext('</div>')
return r.getvalue()
def logo(self):
if not quota.can_logo():
raise quota.NotAvailableFeature()
form = Form(enctype='multipart/form-data', use_tokens=False)
form.add(FileWidget, 'file', title = _('Theme'), required=True)
form.add_submit('submit', _('Upload'))
form.add_submit('remove', _('Remove'))
if not form.is_submitted():
return redirect('appearance')
pages_data_dir = os.path.join(get_publisher().app_dir, 'pages', 'data')
if form.get_submit() == 'remove':
for f in ('png', 'jpeg', 'gif'):
logo_path = os.path.join(pages_data_dir, 'logo.%s' % f)
if os.path.exists(logo_path):
os.unlink(logo_path)
return redirect('appearance')
# how come?
return redirect('appearance')
if form.has_errors():
get_session().message = ('error', _('Failed to set logo.'))
return redirect('appearance')
logo = form.get_widget('file').parse().fp.read()
try:
format = imghdr.what(None, logo)
except:
get_session().message = ('error', _('Failed to set logo (unknown format).'))
return redirect('appearance')
if format not in ('png', 'jpeg', 'gif'):
get_session().message = ('error',
_('Failed to set logo (format must be png, jpeg, or gif).'))
return redirect('appearance')
if not os.path.exists(pages_data_dir):
os.makedirs(pages_data_dir)
for f in ('png', 'jpeg', 'gif'):
logo_path = os.path.join(pages_data_dir, 'logo.%s' % f)
if f == format:
file(logo_path, 'w').write(logo)
else:
# make sure older logo are removed
if os.path.exists(logo_path):
os.unlink(logo_path)
return redirect('appearance')