252 lines
11 KiB
Python
252 lines
11 KiB
Python
# 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/>.
|
|
|
|
from quixote import get_request, get_publisher
|
|
from quixote.html import htmltext, TemplateIO
|
|
|
|
from qommon import misc
|
|
from qommon.form import *
|
|
from qommon.backoffice.listing import pagination_links
|
|
|
|
class FormDefUI(object):
|
|
def __init__(self, formdef):
|
|
self.formdef = formdef
|
|
|
|
def listing(self, fields, selected_filter='all', url_action=None,
|
|
include_form=False, items=None, offset=0, limit=0,
|
|
query=None, order_by=None, criterias=None):
|
|
|
|
partial_display = False
|
|
|
|
if not items:
|
|
if offset and not limit:
|
|
limit = 20
|
|
items, total_count = self.get_listing_items(
|
|
selected_filter, offset, limit, query, order_by,
|
|
criterias=criterias)
|
|
if (offset > 0) or (total_count > limit > 0):
|
|
partial_display = True
|
|
|
|
get_response().add_javascript(['jquery.js'])
|
|
if not partial_display:
|
|
if not get_publisher().is_using_postgresql():
|
|
get_response().add_javascript(['tablesorter/jquery.tablesorter.min.js'])
|
|
else:
|
|
include_form = False
|
|
|
|
get_response().add_css_include('../js/tablesorter/themes/blue/style.css')
|
|
r = TemplateIO(html=True)
|
|
|
|
if self.formdef.workflow:
|
|
colours = []
|
|
for status in self.formdef.workflow.possible_status:
|
|
if status.colour and status.colour != 'FFFFFF':
|
|
fg_colour = misc.get_foreground_colour(status.colour)
|
|
colours.append((status.id, status.colour, fg_colour))
|
|
if colours:
|
|
r += htmltext('<style>')
|
|
for status_id, bg_colour, fg_colour in colours:
|
|
r += htmltext('tr.status-%s-wf-%s td.cell-status { '\
|
|
'background-color: #%s !important; color: %s !important; }\n' % (
|
|
self.formdef.workflow.id, status_id, bg_colour,
|
|
fg_colour))
|
|
r += htmltext('</style>')
|
|
|
|
r += htmltext('<table id="listing" class="sortable tablesorter">')
|
|
|
|
r += htmltext('<colgroup>')
|
|
r += htmltext('<col/>')
|
|
r += htmltext('<col/>')
|
|
for f in fields:
|
|
r += htmltext('<col />')
|
|
r += htmltext('</colgroup>')
|
|
|
|
r += htmltext('<thead><tr>')
|
|
for f in fields:
|
|
field_sort_key = None
|
|
if getattr(f, 'fake', False):
|
|
field_sort_key = f.id
|
|
if f.id == 'time':
|
|
field_sort_key = 'receipt_time'
|
|
elif f.id == 'user-label':
|
|
field_sort_key = None
|
|
else:
|
|
field_sort_key = 'f%s' % f.id
|
|
|
|
if field_sort_key:
|
|
r += htmltext('<th data-field-sort-key="%s">') % field_sort_key
|
|
else:
|
|
r += htmltext('<th>')
|
|
if len(f.label) < 20:
|
|
r += htmltext('<span>%s</span>') % f.label
|
|
else:
|
|
r += htmltext('<span title="%s">%s</span>') % (
|
|
f.label, misc.ellipsize(f.label, 20))
|
|
r += htmltext('</th>')
|
|
r += htmltext('</tr></thead>')
|
|
if include_form:
|
|
r += htmltext('<thead style="display: none">') # will be displayed by javascript
|
|
r += htmltext('<tr>')
|
|
for f in fields:
|
|
r += htmltext('<td>')
|
|
if f.type == 'item' and f.items:
|
|
r += htmltext('<select onchange="updateListing()" name="f-%s">') % f.id
|
|
r += htmltext('<option value="">%s</option>') % _('All')
|
|
for item in f.items:
|
|
r += htmltext('<option value="%s">%s</option>') % (item, misc.ellipsize(item, 20))
|
|
r += htmltext('</select>')
|
|
if f.type == 'status':
|
|
r += htmltext('<select name="status" onchange="updateListing()">')
|
|
r += htmltext('<option value="">%s</option>') % _('All')
|
|
if self.formdef.workflow:
|
|
for status in self.formdef.workflow.possible_status:
|
|
r += htmltext('<option value="wf-%s">%s</option>') % (status.id, status.name)
|
|
r += htmltext('</select>')
|
|
r += htmltext('</td>')
|
|
r += htmltext('</tr>')
|
|
r += htmltext('</thead>')
|
|
|
|
r += htmltext('<tbody>')
|
|
r += htmltext(self.tbody(fields, items, url_action))
|
|
r += htmltext('</tbody>')
|
|
r += htmltext('</table>')
|
|
|
|
if partial_display:
|
|
# add links to paginate
|
|
r += pagination_links(offset, limit, total_count)
|
|
|
|
return r.getvalue()
|
|
|
|
def get_listing_items(self, selected_filter='all', offset=None,
|
|
limit=None, query=None, order_by=None, user=None, criterias=None):
|
|
formdata_class = self.formdef.data_class()
|
|
if selected_filter == 'all':
|
|
item_ids = formdata_class.keys()
|
|
else:
|
|
applied_filters = []
|
|
if selected_filter == 'pending':
|
|
applied_filters = ['wf-%s' % x.id for x in \
|
|
self.formdef.workflow.get_not_endpoint_status()]
|
|
elif selected_filter == 'done':
|
|
applied_filters = ['wf-%s' % x.id for x in \
|
|
self.formdef.workflow.get_endpoint_status()]
|
|
else:
|
|
applied_filters = ['wf-%s' % selected_filter]
|
|
item_ids = []
|
|
for status_id in applied_filters:
|
|
item_ids.extend(formdata_class.get_ids_with_indexed_value(
|
|
str('status'), status_id))
|
|
|
|
if query:
|
|
query_ids = formdata_class.get_ids_from_query(query)
|
|
item_ids = list(set(item_ids).intersection(query_ids))
|
|
|
|
if criterias:
|
|
select_ids = [x.id for x in formdata_class.select(clause=criterias)]
|
|
item_ids = list(set(item_ids).intersection(select_ids))
|
|
|
|
if self.formdef.acl_read != 'all' and item_ids:
|
|
# if the formdef has some ACL defined, we don't go the full way of
|
|
# supporting all the cases but assume that as we are in the
|
|
# backoffice, we don't have to care about the situation where the
|
|
# user is the submitter, and may limit ourselves to consider
|
|
# treating roles.
|
|
user = user or get_request().user
|
|
if not user.is_admin:
|
|
user_roles = set(user.roles or [])
|
|
concerned_ids = set()
|
|
for role in user_roles:
|
|
concerned_ids |= set(formdata_class.get_ids_with_indexed_value(
|
|
'concerned_roles', str(role)))
|
|
item_ids = list(set(item_ids).intersection(concerned_ids))
|
|
|
|
if order_by:
|
|
ordered_ids = formdata_class.get_sorted_ids(order_by)
|
|
new_item_ids = []
|
|
for item_id in ordered_ids:
|
|
if item_id in item_ids:
|
|
new_item_ids.append(item_id)
|
|
item_ids = new_item_ids
|
|
else:
|
|
item_ids.sort(lambda x,y: cmp(int(x), int(y)))
|
|
item_ids.reverse()
|
|
|
|
total_count = len(item_ids)
|
|
|
|
if not offset:
|
|
offset = 0
|
|
|
|
if limit:
|
|
items = formdata_class.get_ids(item_ids[offset:offset+limit],
|
|
keep_order=True)
|
|
else:
|
|
items = formdata_class.get_ids(item_ids, keep_order=True)
|
|
|
|
return (items, total_count)
|
|
|
|
|
|
def tbody(self, fields=None, items=None, url_action=None):
|
|
r = TemplateIO(html=True)
|
|
if url_action:
|
|
pass
|
|
#url_action = '/' + url_action
|
|
else:
|
|
url_action = ''
|
|
root_url = get_publisher().get_root_url()
|
|
for i, filled in enumerate(items):
|
|
if filled.is_draft(): # skipping drafts
|
|
continue
|
|
if i%2:
|
|
style = 'even'
|
|
else:
|
|
style = 'odd'
|
|
link = str(filled.id) + '/'
|
|
data = ' data-link="%s"' % link
|
|
if filled.anonymised:
|
|
data += ' data-anonymised="true"'
|
|
r += htmltext('<tr class="status-%s-%s %s"%s>' % (filled.formdef.workflow.id,
|
|
filled.status, style, data))
|
|
for i, f in enumerate(fields):
|
|
if f.type == 'id':
|
|
r += htmltext('<td class="cell-id"><a href="%s%s">%s</a></td>') % (link, url_action,
|
|
filled.get_display_id())
|
|
elif f.type == 'time':
|
|
r += htmltext('<td class="cell-time">%s</td>') % misc.localstrftime(filled.receipt_time)
|
|
elif f.type == 'user-label':
|
|
try:
|
|
value = get_publisher().user_class.get(filled.user_id).display_name
|
|
r += htmltext('<td class="cell-user">%s</td>') % value
|
|
except:
|
|
r += htmltext('<td class="cell-user cell-no-user">-</td>')
|
|
elif f.type == 'status':
|
|
r += htmltext('<td class="cell-status">%s</td>') % filled.get_status_label()
|
|
elif f.type == 'anonymised':
|
|
if filled.anonymised:
|
|
anonymised = _('Yes')
|
|
else:
|
|
anonymised = _('No')
|
|
r += htmltext('<td class="cell-anonymised">%s</td>') % anonymised
|
|
else:
|
|
r += htmltext('<td>')
|
|
value = filled.data.get('%s_display' % f.id, filled.data.get(f.id))
|
|
if value is not None:
|
|
s = f.get_view_short_value(value, min(120/len(fields), 30))
|
|
s = s.replace(str('[download]'), str('%sdownload' % link))
|
|
r += s
|
|
r += htmltext('</td>')
|
|
r += htmltext('</tr>\n')
|
|
return r.getvalue()
|