workflows: do not accept invalid data source value in backoffice fields (#50288) #701

Merged
fpeters merged 1 commits from wip/50288-backoffice-item-field-unknown-value into main 2023-09-29 07:33:03 +02:00
5 changed files with 34 additions and 4 deletions

View File

@ -310,7 +310,7 @@ def test_form_autosave_item_field_data_source_error(pub):
with mock.patch.object(NamedDataSource, 'get_structured_value', lambda *args: None):
autosave_resp = app.post('/test/autosave', params=resp.form.submit_fields())
assert autosave_resp.json == {
'reason': 'form deserialization failed: a datasource is unavailable (field id: 1)',
'reason': 'form deserialization failed: no matching value in datasource (field id: 1, value: \'1\')',
'result': 'error',
}

View File

@ -2147,7 +2147,7 @@ def test_field_live_condition_data_source_error(pub):
with mock.patch.object(NamedDataSource, 'get_structured_value', lambda *args: None):
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
assert live_resp.json == {
'reason': 'form deserialization failed: a datasource is unavailable (field id: 1)',
'reason': 'form deserialization failed: no matching value in datasource (field id: 1, value: \'2\')',
'result': 'error',
}

View File

@ -685,10 +685,28 @@ def test_set_backoffice_field_item(pub):
item.perform(formdata)
formdata = formdef.data_class().get(formdata.id)
assert formdata.data['bo1'] == 'foobar'
assert formdata.data['bo1'] is None
assert formdata.data.get('bo1_display') is None
assert formdata.data.get('bo1_structured') is None
# check with unknown value but no datasource
wf.backoffice_fields_formdef.fields[0].data_source = None
wf.store()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.store()
item = SetBackofficeFieldsWorkflowStatusItem()
item.parent = st1
item.fields = [{'field_id': 'bo1', 'value': 'foobar'}]
item.perform(formdata)
formdata = formdef.data_class().get(formdata.id)
assert formdata.data['bo1'] == 'foobar'
assert formdata.data.get('bo1_display') == 'foobar'
assert formdata.data.get('bo1_structured') is None
def test_set_backoffice_field_card_item(pub):
CardDef.wipe()

View File

@ -2557,6 +2557,18 @@ class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin, ItemWithImageField
widget.extra_css_class = self.extra_css_class
return widget
def set_value(self, data, value, raise_on_error=False):
data_source = data_sources.get_object(self.data_source)
if raise_on_error and value and data_source and data_source.type != 'jsonp':
# check value (this looks up on id only, not text, convert_value_from_anything()
# can be called before if the value may be a text value, as it's done in the
# wf/backoffice_fields.py action.
if not data_source.get_structured_value(value):
raise SetValueError(
'no matching value in datasource (field id: %s, value: %r)' % (self.id, value)
)
super().set_value(data, value, raise_on_error=raise_on_error)
def store_display_value(self, data, field_id, raise_on_error=False):
value = data.get(field_id)
if not value:

View File

@ -187,7 +187,7 @@ class SetBackofficeFieldsWorkflowStatusItem(WorkflowStatusItem):
continue
try:
formdef_field.set_value(formdata.data, new_value)
formdef_field.set_value(formdata.data, new_value, raise_on_error=True)
except SetValueError as e:
summary = _('Failed to set %(kind)s field (%(id)s), error: %(exc)s') % {
'kind': formdef_field.get_type_label(),