331 lines
12 KiB
Python
331 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/>.
|
|
|
|
from quixote import get_request, get_response, redirect
|
|
from quixote.directory import Directory
|
|
from quixote.html import TemplateIO, htmltext
|
|
|
|
from qommon.backoffice.menu import html_top
|
|
from qommon import errors, misc, get_logger
|
|
|
|
from wcs.backoffice.root import FormPage
|
|
from wcs.formdef import FormDef
|
|
from wcs.users import User
|
|
|
|
import anonymity
|
|
|
|
def fixcsv(s):
|
|
if type(s) is not str: return s
|
|
if not s: return s
|
|
return s #.replace('\n', ' ').replace(';', ',')
|
|
|
|
class FakeField:
|
|
def __init__(self, id, label):
|
|
self.id = id
|
|
self.label = label
|
|
|
|
def get_view_value(self, value):
|
|
# just here to quack like a duck
|
|
return None
|
|
|
|
def get_csv_heading(self):
|
|
return [self.label]
|
|
|
|
def get_csv_value(self, element):
|
|
return [element]
|
|
|
|
|
|
class FormResultDirectory(FormPage):
|
|
_q_exports = ['', 'csv', 'xls', 'participation', 'table', 'list', 'export']
|
|
|
|
def __init__(self, formdef):
|
|
self.formdef = formdef
|
|
|
|
def html_top(self, section, *args, **kwargs):
|
|
html_top('forms/%s/results' % self.formdef.id, *args, **kwargs)
|
|
|
|
def _q_index(self):
|
|
self.html_top(_('Analysis'))
|
|
r = TemplateIO(html=True)
|
|
r += htmltext('<h2>%s</h2>') % _('Analysis')
|
|
|
|
if self.formdef.asec_status == 'running':
|
|
r += htmltext('<p>')
|
|
r += _('The questionnaire is still running, this is therefore preliminary data.')
|
|
r += htmltext('</p>')
|
|
|
|
values = self.formdef.data_class().select()
|
|
|
|
no_forms = len(values)
|
|
r += htmltext('<p>%s %d</p>') % (_('Total number of records:'), no_forms)
|
|
# XXX: insert participation stats here
|
|
r += self.stats_fields(values)
|
|
|
|
get_response().filter['sidebar'] = self.get_results_sidebar()
|
|
return r.getvalue()
|
|
|
|
def get_results_sidebar(self, qs=''):
|
|
r = TemplateIO(html=True)
|
|
r += htmltext('<ul>')
|
|
r += htmltext(' <li><a href="list%s">%s</a></li>') % (qs, _('List of results'))
|
|
r += htmltext(' <li><a href="table%s">%s</a></li>') % (qs, _('Table of results'))
|
|
r += htmltext(' <li><a href="csv%s">%s</a></li>') % (qs, _('CSV Export'))
|
|
if str(self.formdef.workflow_id).endswith(str('+anonymous')):
|
|
r += htmltext(' <li><a href="participation">%s</a>') % _('Participation')
|
|
r += htmltext('</ul>')
|
|
return r.getvalue()
|
|
|
|
def csv_tuple_heading(self, fields):
|
|
if str(self.formdef.workflow_id).endswith(str('+anonymous')):
|
|
heading_fields = ['#code']
|
|
else:
|
|
heading_fields = ['#id', _('time'), _('userlabel')]
|
|
for field in fields:
|
|
heading_fields.extend(field.get_csv_heading())
|
|
return heading_fields
|
|
|
|
def csv_tuple(self, fields, data):
|
|
if str(self.formdef.workflow_id).endswith(str('+anonymous')):
|
|
try:
|
|
elements = [data.verification_code]
|
|
except AttributeError:
|
|
elements = ['-']
|
|
else:
|
|
try:
|
|
userlabel = User.get(data.user_id).display_name
|
|
except:
|
|
userlabel = ''
|
|
elements = [str(data.id), misc.localstrftime(data.receipt_time), userlabel]
|
|
|
|
for field in fields:
|
|
element = data.data.get(field.id, '') or ''
|
|
elements.extend(field.get_csv_value(element))
|
|
return elements
|
|
|
|
def get_filter_from_query(self):
|
|
if 'filter' in get_request().form:
|
|
return get_request().form['filter']
|
|
return 'all'
|
|
|
|
def participation(self):
|
|
if not str(self.formdef.workflow_id).endswith(str('+anonymous')):
|
|
raise errors.TraversalError()
|
|
get_logger().info('backoffice - form %s - participation' % self.formdef.name)
|
|
self.html_top('%s - %s' % (_('Participation'), self.formdef.name))
|
|
r = TemplateIO(html=True)
|
|
get_response().breadcrumb.append( ('participation', _('Participation')) )
|
|
r += htmltext('<h2>%s - %s</h2>') % (self.formdef.name, _('Participation'))
|
|
|
|
nb_users = 0
|
|
if self.formdef.roles:
|
|
for user in User.select():
|
|
for role_id in self.formdef.roles:
|
|
if role_id in (user.roles or []):
|
|
break
|
|
else:
|
|
continue
|
|
nb_users += 1
|
|
|
|
r += htmltext('<ul>')
|
|
r += htmltext(' <li>%s</li>') % _('Registered Participants: %s') % nb_users
|
|
|
|
voters = anonymity.get_voters(self.formdef)
|
|
r += htmltext(' <li>%s</li>') % _('Registered Responses: %s') % len(voters)
|
|
if nb_users:
|
|
r += htmltext(' <li>%s</li>') % _('Abstention: %.2f%%') % (100*(1.0-(1.0*len(voters)/nb_users)))
|
|
else:
|
|
r += htmltext(' <li>%s</li>') % _('Abstention: n/a')
|
|
r += htmltext('</ul>')
|
|
|
|
r += htmltext('<h3>%s</h3>') % _('List of participants')
|
|
|
|
r += htmltext('<ul>')
|
|
for v in sorted(voters):
|
|
try:
|
|
r += htmltext('<li>%s</li>') % User.get(v).display_name
|
|
except KeyError:
|
|
r += htmltext('<li>%s</li>') % _('Deleted user')
|
|
r += htmltext('</ul>')
|
|
return r.getvalue()
|
|
|
|
def get_fields_from_query(self):
|
|
field_ids = [x for x in get_request().form.keys()]
|
|
if not field_ids:
|
|
for field in self.formdef.fields:
|
|
if not hasattr(field, str('get_view_value')):
|
|
continue
|
|
field_ids = [field.id]
|
|
break
|
|
|
|
fields = []
|
|
for field in self.get_formdef_fields():
|
|
if field.id in field_ids:
|
|
fields.append(field)
|
|
|
|
return fields
|
|
|
|
def list(self):
|
|
self.html_top('%s - %s' % (_('List of results'), self.formdef.name))
|
|
r = TemplateIO(html=True)
|
|
fields = self.get_fields_from_query()
|
|
qs = ''
|
|
if get_request().get_query():
|
|
qs = '?' + get_request().get_query()
|
|
get_response().filter['sidebar'] = self.get_results_sidebar(qs) + self.get_fields_sidebar(fields)
|
|
get_response().breadcrumb.append( ('list', _('List of results')) )
|
|
|
|
if len(fields) == 1:
|
|
r += htmltext('<h2>%s</h2>') % fields[0].label
|
|
else:
|
|
r += htmltext('<h2>%s</h2>') % _('List of results')
|
|
|
|
r += htmltext('<div class="fields-listing">')
|
|
for result in self.formdef.data_class().select(order_by='id'):
|
|
had_data = False
|
|
for field in fields:
|
|
value = None
|
|
if isinstance(field, FakeField):
|
|
if field.id == 'id':
|
|
value = result.id
|
|
elif field.id == 'time':
|
|
value = misc.localstrftime(result.receipt_time)
|
|
elif field.id == 'user-label':
|
|
try:
|
|
value = User.get(result.user_id).display_name
|
|
except:
|
|
pass
|
|
elif field.id == 'verification-code':
|
|
try:
|
|
value = result.verification_code
|
|
except AttributeError:
|
|
pass
|
|
else:
|
|
if not result.data.has_key(field.id):
|
|
continue
|
|
if not hasattr(field, str('get_view_value')):
|
|
continue
|
|
value = result.data[field.id]
|
|
if value:
|
|
value = field.get_view_value(value)
|
|
value = value.replace(str('[download]'), str(''))
|
|
|
|
if value is None or value == '':
|
|
continue
|
|
|
|
if not had_data:
|
|
r += htmltext('<div class="dataview">')
|
|
had_data = True
|
|
if len(fields) > 1:
|
|
r += htmltext('<p><span class="label">%s</span> ') % field.label
|
|
r += htmltext('<span class="value">')
|
|
r += value
|
|
r += htmltext('</span></p>')
|
|
if had_data:
|
|
r += htmltext('</div>')
|
|
r += htmltext('</div>')
|
|
return r.getvalue()
|
|
|
|
def table(self):
|
|
self.html_top('%s - %s' % (_('Table of results'), self.formdef.name))
|
|
r = TemplateIO(html=True)
|
|
fields = self.get_fields_from_query()
|
|
qs = ''
|
|
if get_request().get_query():
|
|
qs = '?' + get_request().get_query()
|
|
get_response().filter['sidebar'] = self.get_results_sidebar(qs) + self.get_fields_sidebar(fields)
|
|
get_response().breadcrumb.append( ('table', _('Table of results')) )
|
|
|
|
r += htmltext('<h2>%s</h2>') % _('Table of results')
|
|
|
|
r += htmltext('<table id="listing">')
|
|
r += htmltext('<thead>')
|
|
for field in fields:
|
|
r += htmltext('<th>%s</th>') % field.label
|
|
r += htmltext('</thead>')
|
|
r += htmltext('<tbody>')
|
|
for result in self.formdef.data_class().select(order_by='id'):
|
|
had_data = False
|
|
for field in fields:
|
|
value = None
|
|
if isinstance(field, FakeField):
|
|
if field.id == 'id':
|
|
value = result.id
|
|
elif field.id == 'time':
|
|
value = misc.localstrftime(result.receipt_time)
|
|
elif field.id == 'user-label':
|
|
try:
|
|
value = User.get(result.user_id).display_name
|
|
except:
|
|
pass
|
|
elif field.id == 'verification-code':
|
|
try:
|
|
value = result.verification_code
|
|
except AttributeError:
|
|
pass
|
|
else:
|
|
if result.data.has_key(field.id):
|
|
value = result.data[field.id]
|
|
if value:
|
|
value = field.get_view_value(value)
|
|
value = value.replace(str('[download]'), str(''))
|
|
|
|
if not had_data:
|
|
r += htmltext('<tr>')
|
|
had_data = True
|
|
r += htmltext('<td>')
|
|
r += value
|
|
r += htmltext('</td>')
|
|
if had_data:
|
|
r += htmltext('</tr>')
|
|
r += htmltext('</tbody>')
|
|
r += htmltext('</table>')
|
|
return r.getvalue()
|
|
|
|
def get_fields_sidebar(self, fields):
|
|
r = TemplateIO(html=True)
|
|
r += htmltext('<h3>%s</h3>') % _('Fields to display')
|
|
r += htmltext('<form>')
|
|
r += htmltext('<ul>')
|
|
for field in self.get_formdef_fields():
|
|
if not hasattr(field, str('get_view_value')):
|
|
continue
|
|
r += htmltext('<li><input type="checkbox" name="%s"') % field.id
|
|
if field.id in [x.id for x in fields]:
|
|
r += htmltext(' checked="checked"')
|
|
r += htmltext('/>')
|
|
r += htmltext('<label for="%s">%s</label>') % (field.id, field.label)
|
|
r += htmltext('</li>')
|
|
r += htmltext('</ul>')
|
|
r += htmltext('<input type="submit" value="%s"/>') % _('Reload')
|
|
r += htmltext('</form>')
|
|
return r.getvalue()
|
|
|
|
def get_formdef_fields(self):
|
|
fields = []
|
|
if not str(self.formdef.workflow_id).endswith(str('+anonymous')):
|
|
fields.append(FakeField('id', _('Identifier')))
|
|
fields.append(FakeField('time', _('Time')))
|
|
fields.append(FakeField('user-label', _('User Label')))
|
|
|
|
fields.extend(self.formdef.fields)
|
|
|
|
if str(self.formdef.workflow_id).endswith(str('+anonymous')):
|
|
fields.append(FakeField('verification-code', _('Verification Code')))
|
|
|
|
return fields
|
|
|
|
|