general: store conditions as type/value dictionaries (#21550)

This commit is contained in:
Frédéric Péters 2018-02-24 15:43:04 +01:00
parent 653a2b8efc
commit 2c0e8e4d05
11 changed files with 241 additions and 61 deletions

View File

@ -1210,18 +1210,18 @@ def test_form_edit_page_field(pub):
assert FormDef.get(1).fields[0].label == 'foobar'
resp = resp.click('Edit', href='1/')
resp.form['post_conditions$element0$condition'] = 'foo'
resp.form['post_conditions$element0$condition$value_python'] = 'foo'
resp.form['post_conditions$element0$error_message'] = 'bar'
resp = resp.form.submit('post_conditions$add_element')
resp.form['post_conditions$element1$condition'] = 'foo2'
resp.form['post_conditions$element1$condition$value_python'] = 'foo2'
resp = resp.form.submit('submit')
assert 'Both condition and error message are required.' in resp.body
resp.form['post_conditions$element1$error_message'] = 'bar2'
resp = resp.form.submit('submit')
assert FormDef.get(1).fields[0].post_conditions == [
{'condition': 'foo', 'error_message': 'bar'},
{'condition': 'foo2', 'error_message': 'bar2'},
{'condition': {'type': 'python', 'value': 'foo'}, 'error_message': 'bar'},
{'condition': {'type': 'python', 'value': 'foo2'}, 'error_message': 'bar2'},
]
def test_form_edit_comment_field(pub):

View File

@ -3676,7 +3676,7 @@ def test_backoffice_logged_errors(pub):
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
jump.status = 'rejected'
jump.condition = '1/0' # ZeroDivisionError
jump.condition = {'type': 'python', 'value': '1/0'} # ZeroDivisionError
st1 = workflow.possible_status[0]
st1.items.insert(0, jump)
jump.parent = st1

View File

@ -119,7 +119,7 @@ def test_page():
formdef.fields = []
page = fields.PageField()
assert page.is_visible({}, formdef) is True
page.condition = 'var_foo == "bar"'
page.condition = {'type': 'python', 'value': 'var_foo == "bar"'}
assert page.is_visible({}, formdef) is True # 'var_foo' is not defined
formdef.fields = [fields.StringField(id='1', label='string', varname='foo')]
assert page.is_visible({}, formdef) is False

View File

@ -463,7 +463,7 @@ def test_form_multi_page(pub):
fields.StringField(id='1', label='string'),
fields.PageField(id='2', label='2nd page', type='page'),
fields.StringField(id='3', label='string 2')]
formdef.fields[0].condition = initial_condition
formdef.fields[0].condition = {'type': 'python', 'value': initial_condition}
formdef.store()
page = get_app(pub).get('/test/')
formdef.data_class().wipe()
@ -489,7 +489,8 @@ def test_form_multi_page_condition(pub):
formdef = create_formdef()
formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
fields.StringField(id='1', label='string'),
fields.PageField(id='2', label='2nd page', type='page', condition='False'),
fields.PageField(id='2', label='2nd page', type='page',
condition={'type': 'python', 'value': 'False'}),
fields.StringField(id='3', label='string 2')]
formdef.store()
resp = get_app(pub).get('/test/')
@ -508,9 +509,9 @@ def test_form_multi_page_condition_select(pub):
required=True,
varname='foo', items=['Foo', 'Bar']),
fields.PageField(id='2', label='2nd page', type='page',
condition='var_foo == "Foo"'),
condition={'type': 'python', 'value': 'var_foo == "Foo"'}),
fields.PageField(id='3', label='3rd page', type='page',
condition='var_foo == "Bar"'),
condition={'type': 'python', 'value': 'var_foo == "Bar"'}),
fields.StringField(id='3', label='string 2')]
formdef.store()
formdef.data_class().wipe()
@ -537,9 +538,9 @@ def test_form_multi_page_condition_select_new_varname(pub):
required=True,
varname='foo', items=['Foo', 'Bar']),
fields.PageField(id='2', label='2nd page', type='page',
condition='form_var_foo == "Foo"'),
condition={'type': 'python', 'value': 'form_var_foo == "Foo"'}),
fields.PageField(id='3', label='3rd page', type='page',
condition='form_var_foo == "Bar"'),
condition={'type': 'python', 'value': 'form_var_foo == "Bar"'}),
fields.StringField(id='3', label='string 2')]
formdef.store()
formdef.data_class().wipe()
@ -564,7 +565,7 @@ def test_form_multi_page_condition_checkbox(pub):
formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
fields.BoolField(id='1', label='checkbox', varname='checkbox'),
fields.PageField(id='2', label='2nd page', type='page',
condition='var_checkbox == "False"'),
condition={'type': 'python', 'value': 'var_checkbox == "False"'}),
fields.StringField(id='3', label='string 2')]
formdef.store()
resp = get_app(pub).get('/test/')
@ -585,10 +586,10 @@ def test_form_multi_page_condition_json_check(pub):
formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
fields.BoolField(id='1', label='checkbox', varname='checkbox'),
fields.PageField(id='2', label='2nd page', type='page',
condition='var_checkbox == "False"'),
condition={'type': 'python', 'value': 'var_checkbox == "False"'}),
fields.StringField(id='3', label='string 2', varname='st2'),
fields.PageField(id='4', label='3rd page', type='page',
condition='var_checkbox == "True"'),
condition={'type': 'python', 'value': 'var_checkbox == "True"'}),
fields.StringField(id='5', label='string 3', varname='st3'),
]
formdef.store()
@ -627,10 +628,10 @@ def test_form_multi_page_condition_no_confirmation_json_check(pub):
formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
fields.BoolField(id='1', label='checkbox', varname='checkbox'),
fields.PageField(id='2', label='2nd page', type='page',
condition='var_checkbox == "False"'),
condition={'type': 'python', 'value': 'var_checkbox == "False"'}),
fields.StringField(id='3', label='string 2', varname='st2'),
fields.PageField(id='4', label='3rd page', type='page',
condition='var_checkbox == "True"'),
condition={'type': 'python', 'value': 'var_checkbox == "True"'}),
fields.StringField(id='5', label='string 3', varname='st3'),
fields.PageField(id='6', label='4th page', type='page'),
fields.CommentField(id='7', label='Check values then click submit.',
@ -670,7 +671,7 @@ def test_form_multi_page_condition_data_source(pub):
formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
fields.BoolField(id='1', label='checkbox', varname='checkbox'),
fields.PageField(id='2', label='2nd page', type='page',
condition='len(data_source.foobar) > 0'),
condition={'type': 'python', 'value': 'len(data_source.foobar) > 0'}),
fields.StringField(id='3', label='string 2')]
formdef.store()
@ -707,7 +708,7 @@ def test_form_multi_page_condition_data_source_with_form_variable(pub):
fields.StringField(id='1', label='string', varname='xxx',
required=False),
fields.PageField(id='2', label='2nd page', type='page',
condition='len(data_source.foobar) > 0'),
condition={'type': 'python', 'value': 'len(data_source.foobar) > 0'}),
fields.StringField(id='3', label='string 2')]
formdef.store()
@ -731,7 +732,9 @@ def test_form_multi_page_condition_data_source_with_form_variable(pub):
def test_form_multi_page_condition_on_first_page(pub):
formdef = create_formdef()
formdef.fields = [fields.PageField(id='0', label='1st page', type='page', condition='False'),
formdef.fields = [
fields.PageField(id='0', label='1st page', type='page',
condition={'type': 'condition', 'value': 'False'}),
fields.StringField(id='1', label='string'),
fields.PageField(id='2', label='2nd page', type='page'),
fields.StringField(id='3', label='string 2')]
@ -752,9 +755,12 @@ def test_form_multi_page_condition_on_first_page(pub):
def test_form_multi_page_condition_no_visible_page(pub):
formdef = create_formdef()
formdef.fields = [fields.PageField(id='0', label='1st page', type='page', condition='False'),
formdef.fields = [
fields.PageField(id='0', label='1st page', type='page',
condition={'type': 'python', 'value': 'False'}),
fields.StringField(id='1', label='string'),
fields.PageField(id='2', label='2nd page', type='page', condition='False'),
fields.PageField(id='2', label='2nd page', type='page',
condition={'type': 'python', 'value': 'False'}),
fields.StringField(id='3', label='string 2')]
formdef.store()
get_app(pub).get('/test/', status=404)
@ -763,7 +769,8 @@ def test_form_multi_page_post_conditions(pub):
formdef = create_formdef()
formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
fields.StringField(id='1', label='string', varname='foo'),
fields.PageField(id='2', label='2nd page', type='page', condition='False'),
fields.PageField(id='2', label='2nd page', type='page',
condition={'type': 'python', 'value': 'False'}),
fields.StringField(id='3', label='string 2'),
fields.PageField(id='4', label='3rd page', type='page'),
fields.StringField(id='5', label='string 3', varname='bar'),
@ -783,7 +790,7 @@ def test_form_multi_page_post_conditions(pub):
assert formdef.data_class().select()[0].data['5'] == 'bar'
formdef.fields[4].post_conditions = [
{'condition': 'False', 'error_message': 'You shall not pass.'},
{'condition': {'type': 'python', 'value': 'False'}, 'error_message': 'You shall not pass.'},
]
formdef.store()
formdef.data_class().wipe()
@ -797,7 +804,7 @@ def test_form_multi_page_post_conditions(pub):
assert 'You shall not pass.' in resp.body
formdef.fields[4].post_conditions = [
{'condition': 'form_var_foo == "foo"', 'error_message': 'You shall not pass.'},
{'condition': {'type': 'python', 'value': 'form_var_foo == "foo"'}, 'error_message': 'You shall not pass.'},
]
formdef.store()
formdef.data_class().wipe()
@ -818,7 +825,7 @@ def test_form_multi_page_post_conditions(pub):
# check a post-condition raising an exception, they should always fail.
formdef.fields[4].post_conditions = [
{'condition': '1/0', 'error_message': 'You shall not pass.'},
{'condition': {'type': 'python', 'value': '1/0'}, 'error_message': 'You shall not pass.'},
]
formdef.store()
formdef.data_class().wipe()
@ -832,7 +839,7 @@ def test_form_multi_page_post_conditions(pub):
# check a post-condition referring to a field on the same page
formdef.fields[4].post_conditions = [
{'condition': 'form_var_bar == "bar"', 'error_message': 'You shall not pass.'},
{'condition': {'type': 'python', 'value': 'form_var_bar == "bar"'}, 'error_message': 'You shall not pass.'},
]
formdef.store()
formdef.data_class().wipe()
@ -1350,7 +1357,7 @@ def test_form_multi_page_formdef_count_condition(pub):
formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
fields.StringField(id='1', label='string'),
fields.PageField(id='2', label='2nd page', type='page',
condition='form_objects.count > 0'),
condition={'type': 'python', 'value': 'form_objects.count > 0'}),
fields.StringField(id='3', label='string 2')]
formdef.store()
@ -1459,7 +1466,7 @@ def test_form_count_dispatching(pub):
workflow = Workflow(name='test')
st1 = workflow.add_status('Status1', 'st1')
jump = JumpWorkflowStatusItem()
jump.condition = 'form_objects.count_status_st2 < 1'
jump.condition = {'type': 'python', 'value': 'form_objects.count_status_st2 < 1'}
jump.status = 'st2'
st1.items.append(jump)
jump.parent = st1
@ -2964,12 +2971,14 @@ def test_form_middle_session_change(pub):
def test_form_autocomplete_variadic_url(pub):
formdef = create_formdef()
formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
fields.PageField(id='3', label='2nd page', type='page', condition="True"),
fields.PageField(id='3', label='2nd page', type='page',
condition={'type': 'python', 'value': 'True'}),
fields.ItemField(id='1', label='string', type='item',
varname='foo', items=['Foo', 'Bar']),
fields.StringField(id='2', label='string2', required=True,
data_source={'type': 'jsonp', 'value': '[var_foo]'}),
fields.PageField(id='4', label='3rd page', type='page', condition="True")
fields.PageField(id='4', label='3rd page', type='page',
condition={'type': 'python', 'value': 'True'})
]
formdef.store()
@ -3842,7 +3851,7 @@ def test_logged_errors(pub):
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
jump.status = 'rejected'
jump.condition = '1/0' # ZeroDivisionError
jump.condition = {'type': 'python', 'value': '1/0'} # ZeroDivisionError
st1 = workflow.possible_status[0]
st1.items.insert(0, jump)
jump.parent = st1

View File

@ -12,7 +12,7 @@ from wcs import formdef
from wcs.formdef import FormDef
from wcs.qommon.http_request import HTTPRequest
from wcs.workflows import Workflow
from wcs.fields import StringField, FileField, DateField, ItemField
from wcs.fields import StringField, FileField, DateField, ItemField, PageField
from utilities import create_temporary_pub, clean_temporary_pub
@ -211,3 +211,19 @@ def test_internal_identifier_migration(pub):
formdef = FormDef.get(formdef.id)
assert formdef.internal_identifier == 'foo'
def test_page_field_migration(pub):
FormDef.wipe()
formdef = FormDef()
formdef.name = 'foo'
formdef.fields = [
PageField(id='1', type='page',
condition='foo',
post_conditions=[{'condition': 'blah', 'error_message': 'blah'}]),
]
formdef.store()
formdef = FormDef.get(formdef.id)
assert formdef.fields[0].condition == {'type': 'python', 'value': 'foo'}
assert formdef.fields[0].post_conditions == [
{'condition': {'type': 'python', 'value': 'blah'},
'error_message': 'blah'}]

View File

@ -320,26 +320,54 @@ def test_wrong_max_field_id():
formdef2 = FormDef.import_from_xml(StringIO.StringIO(export), include_id=True)
assert formdef2.max_field_id == 2
def test_page_condition():
formdef = FormDef()
formdef.name = 'foo'
formdef.fields = [
fields.PageField(id='1', type='page',
condition={'type': 'python', 'value': 'blah'})
]
fd2 = assert_xml_import_export_works(formdef)
assert fd2.fields[0].type == 'page'
assert fd2.fields[0].condition == formdef.fields[0].condition
# test legacy condition (simple string)
formdef_xml = formdef.export_to_xml(include_id=True)
condition = formdef_xml.findall('fields/field/condition')[0]
condition.clear()
condition.text = 'blah'
fd2 = FormDef.import_from_xml_tree(formdef_xml, include_id=True)
assert fd2.fields[0].condition == formdef.fields[0].condition
def test_page_post_conditions():
formdef = FormDef()
formdef.name = 'foo'
formdef.fields = [
fields.PageField(id='1', type='page',
post_conditions=[{'condition': 'blah', 'error_message': 'bar'}]),
post_conditions=[{'condition': {'type': 'python', 'value': 'blah'}, 'error_message': 'bar'}]),
]
fd2 = assert_xml_import_export_works(formdef)
assert fd2.fields[0].type == 'page'
assert fd2.fields[0].post_conditions == formdef.fields[0].post_conditions
# test legacy condition (simple string)
formdef_xml = formdef.export_to_xml(include_id=True)
post_condition = formdef_xml.findall('fields/field/post_conditions/post_condition/condition')[0]
post_condition.clear()
post_condition.text = 'blah'
fd2 = FormDef.import_from_xml_tree(formdef_xml, include_id=True)
assert fd2.fields[0].post_conditions[0]['condition'] == {'type': 'python', 'value': 'blah'}
assert fd2.fields[0].post_conditions[0]['error_message'] == 'bar'
# test incomplete post condition (not allowed anymore but old formdefs may
# have this)
formdef.fields = [
fields.PageField(id='1', type='page',
post_conditions=[{'condition': 'blah', 'error_message': None}]),
post_conditions=[{'condition': {'type': 'python', 'value': 'blah'}, 'error_message': None}]),
]
formdef_xml = formdef.export_to_xml(include_id=True)
fd2 = FormDef.import_from_xml_tree(formdef_xml, include_id=True)
assert fd2.fields[0].post_conditions[0]['condition'] == 'blah'
assert fd2.fields[0].post_conditions[0]['condition'] == {'type': 'python', 'value': 'blah'}
assert fd2.fields[0].post_conditions[0]['error_message'] == ''
def test_workflow_roles():

View File

@ -297,7 +297,7 @@ def test_jump_action(pub):
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
jump.by = ['_submitter', '_receiver']
jump.condition = '"foo"'
jump.condition = {'type': 'python', 'value': '"foo"'}
jump.trigger = 'bar'
jump.timeout = 1200
jump.status = 'st2'
@ -305,10 +305,19 @@ def test_jump_action(pub):
jump.parent = st1
wf2 = assert_import_export_works(wf)
assert wf2.possible_status[0].items[0].condition == '"foo"'
assert wf2.possible_status[0].items[0].condition == {'type': 'python', 'value': '"foo"'}
assert wf2.possible_status[0].items[0].trigger == 'bar'
assert wf2.possible_status[0].items[0].timeout == 1200
# legacy condition value
workflow_xml = wf.export_to_xml(wf)
condition = workflow_xml.findall('possible_status/*/items/item/condition')[0]
condition.clear()
condition.text = '"foo"'
wf2 = Workflow.import_from_xml_tree(workflow_xml)
assert wf2.possible_status[0].items[0].condition == {'type': 'python', 'value': '"foo"'}
def test_commentable_action(pub):
wf = Workflow(name='status')

View File

@ -204,13 +204,13 @@ def test_jump_datetime_condition(pub):
formdata = formdef.data_class()()
item = JumpWorkflowStatusItem()
yesterday = datetime.datetime.now() - datetime.timedelta(days=1)
item.condition = 'datetime.datetime.now() > datetime.datetime(%s, %s, %s)' % \
yesterday.timetuple()[:3]
item.condition = {'type': 'python', 'value': 'datetime.datetime.now() > datetime.datetime(%s, %s, %s)' % \
yesterday.timetuple()[:3]}
assert item.must_jump(formdata) is True
tomorrow = datetime.datetime.now() + datetime.timedelta(days=1)
item.condition = 'datetime.datetime.now() > datetime.datetime(%s, %s, %s)' % \
tomorrow.timetuple()[:3]
item.condition = {'type': 'python', 'value': 'datetime.datetime.now() > datetime.datetime(%s, %s, %s)' % \
tomorrow.timetuple()[:3]}
assert item.must_jump(formdata) is False
def test_jump_date_conditions(pub):
@ -229,23 +229,33 @@ def test_jump_date_conditions(pub):
pub.substitutions.feed(formdata)
item = JumpWorkflowStatusItem()
item.condition = 'utils.make_date(form_var_date) == utils.make_date("2015-01-04")'
item.condition = {
'type': 'python',
'value': 'utils.make_date(form_var_date) == utils.make_date("2015-01-04")'}
assert item.must_jump(formdata) is True
item = JumpWorkflowStatusItem()
item.condition = 'utils.time_delta(form_var_date, "2015-01-04").days == 0'
item.condition = {
'type': 'python',
'value': 'utils.time_delta(form_var_date, "2015-01-04").days == 0'}
assert item.must_jump(formdata) is True
item = JumpWorkflowStatusItem()
item.condition = 'utils.time_delta(utils.today(), "2015-01-04").days > 0'
item.condition = {
'type': 'python',
'value': 'utils.time_delta(utils.today(), "2015-01-04").days > 0'}
assert item.must_jump(formdata) is True
item = JumpWorkflowStatusItem()
item.condition = 'utils.time_delta(datetime.datetime.now(), "2015-01-04").days > 0'
item.condition = {
'type': 'python',
'value': 'utils.time_delta(datetime.datetime.now(), "2015-01-04").days > 0'}
assert item.must_jump(formdata) is True
item = JumpWorkflowStatusItem()
item.condition = 'utils.time_delta(utils.time.localtime(), "2015-01-04").days > 0'
item.condition = {
'type': 'python',
'value': 'utils.time_delta(utils.time.localtime(), "2015-01-04").days > 0'}
assert item.must_jump(formdata) is True
@ -258,14 +268,14 @@ def test_jump_count_condition(pub):
formdef.data_class().wipe()
formdata = formdef.data_class()()
item = JumpWorkflowStatusItem()
item.condition = 'form_objects.count < 2'
item.condition = {'type': 'python', 'value': 'form_objects.count < 2'}
assert item.must_jump(formdata) is True
for i in range(10):
formdata = formdef.data_class()()
formdata.store()
item.condition = 'form_objects.count < 2'
item.condition = {'type': 'python', 'value': 'form_objects.count < 2'}
assert item.must_jump(formdata) is False
def test_check_auth(pub):
@ -3171,3 +3181,22 @@ def test_redirect_to_url(pub):
item.url = '{% if nada %}https://www.example.net/{% endif %}'
pub.substitutions.feed(formdata)
assert item.perform(formdata) == None
def test_workflow_jump_condition_migration(pub):
workflow = Workflow(name='jump condition migration')
st1 = workflow.add_status('Status1', 'st1')
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
st1.items.append(jump)
jump.parent = st1
workflow.store()
reloaded_workflow = Workflow.get(workflow.id)
assert reloaded_workflow.possible_status[0].items[0].condition is None
jump.condition = 'foobar'
workflow.store()
reloaded_workflow = Workflow.get(workflow.id)
assert reloaded_workflow.possible_status[0].items[0].condition == {
'type': 'python', 'value': 'foobar'}

View File

@ -1426,7 +1426,7 @@ class PostConditionsRowWidget(CompositeWidget):
CompositeWidget.__init__(self, name, value, **kwargs)
if not value:
value = {}
self.add(StringWidget, name='condition', title=_('Condition'),
self.add(ConditionWidget, name='condition', title=_('Condition'),
value=value.get('condition'), size=50)
self.add(StringWidget, name='error_message', title=_('Error message if condition is not met'),
value=value.get('error_message'), size=50)
@ -1464,13 +1464,34 @@ class PageField(Field):
condition = None
post_conditions = None
def condition_init_with_xml(self, node, charset, include_id=False):
if node is None:
return
if node.findall('type'):
self.condition = {
'type': node.find('type').text.encode(charset),
'value': node.find('value').text.encode(charset),
}
else:
self.condition = {'type': 'python', 'value': node.text.encode(charset)}
def post_conditions_init_with_xml(self, node, charset, include_id=False):
if node is None:
return
self.post_conditions = []
for post_condition_node in node.findall('post_condition'):
if post_condition_node.findall('condition/type'):
condition = {
'type': post_condition_node.find('condition/type').text.encode(charset),
'value': post_condition_node.find('condition/value').text.encode(charset),
}
else:
condition = {
'type': 'python',
'value': post_condition_node.find('condition').text.encode(charset),
}
self.post_conditions.append({
'condition': post_condition_node.find('condition').text.encode(charset),
'condition': condition,
'error_message': post_condition_node.find('error_message').text.encode(charset),
})
@ -1480,17 +1501,20 @@ class PageField(Field):
conditions_node = ET.SubElement(node, 'post_conditions')
for post_condition in self.post_conditions:
condition_node = ET.SubElement(conditions_node, 'post_condition')
ET.SubElement(condition_node, 'condition').text = unicode(
post_condition['condition'] or '', charset, 'replace')
ET.SubElement(condition_node, 'error_message').text = unicode(
post_condition_node = ET.SubElement(conditions_node, 'post_condition')
condition_node = ET.SubElement(post_condition_node, 'condition')
ET.SubElement(condition_node, 'type').text = unicode(
post_condition['condition'].get('type') or '', charset, 'replace')
ET.SubElement(condition_node, 'value').text = unicode(
post_condition['condition'].get('value') or '', charset, 'replace')
ET.SubElement(post_condition_node, 'error_message').text = unicode(
post_condition['error_message'] or '', charset, 'replace')
def fill_admin_form(self, form):
form.add(StringWidget, 'label', title = _('Label'), value = self.label,
required = True, size = 50)
form.add(StringWidget, 'condition', title = _('Condition'), value = self.condition,
required = False, size = 50)
form.add(ConditionWidget, 'condition', title=_('Condition'), value=self.condition,
required=False, size=50)
form.add(PostConditionsTableWidget, 'post_conditions',
title=_('Post Conditions'),
value=self.post_conditions,
@ -1499,12 +1523,26 @@ class PageField(Field):
def get_admin_attributes(self):
return Field.get_admin_attributes(self) + ['condition', 'post_conditions']
def migrate(self):
changed = super(PageField, self).migrate()
if isinstance(self.condition, basestring):
self.condition = {'type': 'python', 'value': self.condition}
changed = True
for post_condition in self.post_conditions or []:
condition = post_condition.get('condition')
if isinstance(condition, basestring):
post_condition['condition'] = {'type': 'python', 'value': condition}
changed = True
return changed
def add_to_view_form(self, *args):
pass
def evaluate_condition(self, dict_vars, formdef, condition):
if not condition:
return True
if not condition.get('value'):
return True
# create variables with values currently being evaluated, not yet
# available in the formdata.
@ -1528,10 +1566,10 @@ class PageField(Field):
data.update(live_data)
try:
if eval(condition, get_publisher().get_global_eval_dict(), data):
if eval(condition['value'], get_publisher().get_global_eval_dict(), data):
return True
except Exception, e:
get_logger().warn('failed to evaluate condition "%s" (%r)' % (self.condition, e))
get_logger().warn('failed to evaluate condition "%s" (%r)' % (condition['value'], e))
raise RuntimeError()
return False

View File

@ -2275,3 +2275,35 @@ class ComputedExpressionWidget(StringWidget):
self.validate(self.value)
except ValidationError as e:
self.set_error(str(e))
class ConditionWidget(CompositeWidget):
def __init__(self, name, value=None, **kwargs):
CompositeWidget.__init__(self, name, value, **kwargs)
if not value:
value = {}
self.add(HiddenWidget, 'type', value=value.get('type'))
self.add(StringWidget, 'value_python', value=value.get('value'), **kwargs)
def _parse(self, request):
self.value = {}
self.value['type'] = self.get('type') or 'python'
if self.value['type']:
self.value['value'] = self.get('value_%s' % self.value['type'])
if self.value['type'] == 'python' and self.value.get('value'):
try:
compile(self.value.get('value'), '<string>', 'eval')
except (SyntaxError, TypeError), e:
self.set_error(_('invalid expression: %s') % e)
if not self.value['value']:
self.value = None
def render_content(self):
r = TemplateIO(html=True)
for widget in self.get_widgets():
r += widget.render_content()
return r.getvalue()

View File

@ -117,6 +117,25 @@ class JumpWorkflowStatusItem(WorkflowStatusJumpItem):
else:
self.timeout = int(timeout)
def condition_init_with_xml(self, node, charset, include_id=False):
if node is None:
self.condition = None
elif node.findall('type'):
self.condition = {
'type': node.find('type').text.encode(charset),
'value': node.find('value').text.encode(charset),
}
else:
# backward compatibility
self.condition = {'type': 'python', 'value': node.text.encode(charset)}
def migrate(self):
changed = super(JumpWorkflowStatusItem, self).migrate()
if isinstance(self.condition, basestring):
self.condition = {'type': 'python', 'value': self.condition}
changed = True
return changed
@property
def waitpoint(self):
if self.timeout or self.trigger:
@ -150,7 +169,7 @@ class JumpWorkflowStatusItem(WorkflowStatusJumpItem):
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
WorkflowStatusJumpItem.add_parameters_widgets(self, form, parameters, prefix, formdef)
if 'condition' in parameters:
form.add(StringWidget, '%scondition' % prefix, title=_('Condition (formula)'),
form.add(ConditionWidget, '%scondition' % prefix, title=_('Condition (formula)'),
value=self.condition, size=40)
if 'trigger' in parameters:
form.add(StringWidget, '%strigger' % prefix, title=_('Trigger (string)'),
@ -201,7 +220,7 @@ class JumpWorkflowStatusItem(WorkflowStatusJumpItem):
if self.condition:
variables = get_publisher().substitutions.get_context_variables()
try:
must_jump = eval(self.condition, get_publisher().get_global_eval_dict(), variables)
must_jump = eval(self.condition['value'], get_publisher().get_global_eval_dict(), variables)
except:
# get the variables in the locals() namespace so they are
# displayed within the trace.