wcs/wcs/wf/form.py

222 lines
8.4 KiB
Python

# w.c.s. - web application for online forms
# Copyright (C) 2005-2013 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/>.
import xml.etree.ElementTree as ET
from qommon import _
from qommon.form import *
from wcs.workflows import WorkflowStatusItem, register_item_class
from wcs.formdef import FormDef, lax_int
from wcs.admin.fields import FieldDefPage, FieldsDirectory
from wcs.formdata import get_dict_with_varnames
from wcs.forms.common import FileDirectory
def lookup_wf_form_file(self, filename):
# supports for URLs such as /$formdata/$id/files/form-$formvar-$fieldvar/test.txt
try:
literal, formvar, fieldvar = self.reference.split('-')
except ValueError:
return
if literal != 'form':
return
try:
return self.formdata.workflow_data['%s_var_%s_raw' % (formvar, fieldvar)]
except KeyError:
return
class WorkflowFormFieldsFormDef(FormDef):
lightweight = False
def __init__(self, item):
self.name = _('Workflow Form Fields')
self.item = item
self.fields = []
self.id = None
def store(self):
self.item.parent.parent.store()
class WorkflowFormFieldDefPage(FieldDefPage):
section = 'workflows'
def form(self):
form = super(WorkflowFormFieldDefPage, self).form()
form.remove('in_listing')
return form
class WorkflowFormFieldsDirectory(FieldsDirectory):
section = 'workflows'
support_import = False
blacklisted_types = ['page']
blacklisted_attributes = ['condition']
field_def_page_class = WorkflowFormFieldDefPage
class FormWorkflowStatusItem(WorkflowStatusItem):
description = N_('Form')
key = 'form'
category = 'interaction'
ok_in_global_action = False
endpoint = False
waitpoint = True
by = []
formdef = None
varname = None
@classmethod
def init(cls):
if not 'lookup_wf_form_file' in FileDirectory._lookup_methods:
FileDirectory._lookup_methods.append('lookup_wf_form_file')
FileDirectory.lookup_wf_form_file = lookup_wf_form_file
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
super(FormWorkflowStatusItem, self).add_parameters_widgets(
form, parameters, prefix=prefix, formdef=formdef)
if 'by' in parameters:
form.add(WidgetList, '%sby' % prefix, title = _('To'), element_type = SingleSelectWidget,
value = self.by,
add_element_label = _('Add Role'),
element_kwargs = {'render_br': False,
'options': [(None, '---', None)] +
self.get_list_of_roles(include_logged_in_users=False)})
if 'varname' in parameters:
form.add(VarnameWidget, '%svarname' % prefix, required=True,
title=_('Identifier'), value=self.varname,
hint=_('This is used as prefix for form fields variable names.'))
form.widgets.append(HtmlWidget(htmltext('<p><a href="fields/">%s</a></p>') % _('Edit Fields')))
def get_parameters(self):
return ('by', 'varname', 'condition')
def migrate(self):
changed = False
if self.formdef and self.formdef.fields:
for field in self.formdef.fields:
changed |= field.migrate()
return changed
def export_to_xml(self, charset, include_id=False):
item = WorkflowStatusItem.export_to_xml(self, charset, include_id=include_id)
if not hasattr(self, 'formdef') or not self.formdef or not self.formdef.fields:
return item
formdef = ET.SubElement(item, 'formdef')
# we give a name to the formdef because it is required in the formdef
# xml import.
ET.SubElement(formdef, 'name').text = '-'
fields = ET.SubElement(formdef, 'fields')
for field in self.formdef.fields:
fields.append(field.export_to_xml(charset=charset, include_id=include_id))
return item
def init_with_xml(self, elem, charset, include_id=False):
WorkflowStatusItem.init_with_xml(self, elem, charset)
el = elem.find('formdef')
if el is None:
return
# we can always include id in the formdef export as it lives in
# a different space, isolated from other formdefs.
imported_formdef = FormDef.import_from_xml_tree(el, include_id=True)
self.formdef = WorkflowFormFieldsFormDef(item=self)
self.formdef.fields = imported_formdef.fields
if self.formdef.max_field_id is None and self.formdef.fields:
self.formdef.max_field_id = max([lax_int(x.id) for x in self.formdef.fields])
def q_admin_lookup(self, workflow, status, component, html_top):
if component == 'fields':
if not self.formdef:
self.formdef = WorkflowFormFieldsFormDef(item=self)
fields_directory = WorkflowFormFieldsDirectory(self.formdef)
if self.varname:
fields_directory.field_var_prefix = '%s_var_' % self.varname
fields_directory.html_top = html_top
return fields_directory
return None
def fill_form(self, form, formdata, user):
if not self.formdef:
return
self.formdef.add_fields_to_form(form)
form.add_submit('submit', _('Submit'))
# put varname in a form attribute so it can be used in templates to
# identify the form.
form.varname = self.varname
formdata.feed_session()
req = get_request()
for field in self.formdef.fields:
if ('f%s' % field.id) in req.form:
continue
if not field.prefill or field.prefill.get('type') == 'none':
continue
# FIXME: this code duplicates code from wcs/forms/root.py :/
prefill_user = get_request().user
if get_request().is_in_backoffice():
prefill_user = get_publisher().substitutions.get_context_variables(
).get('form_user')
v, verified = field.get_prefill_value(user=prefill_user)
if get_request().is_in_backoffice() and (
field.prefill and field.prefill.get('type') == 'geoloc'):
# turn off prefilling from geolocation attributes if
# the form is filled from the backoffice
v = None
if v:
form.get_widget('f%s' % field.id).set_value(v)
req.form['f%s' % field.id] = v
def submit_form(self, form, formdata, user, evo):
if not self.formdef:
return
if form.get_submit() == 'submit' and not form.has_errors():
workflow_data = {}
for k, v in get_dict_with_varnames(
self.formdef.fields, self.formdef.get_data(form),
varnames_only=True).items():
workflow_data['%s_%s' % (self.varname, k)] = v
formdata.update_workflow_data(workflow_data)
formdata.store()
def get_parameters_view(self):
r = TemplateIO(html=True)
r += super(FormWorkflowStatusItem, self).get_parameters_view()
if self.formdef and self.formdef.fields:
r += htmltext('<p>%s</p>') % _('Form:')
r += htmltext('<ul>')
for field in self.formdef.fields:
r += htmltext('<li>')
r += field.label
if getattr(field, 'required', True):
r += htmltext(' (%s)') % _('required')
r += htmltext(' (%s)') % _(field.description)
if field.varname:
r += htmltext(' (<tt>%s</tt>)') % field.varname
r += htmltext('</li>')
r += htmltext('</ul>')
return r.getvalue()
register_item_class(FormWorkflowStatusItem)