Projet

Général

Profil

0001-formdef-do-not-load-data-from-item-s-widgets-with-er.patch

Benjamin Dauvergne, 26 octobre 2021 20:58

Télécharger (4,52 ko)

Voir les différences:

Subject: [PATCH] formdef: do not load data from item's widgets with errors
 (#58207)

 tests/form_pages/test_all.py | 71 ++++++++++++++++++++++++++++++++++++
 wcs/formdef.py               |  9 ++++-
 2 files changed, 78 insertions(+), 2 deletions(-)
tests/form_pages/test_all.py
7987 7987
    # and persist after being saved again
7988 7988
    resp = resp.form.submit('submit').follow()
7989 7989
    assert '<span>test.txt</span>' in resp.text
7990

  
7991

  
7992
def test_autosave_and_datasource_failure(mocker, pub, settings):
7993
    values = [
7994
        {'id': '1', 'text': 'item 1', 'foo': 'bar'},
7995
        {'id': '2', 'text': 'item 2', 'bar': 'foo'},
7996
    ]
7997

  
7998
    _get_structured_items_mock = mocker.patch('wcs.data_sources._get_structured_items')
7999
    _get_structured_items_mock.return_value = values
8000
    get_value_by_id_mock = mocker.patch('wcs.data_sources.NamedDataSource.get_value_by_id')
8001
    get_value_by_id_mock.return_value = values[0]
8002

  
8003
    create_user(pub)
8004

  
8005
    NamedDataSource.wipe()
8006
    data_source = NamedDataSource(name='foobar')
8007
    data_source.data_source = {'type': 'json', 'value': 'http://remote.example.net/json'}
8008
    data_source.query_parameter = 'q'
8009
    data_source.id_parameter = 'id'
8010
    data_source.store()
8011

  
8012
    formdef = create_formdef()
8013
    formdef.data_class().wipe()
8014

  
8015
    formdef.fields = [
8016
        fields.PageField(id='0', label='1st page', type='page'),
8017
        fields.ItemField(
8018
            id='1',
8019
            label='string',
8020
            type='item',
8021
            data_source={'type': 'foobar'},
8022
        ),
8023
        fields.StringField(id='2', label='string', required=False),
8024
        fields.PageField(id='3', label='2nd page', type='page'),
8025
        fields.StringField(id='4', label='string', required=False),
8026
    ]
8027
    formdef.store()
8028

  
8029
    app = get_app(pub)
8030
    login(app, username='foo', password='foo')
8031

  
8032
    resp = app.get('/test/')
8033
    # select item 1
8034
    resp.form['f1'].force_value('1')
8035
    # prevent nothing to save during autosave
8036
    resp.form['f2'].force_value('foobar')
8037
    # save data for asynchronous autosave
8038
    autosave_data = resp.form.submit_fields()
8039
    # submit first page
8040
    resp = resp.form.submit('submit')  # -> next page
8041

  
8042
    # simulate a still valid _ajax_form_token
8043
    valid_ajax_form_token = resp.form['_ajax_form_token'].value
8044
    autosave_data = [
8045
        (k, v) if k != '_ajax_form_token' else (k, valid_ajax_form_token) for k, v in autosave_data
8046
    ]
8047

  
8048
    # simulate data source failure
8049
    _get_structured_items_mock.return_value = []
8050
    resp_autosave = app.post('/test/autosave', params=autosave_data)
8051
    _get_structured_items_mock.return_value = values
8052
    assert resp_autosave.json == {'result': 'success'}
8053

  
8054
    # submit second page
8055
    resp = resp.form.submit('submit')  # -> validation page
8056
    # validate
8057
    resp = resp.form.submit('submit')  # -> submit
8058

  
8059
    data = formdef.data_class().select()[0].data
8060
    assert '1' not in data or (data['1'] is not None and data['1_display'] is not None)
wcs/formdef.py
39 39
from .qommon import PICKLE_KWARGS, _, force_str, get_cfg
40 40
from .qommon.admin.emails import EmailsDirectory
41 41
from .qommon.cron import CronJob
42
from .qommon.form import Form, HtmlWidget, UploadedFile
42
from .qommon.form import Form, HtmlWidget, UploadedFile, Widget
43 43
from .qommon.misc import JSONEncoder, get_as_datetime, simplify, xml_node_text
44 44
from .qommon.publisher import get_publisher_class
45 45
from .qommon.storage import Equal, NotEqual, StorableObject, fix_key
......
808 808
    @classmethod
809 809
    def get_field_data(cls, field, widget):
810 810
        d = {}
811
        d[field.id] = widget.parse()
811
        value = widget.parse()
812
        # ignore temporarily invalid value from item(s) fields
813
        if field.key in ['item', 'items'] and not value and widget.has_error() and Widget.parse(widget):
814
            return {}
815

  
816
        d[field.id] = value
812 817
        if d.get(field.id) is not None and field.convert_value_from_str:
813 818
            d[field.id] = field.convert_value_from_str(d[field.id])
814 819
        field.set_value(d, d[field.id])
815
-