blocks: apply prefill to added rows (#50289)
This commit is contained in:
parent
1831aff4b0
commit
86c70cb2a9
|
@ -571,6 +571,101 @@ def test_block_locked_prefill(pub, blocks_feature):
|
|||
assert formdata.data['3']['data'][0]['123'] == 'Hello World' # value got reverted
|
||||
|
||||
|
||||
def test_block_multi_string_prefill(pub):
|
||||
FormDef.wipe()
|
||||
BlockDef.wipe()
|
||||
|
||||
block = BlockDef()
|
||||
block.name = 'foobar'
|
||||
block.fields = [
|
||||
fields.StringField(
|
||||
id='123', required=True, label='Test', type='string',
|
||||
prefill={'type': 'string', 'value': '{{ form_var_foo }} World'}),
|
||||
]
|
||||
block.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'form title'
|
||||
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'),
|
||||
fields.BlockField(id='3', label='test', type='block:foobar', max_items=5),
|
||||
]
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
app = get_app(pub)
|
||||
resp = app.get(formdef.get_url())
|
||||
resp.form['f1'] = 'Hello'
|
||||
resp = resp.form.submit('submit') # -> 2nd page
|
||||
assert not resp.pyquery('#form_error_f3') # not marked as error
|
||||
assert resp.form['f3$element0$f123'].value == 'Hello World'
|
||||
resp = resp.form.submit('f3$add_element') # add second row
|
||||
assert resp.form['f3$element1$f123'].value == 'Hello World'
|
||||
resp.form['f3$element1$f123'].value = 'Something else'
|
||||
resp = resp.form.submit('f3$add_element') # add third row
|
||||
assert resp.form['f3$element0$f123'].value == 'Hello World'
|
||||
assert resp.form['f3$element1$f123'].value == 'Something else' # unchanged
|
||||
assert resp.form['f3$element2$f123'].value == 'Hello World'
|
||||
resp = resp.form.submit('submit') # -> validation page
|
||||
resp = resp.form.submit('submit') # -> end page
|
||||
resp = resp.follow()
|
||||
|
||||
formdata = formdef.data_class().select()[0]
|
||||
assert formdata.data['3']['data'][0]['123'] == 'Hello World'
|
||||
assert formdata.data['3']['data'][1]['123'] == 'Something else'
|
||||
assert formdata.data['3']['data'][2]['123'] == 'Hello World'
|
||||
|
||||
|
||||
def test_block_multi_string_modify_prefill(pub):
|
||||
FormDef.wipe()
|
||||
BlockDef.wipe()
|
||||
|
||||
block = BlockDef()
|
||||
block.name = 'foobar'
|
||||
block.fields = [
|
||||
fields.StringField(
|
||||
id='123', required=True, label='Test', type='string',
|
||||
prefill={'type': 'string', 'value': '{{ form_var_foo }} World'}),
|
||||
]
|
||||
block.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'form title'
|
||||
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'),
|
||||
fields.BlockField(id='3', label='test', type='block:foobar', max_items=5),
|
||||
]
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
app = get_app(pub)
|
||||
|
||||
|
||||
formdef.data_class().wipe()
|
||||
resp = app.get(formdef.get_url())
|
||||
resp.form['f1'] = 'Hello'
|
||||
resp = resp.form.submit('submit') # -> 2nd page
|
||||
assert not resp.pyquery('#form_error_f3') # not marked as error
|
||||
assert resp.form['f3$element0$f123'].value == 'Hello World'
|
||||
resp = resp.form.submit('f3$add_element') # add second row
|
||||
assert resp.form['f3$element1$f123'].value == 'Hello World'
|
||||
resp.form['f3$element1$f123'].value = 'Something else'
|
||||
resp = resp.form.submit('f3$add_element') # add third row
|
||||
assert resp.form['f3$element0$f123'].value == 'Hello World'
|
||||
assert resp.form['f3$element1$f123'].value == 'Something else' # unchanged
|
||||
assert resp.form['f3$element2$f123'].value == 'Hello World'
|
||||
resp = resp.form.submit('previous') # -> 1st page
|
||||
resp.form['f1'] = 'Bye'
|
||||
resp = resp.form.submit('submit') # -> 2nd page
|
||||
assert resp.form['f3$element0$f123'].value == 'Bye World' # updated
|
||||
assert resp.form['f3$element1$f123'].value == 'Something else' # unchanged
|
||||
assert resp.form['f3$element2$f123'].value == 'Bye World' # updated
|
||||
|
||||
|
||||
def test_workflow_form_block_prefill(pub):
|
||||
FormDef.wipe()
|
||||
BlockDef.wipe()
|
||||
|
|
|
@ -327,27 +327,47 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
|
||||
@classmethod
|
||||
def iter_with_block_fields(cls, form, fields):
|
||||
from wcs.blocks import BlockSubWidget
|
||||
for field in fields:
|
||||
field_key = '%s' % field.id
|
||||
widget = form.get_widget('f%s' % field_key) if form else None
|
||||
yield field, field_key, widget, None
|
||||
yield field, field_key, widget, None, None
|
||||
if field.key == 'block':
|
||||
# we only ever prefill the first item
|
||||
subwidget = widget.widgets[0] if widget else None
|
||||
for subfield in field.block.fields:
|
||||
subfield_key = '%s$%s' % (field.id, subfield.id)
|
||||
subfield_widget = subwidget.get_widget('f%s' % subfield.id) if subwidget else None
|
||||
yield subfield, subfield_key, subfield_widget, field
|
||||
# we prefill all items
|
||||
for idx, subwidget in enumerate(
|
||||
[x for x in widget.widgets if isinstance(x, BlockSubWidget)]
|
||||
if widget else []):
|
||||
if not isinstance(subwidget, BlockSubWidget):
|
||||
continue
|
||||
for subfield in field.block.fields:
|
||||
subfield_key = '%s$%s' % (field.id, subfield.id)
|
||||
subfield_widget = subwidget.get_widget('f%s' % subfield.id) if subwidget else None
|
||||
yield subfield, subfield_key, subfield_widget, field, idx
|
||||
|
||||
@classmethod
|
||||
def apply_field_prefills(cls, data, form, displayed_fields):
|
||||
def apply_field_prefills(cls, data, form, displayed_fields, add_button_clicked=False):
|
||||
req = get_request()
|
||||
had_prefill = False
|
||||
for field, field_key, widget, block in cls.iter_with_block_fields(form, displayed_fields):
|
||||
|
||||
if 'prefilling_data' not in data:
|
||||
data['prefilling_data'] = {}
|
||||
prefilling_new_data = data['prefilling_data']
|
||||
prefilling_current_data = copy.copy(prefilling_new_data)
|
||||
|
||||
for field, field_key, widget, block, block_idx in cls.iter_with_block_fields(form, displayed_fields):
|
||||
v = None
|
||||
prefilled = False
|
||||
locked = False
|
||||
|
||||
if add_button_clicked:
|
||||
if not block:
|
||||
# do not replay filling fields that are not part of a block
|
||||
continue
|
||||
if widget and widget.value:
|
||||
# do not alter subwidget values that may not yet have been
|
||||
# "commited" to data when an "add row" button is clicked
|
||||
continue
|
||||
|
||||
if field.prefill:
|
||||
prefill_user = get_request().user
|
||||
if get_request().is_in_backoffice():
|
||||
|
@ -363,7 +383,7 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
has_current_value = False
|
||||
if block:
|
||||
try:
|
||||
current_value = data[block.id]['data'][0][field.id]
|
||||
current_value = data[block.id]['data'][block_idx][field.id]
|
||||
has_current_value = True
|
||||
except (IndexError, KeyError, TypeError, ValueError):
|
||||
pass
|
||||
|
@ -379,7 +399,7 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
# if it's the same that was previously computed.
|
||||
prefill_value = v
|
||||
v = current_value
|
||||
if data.get('prefilling_data', {}).get(field_key) == current_value:
|
||||
if prefilling_current_data.get(field_key) == current_value:
|
||||
# replace value with new value computed for prefill
|
||||
v = prefill_value
|
||||
else:
|
||||
|
@ -409,9 +429,7 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
# store computed value, it will be used to compare with
|
||||
# submitted value if page is visited again.
|
||||
if should_prefill:
|
||||
if 'prefilling_data' not in data:
|
||||
data['prefilling_data'] = {}
|
||||
data['prefilling_data'][field_key] = v
|
||||
prefilling_new_data[field_key] = v
|
||||
if not isinstance(v, str) and field.convert_value_to_str:
|
||||
v = field.convert_value_to_str(v)
|
||||
widget.set_value(v)
|
||||
|
@ -498,14 +516,17 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
form.add_submit('previous', _('Previous'))
|
||||
|
||||
had_prefill = False
|
||||
if page_change:
|
||||
# on page change, we fake a GET request so the form is not altered
|
||||
# with errors from the previous submit; if the page was already
|
||||
if page_change or submit_button is True:
|
||||
# on page change (or when a "add row" button is clicked), we
|
||||
# fake a GET request so the form is not altered# with errors
|
||||
# from the previous submit; if the page was already
|
||||
# visited, we restore values; otherwise we set req.form as empty.
|
||||
req = get_request()
|
||||
req.environ['REQUEST_METHOD'] = 'GET'
|
||||
|
||||
had_prefill = self.apply_field_prefills(data, form, displayed_fields)
|
||||
had_prefill = self.apply_field_prefills(data, form,
|
||||
displayed_fields,
|
||||
add_button_clicked=bool(submit_button is True))
|
||||
|
||||
if had_prefill:
|
||||
# include prefilled data
|
||||
|
@ -520,12 +541,12 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
else:
|
||||
# not a page change, reset_locked_data() will have been called
|
||||
# earlier, we use that to set appropriate fields as readonly.
|
||||
for field, field_key, widget, block in self.iter_with_block_fields(form, displayed_fields):
|
||||
for field, field_key, widget, block, block_idx in self.iter_with_block_fields(form, displayed_fields):
|
||||
if get_request().form.get('__locked_f%s' % field_key):
|
||||
widget.readonly = 'readonly'
|
||||
widget.attrs['readonly'] = 'readonly'
|
||||
|
||||
for field, field_key, widget, block in self.iter_with_block_fields(form, displayed_fields):
|
||||
for field, field_key, widget, block, block_idx in self.iter_with_block_fields(form, displayed_fields):
|
||||
if field.prefill:
|
||||
# always set additional attributes as they will be used for
|
||||
# "live prefill", regardless of existing data.
|
||||
|
@ -537,7 +558,7 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
# pass over prefilled fields that are used as live source of item
|
||||
# fields
|
||||
fields_to_update = set()
|
||||
for field, field_key, widget, block in self.iter_with_block_fields(form, displayed_fields):
|
||||
for field, field_key, widget, block, block_idx in self.iter_with_block_fields(form, displayed_fields):
|
||||
if getattr(widget, 'prefilled', False) and getattr(widget, 'live_condition_source', False):
|
||||
fields_to_update.update(widget.live_condition_fields)
|
||||
elif field in fields_to_update and field.type == 'item':
|
||||
|
@ -1121,12 +1142,12 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
prefill_user = get_request().user
|
||||
if get_request().is_in_backoffice():
|
||||
prefill_user = get_publisher().substitutions.get_context_variables().get('form_user')
|
||||
for field, field_key, widget, block in self.iter_with_block_fields(form, self.formdef.fields):
|
||||
for field, field_key, widget, block, block_idx in self.iter_with_block_fields(form, self.formdef.fields):
|
||||
if not field.prefill:
|
||||
continue
|
||||
post_key = 'f%s' % field_key
|
||||
if block:
|
||||
post_key = 'f%s$element0$f%s' % (block.id, field.id)
|
||||
post_key = 'f%s$element%s$f%s' % (block.id, block_idx, field.id)
|
||||
if post_key not in get_request().form:
|
||||
continue
|
||||
v, locked = field.get_prefill_value(user=prefill_user)
|
||||
|
|
Loading…
Reference in New Issue