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/boresults.py

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