278 lines
10 KiB
Python
278 lines
10 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/>.
|
|
|
|
from quixote import get_publisher, get_request, get_response, get_session, redirect
|
|
from quixote.directory import Directory, AccessControlled
|
|
from quixote.html import TemplateIO, htmltext
|
|
|
|
from qommon import errors
|
|
from qommon.admin.texts import TextsDirectory
|
|
import qommon.backoffice.menu
|
|
from qommon.backoffice.menu import html_top
|
|
from qommon.form import *
|
|
|
|
from wcs import workflows
|
|
from wcs.formdef import FormDef
|
|
|
|
from boforms import FormsDirectory
|
|
from boconfig import ConfigDirectory
|
|
|
|
import quota
|
|
|
|
|
|
def generate_user_info():
|
|
# same as backoffice.menu.generate_user_info, without the admin link, but
|
|
# with a configuration link
|
|
if not get_request().user:
|
|
return ''
|
|
|
|
user = get_request().user
|
|
if user:
|
|
user = get_session().get_user_object()
|
|
username = user.display_name
|
|
else:
|
|
username = _('Unknown')
|
|
|
|
logout_url = get_publisher().get_root_url() + 'logout'
|
|
config_url = get_publisher().get_root_url() + 'backoffice/config/'
|
|
|
|
r = TemplateIO(html=True)
|
|
r += htmltext('<ul class="user-info">')
|
|
r += htmltext('<li class="ui-name">%s</li>') % username
|
|
r += htmltext('<li class="ui-logout"><a href="%s">%s</a></li>') % (logout_url, _('logout'))
|
|
|
|
if get_publisher().backoffice_help_url and \
|
|
get_request().language in get_publisher().backoffice_help_url:
|
|
help_url = get_publisher().backoffice_help_url[get_request().language]
|
|
r += htmltext('<li class="ui-help"><a href="%s">%s</a></li>') % (help_url, _('help'))
|
|
r += htmltext('</ul>')
|
|
return r.getvalue()
|
|
|
|
qommon.backoffice.menu.generate_user_info = generate_user_info
|
|
|
|
def generate_header_menu(selected = None):
|
|
s = ['<ul id="menu">\n']
|
|
base_url = get_publisher().get_root_url() + 'backoffice'
|
|
for item in get_publisher().get_backoffice_root().items:
|
|
if len(item) == 2:
|
|
k, v = item
|
|
display_function = None
|
|
elif len(item) == 3:
|
|
k, v, display_function = item
|
|
if k is None: # heading
|
|
s.append('<li><strong>%s</strong></li>' % v)
|
|
continue
|
|
if display_function and not display_function(k):
|
|
continue
|
|
if k.rstrip('/') == selected:
|
|
s.append('<li class="active">')
|
|
else:
|
|
s.append('<li>')
|
|
s.append('<a href="%s/%s">%s</a></li>\n' % (base_url, k, _(v)))
|
|
s.append('</ul>\n')
|
|
return ''.join(s)
|
|
|
|
qommon.backoffice.menu.generate_header_menu = generate_header_menu
|
|
|
|
|
|
class RootDirectory(AccessControlled, Directory):
|
|
_q_exports = ['', 'forms', 'config', 'new']
|
|
|
|
forms = FormsDirectory()
|
|
config = ConfigDirectory()
|
|
|
|
def get_items(self):
|
|
if get_response().filter.get('objectdef'):
|
|
id = get_response().filter.get('objectdef').id
|
|
return [('forms/%s/' % id, N_('Design')),
|
|
('forms/%s/diffusion/' % id, N_('Diffusion')),
|
|
('forms/%s/results/' % id, N_('Analysis'))]
|
|
return [ ('', N_('Welcome')), ]
|
|
items = property(get_items)
|
|
|
|
def register_directory(cls, *args):
|
|
pass
|
|
register_directory = classmethod(register_directory)
|
|
|
|
def register_menu_item(cls, *args):
|
|
pass
|
|
register_menu_item = classmethod(register_menu_item)
|
|
|
|
def _q_access(self):
|
|
get_response().breadcrumb = [ ('backoffice/', _('Back Office')) ]
|
|
user = get_request().user
|
|
|
|
if not user:
|
|
raise errors.AccessUnauthorizedError(
|
|
public_msg = _('Access to backoffice is restricted to authorized persons only. '\
|
|
'Please login.'))
|
|
if user and not ((hasattr(user, 'is_asec_admin') and user.is_asec_admin) or user.is_admin):
|
|
raise errors.AccessForbiddenError()
|
|
|
|
self.create_asec_objects()
|
|
|
|
def _q_index(self):
|
|
get_response().breadcrumb = [ ('backoffice/', _('Back Office of your site')) ]
|
|
html_top('', _('Questionnaires'))
|
|
r = TemplateIO(html=True)
|
|
|
|
if quota.is_expired():
|
|
r += TextsDirectory.get_html_text('asec-expired-site-backoffice')
|
|
|
|
formdefs = FormDef.select(order_by='name', ignore_errors=True)
|
|
|
|
if formdefs:
|
|
r += htmltext('<h2>%s</h2>') % _('Existing Questionnaires')
|
|
|
|
r += htmltext('<ul class="biglist" id="all-forms">')
|
|
for formdef in formdefs:
|
|
if formdef.disabled:
|
|
r += htmltext('<li class="disabled">')
|
|
else:
|
|
r += htmltext('<li>')
|
|
r += htmltext('<strong class="label"><a href="forms/%s/">%s</a></strong>') % (formdef.id, formdef.name)
|
|
r += htmltext('</li>')
|
|
r += htmltext('</ul>')
|
|
|
|
if quota.may_add_a_new_form():
|
|
r += htmltext('<h2>%s</h2>') % _('New Questionnaire')
|
|
|
|
form = Form(enctype='multipart/form-data', action='new')
|
|
form.add(StringWidget, 'name', title=_('Title'), size=40, required=True)
|
|
form.add_submit('submit', _('Create New Questionnaire'))
|
|
r += form.render()
|
|
|
|
get_response().filter['sidebar'] = self.get_sidebar()
|
|
return r.getvalue()
|
|
|
|
def get_sidebar(self):
|
|
# manually add those scripts, as the sidebar is not parsed when looking
|
|
# for popup links
|
|
get_response().add_javascript(['jquery.js', 'simplemodal/jquery.simplemodal.js', 'popup.js'])
|
|
r = TemplateIO(html=True)
|
|
r += htmltext('<div class="bo-block">')
|
|
r += htmltext('<h3>%s</h3>') % _('Your Profile')
|
|
# TODO: possiblity to create additional administrator accounts?
|
|
|
|
r += htmltext('<ul>')
|
|
r += htmltext(' <li><a href="config/contact" rel="popup">%s</a></li>') % _('Contact Information')
|
|
r += htmltext(' <li><a href="config/password" rel="popup">%s</a></li>') % _('Password Change')
|
|
r += htmltext('</ul>')
|
|
r += htmltext('</div>')
|
|
|
|
r += htmltext('<div class="bo-block">')
|
|
r += htmltext('<h3>%s</h3>') % _('Site Settings')
|
|
|
|
r += htmltext('<ul>')
|
|
r += htmltext(' <li><a href="config/sitetitle" rel="popup">%s</a></li>') % _('Title')
|
|
r += htmltext(' <li><a href="config/homepage">%s</a></li>') % _('Welcome Text')
|
|
r += htmltext(' <li><a href="config/texts/asec-recorded-vote">%s</a></li>') % _('End Text')
|
|
if quota.can_logo() or quota.can_theme():
|
|
r += htmltext(' <li><a href="config/appearance">%s</a></li>') % _('Appearance')
|
|
r += htmltext('</ul>')
|
|
r += htmltext('</div>')
|
|
return r.getvalue()
|
|
|
|
def new(self):
|
|
if not quota.may_add_a_new_form():
|
|
raise quota.QuotaExceeded()
|
|
|
|
form = Form(enctype='multipart/form-data', action='new')
|
|
form.add(StringWidget, 'name', title=_('Title'), size=40, required=True)
|
|
form.add_submit('submit', _('Submit'))
|
|
|
|
if form.has_errors():
|
|
return redirect('.')
|
|
|
|
formdef = FormDef()
|
|
name = form.get_widget('name').parse()
|
|
formdefs_name = [x.name for x in FormDef.select(ignore_errors=True) if x.id != formdef.id]
|
|
if name in formdefs_name:
|
|
form.get_widget('name').set_error(_('This name is already used'))
|
|
raise ValueError()
|
|
|
|
formdef.name = form.get_widget('name').parse()
|
|
formdef.fields = []
|
|
formdef.disabled = True
|
|
formdef.asec_status = 'soon-available'
|
|
try:
|
|
formdef.workflow_id = 'asec-default'
|
|
except IndexError:
|
|
pass
|
|
formdef.disabled = True
|
|
formdef.store() # this makes sure the form has a correct id
|
|
formdef.private = False
|
|
formdef.disabled = False
|
|
formdef.store()
|
|
|
|
return redirect('forms/%s/' % formdef.id)
|
|
|
|
def create_asec_objects(self):
|
|
if not workflows.Workflow.has_key('asec-default'):
|
|
workflow = workflows.Workflow(name=_('Default Workflow'))
|
|
workflow._version = 1
|
|
workflow.id = 'asec-default'
|
|
status = workflow.add_status(_('Done'))
|
|
status.id = 'done'
|
|
workflow.store()
|
|
|
|
if not workflows.Workflow.has_key('asec-default+anonymous'):
|
|
import anonymity
|
|
workflow = workflows.Workflow(name=_('Default Workflow, Anonymous'))
|
|
workflow._version = 1
|
|
workflow.id = 'asec-default+anonymous'
|
|
status = workflow.add_status(_('Done'))
|
|
status.items = [anonymity.AnonymiseStatusItem()]
|
|
status.id = 'done'
|
|
workflow.store()
|
|
|
|
wf1 = workflows.Workflow.get('asec-default')
|
|
wf2 = workflows.Workflow.get('asec-default+anonymous')
|
|
|
|
# fix workflows created in the first versions of asec, to have them
|
|
# versioned like new ones.
|
|
if not hasattr(wf1, 'version'):
|
|
wf1.version = 1
|
|
wf1.possible_status[0].id = 'done'
|
|
if not hasattr(wf2, 'version'):
|
|
wf2.version = 1
|
|
wf2.possible_status[0].id = 'done'
|
|
|
|
for wf in (wf1, wf2):
|
|
if wf.version < 2:
|
|
# add a Sendmail action, left blank
|
|
wf.version = 2
|
|
status = wf.get_status('done')
|
|
sendmail_item = workflows.SendmailWorkflowStatusItem()
|
|
sendmail_item.id = 'mail-on-filled'
|
|
sendmail_item.subject = _('New questionnaire ([name]) has been filled')
|
|
sendmail_item.body = _('''\
|
|
A new questionnaire ([name]) has been filled.
|
|
|
|
[details]
|
|
''')
|
|
status.items.append(sendmail_item)
|
|
wf.store()
|
|
|
|
|
|
TextsDirectory.register('asec-expired-site-backoffice',
|
|
N_('Text displayed on the backoffice when the site has expired'),
|
|
default=N_('''<p>
|
|
This site has expired. You still have access to all of your data but
|
|
your questionnaires are no longer published.
|
|
</p>
|
|
'''))
|