This commit is contained in:
parent
26668ba3ea
commit
0abc13aab0
|
@ -2881,3 +2881,108 @@ def test_block_multiple_rows_single_draft(pub, logged_user, tracking_code):
|
|||
|
||||
assert formdef.data_class().count() == 1
|
||||
assert formdef.data_class().select()[0].status == 'wf-new'
|
||||
|
||||
|
||||
def test_block_field_post_condition(pub):
|
||||
FormDef.wipe()
|
||||
BlockDef.wipe()
|
||||
|
||||
block = BlockDef()
|
||||
block.name = 'foobar'
|
||||
block.fields = [
|
||||
fields.StringField(id='123', label='Foo', varname='foo'),
|
||||
fields.StringField(id='234', label='Bar', varname='bar'),
|
||||
]
|
||||
block.post_conditions = [
|
||||
{
|
||||
'condition': {'type': 'django', 'value': 'block_var_foo|startswith:"b"'},
|
||||
'error_message': 'foo must start with a b.',
|
||||
},
|
||||
{
|
||||
'condition': {'type': 'django', 'value': 'block_var_foo == block_var_bar'},
|
||||
'error_message': 'foo and bar must be identical.',
|
||||
},
|
||||
]
|
||||
|
||||
block.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'form title'
|
||||
formdef.fields = [
|
||||
fields.BlockField(id='1', label='test', block_slug='foobar'),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
app = get_app(pub)
|
||||
resp = app.get(formdef.get_url())
|
||||
resp.form['f1$element0$f123'] = 'foo'
|
||||
resp.form['f1$element0$f234'] = 'bar'
|
||||
resp = resp.form.submit('submit') # -> error
|
||||
assert (
|
||||
resp.pyquery('.widget-with-error .error').text()
|
||||
== 'foo must start with a b. foo and bar must be identical.'
|
||||
)
|
||||
|
||||
resp.form['f1$element0$f123'] = 'baz'
|
||||
resp.form['f1$element0$f234'] = 'bar'
|
||||
resp = resp.form.submit('submit') # -> error
|
||||
assert resp.pyquery('.widget-with-error .error').text() == 'foo and bar must be identical.'
|
||||
|
||||
resp.form['f1$element0$f123'] = 'baz'
|
||||
resp.form['f1$element0$f234'] = 'baz'
|
||||
resp = resp.form.submit('submit') # -> validation page
|
||||
|
||||
assert resp.form['f1$element0$f123'].attrs['readonly']
|
||||
resp = resp.form.submit('submit') # -> end page
|
||||
|
||||
formdata = formdef.data_class().select()[0]
|
||||
assert formdata.status == 'wf-new'
|
||||
assert formdata.data == {
|
||||
'1': {'data': [{'123': 'baz', '234': 'baz'}], 'schema': {'123': 'string', '234': 'string'}},
|
||||
'1_display': 'foobar',
|
||||
}
|
||||
|
||||
# multiple rows
|
||||
formdef.fields[0].max_items = 3
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
resp = app.get(formdef.get_url())
|
||||
resp.form['f1$element0$f123'] = 'baz'
|
||||
resp.form['f1$element0$f234'] = 'bar'
|
||||
resp = resp.form.submit('f1$add_element')
|
||||
assert not resp.pyquery('.widget-with-error')
|
||||
|
||||
resp.form['f1$element1$f123'] = 'bar'
|
||||
resp.form['f1$element1$f234'] = 'bar'
|
||||
resp = resp.form.submit('submit') # -> error
|
||||
assert (
|
||||
resp.pyquery('.widget-with-error[data-block-row="element0"] .error').text()
|
||||
== 'foo and bar must be identical.'
|
||||
)
|
||||
assert resp.pyquery('.widget-with-error[data-block-row="element1"] .error').text() == ''
|
||||
|
||||
resp.form['f1$element1$f234'] = 'baz'
|
||||
resp = resp.form.submit('submit') # -> error
|
||||
assert (
|
||||
resp.pyquery('.widget-with-error[data-block-row="element0"] .error').text()
|
||||
== 'foo and bar must be identical.'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('.widget-with-error[data-block-row="element1"] .error').text()
|
||||
== 'foo and bar must be identical.'
|
||||
)
|
||||
|
||||
resp.form['f1$element0$f123'] = 'bar'
|
||||
resp.form['f1$element1$f234'] = 'bar'
|
||||
resp = resp.form.submit('submit') # -> validation page
|
||||
assert resp.form['f1$element0$f123'].attrs['readonly']
|
||||
resp = resp.form.submit('submit') # -> end page
|
||||
formdata = formdef.data_class().select()[0]
|
||||
assert formdata.status == 'wf-new'
|
||||
assert formdata.data == {
|
||||
'1': {
|
||||
'data': [{'123': 'bar', '234': 'bar'}, {'123': 'bar', '234': 'bar'}],
|
||||
'schema': {'123': 'string', '234': 'string'},
|
||||
},
|
||||
'1_display': 'foobar, foobar',
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ from contextlib import contextmanager
|
|||
from quixote import get_publisher, get_request, get_response
|
||||
from quixote.html import htmltag, htmltext
|
||||
|
||||
from . import data_sources, fields
|
||||
from . import conditions, data_sources, fields
|
||||
from .categories import BlockCategory
|
||||
from .formdata import FormData
|
||||
from .qommon import _, misc
|
||||
|
@ -455,6 +455,22 @@ class BlockSubWidget(CompositeWidget):
|
|||
all_lists = False
|
||||
if widget_value.get(widget.field.id) not in empty_values:
|
||||
empty = False
|
||||
|
||||
if not empty and self.block.post_conditions:
|
||||
error_messages = []
|
||||
with self.block.visibility_context(value, self.index):
|
||||
for i, post_condition in enumerate(self.block.post_conditions):
|
||||
condition = post_condition.get('condition')
|
||||
try:
|
||||
if conditions.Condition(condition, record_errors=False).evaluate():
|
||||
continue
|
||||
except RuntimeError:
|
||||
pass
|
||||
error_message = post_condition.get('error_message')
|
||||
error_messages.append(get_publisher().translate(error_message))
|
||||
if error_messages:
|
||||
self.set_error(' '.join(error_messages))
|
||||
|
||||
if empty and not all_lists and not get_publisher().keep_all_block_rows_mode:
|
||||
value = None
|
||||
for widget in self.get_widgets(): # reset "required" errors
|
||||
|
@ -559,6 +575,10 @@ class BlockWidget(WidgetList):
|
|||
self._parse(request)
|
||||
if self.required and self.value is None:
|
||||
self.set_error(_(self.REQUIRED_ERROR))
|
||||
for widget in self.widgets:
|
||||
# mark required rows with a special attribute, to avoid doubling the
|
||||
# error messages in the template.
|
||||
widget.is_required_error = bool(widget.error == self.REQUIRED_ERROR)
|
||||
return self.value
|
||||
|
||||
def add_media(self):
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block widget-content %}
|
||||
{% if not widget.readonly and widget.error and not widget.is_required_error %}<div class="error"><p>{{ widget.error }}</p></div>{% endif %}
|
||||
{% for subwidget in widget.get_widgets %}
|
||||
{% if widget.readonly and not subwidget.field.include_in_validation_page %}<div style="display: none">{% endif %}
|
||||
{{ subwidget.render|safe }}
|
||||
|
|
Loading…
Reference in New Issue