1924 lines
72 KiB
Python
1924 lines
72 KiB
Python
import datetime
|
|
import io
|
|
import itertools
|
|
import json
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
from webtest import Checkbox, Hidden
|
|
|
|
from wcs import fields
|
|
from wcs.blocks import BlockDef
|
|
from wcs.carddef import CardDef
|
|
from wcs.data_sources import NamedDataSource
|
|
from wcs.formdef import FormDef
|
|
from wcs.wf.form import WorkflowFormFieldsFormDef
|
|
from wcs.workflows import Workflow
|
|
|
|
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
|
|
from .test_all import create_user
|
|
|
|
|
|
def pytest_generate_tests(metafunc):
|
|
if 'pub' in metafunc.fixturenames:
|
|
metafunc.parametrize('pub', ['sql', 'sql-lazy'], indirect=True)
|
|
|
|
|
|
@pytest.fixture
|
|
def pub(request):
|
|
pub = create_temporary_pub(
|
|
lazy_mode=bool('lazy' in request.param),
|
|
)
|
|
pub.cfg['identification'] = {'methods': ['password']}
|
|
pub.cfg['language'] = {'language': 'en'}
|
|
pub.write_cfg()
|
|
|
|
return pub
|
|
|
|
|
|
def teardown_module(module):
|
|
clean_temporary_pub()
|
|
|
|
|
|
def test_field_live_condition(pub):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='1', label='Bar', size='40', required=True, varname='bar'),
|
|
fields.StringField(
|
|
type='string',
|
|
id='2',
|
|
label='Foo',
|
|
size='40',
|
|
required=True,
|
|
varname='foo',
|
|
condition={'type': 'django', 'value': 'form_var_bar == "bye"'},
|
|
),
|
|
]
|
|
formdef.store()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none'
|
|
resp.form['f1'] = 'hello'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert not live_resp.json['result']['2']['visible']
|
|
resp.form['f1'] = 'bye'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert live_resp.json['result']['2']['visible']
|
|
resp.form['f1'] = 'hello'
|
|
resp = resp.form.submit('submit')
|
|
assert 'Check values then click submit.' in resp.text
|
|
assert 'name="f1"' in resp.text
|
|
assert 'name="f2"' not in resp.text
|
|
resp = resp.form.submit('submit')
|
|
resp = resp.follow()
|
|
assert '<span class="label">Bar</span>' in resp.text
|
|
assert '<span class="label">Foo</span>' not in resp.text
|
|
|
|
resp = get_app(pub).get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
resp.form['f1'] = 'bye'
|
|
resp = resp.form.submit('submit')
|
|
assert 'There were errors' in resp.text
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') is None
|
|
resp.form['f2'] = 'bye'
|
|
resp = resp.form.submit('submit')
|
|
assert 'Check values then click submit.' in resp.text
|
|
assert 'name="f1"' in resp.text
|
|
assert 'name="f2"' in resp.text
|
|
resp = resp.form.submit('submit')
|
|
resp = resp.follow()
|
|
assert '<span class="label">Bar</span>' in resp.text
|
|
assert '<span class="label">Foo</span>' in resp.text
|
|
|
|
|
|
def test_field_live_items_condition(pub):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.ItemsField(type='items', id='1', label='Bar', items=['a', 'b'], varname='bar'),
|
|
fields.StringField(
|
|
type='string',
|
|
id='2',
|
|
label='Foo',
|
|
size='40',
|
|
required=True,
|
|
varname='foo',
|
|
condition={'type': 'django', 'value': '"b" in form_var_bar'},
|
|
),
|
|
]
|
|
formdef.store()
|
|
|
|
create_user(pub)
|
|
app = login(get_app(pub), username='foo', password='foo')
|
|
resp = app.get('/foo/')
|
|
assert 'f1$element0' in resp.form.fields
|
|
assert 'f1$element1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none'
|
|
resp.form['f1$element0'].checked = True
|
|
app.post('/foo/autosave', params=resp.form.submit_fields())
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert not live_resp.json['result']['2']['visible']
|
|
resp.form['f1$element1'].checked = True
|
|
app.post('/foo/autosave', params=resp.form.submit_fields())
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert live_resp.json['result']['2']['visible']
|
|
resp.form['f1$element0'].checked = False
|
|
resp.form['f1$element1'].checked = False
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert not live_resp.json['result']['2']['visible']
|
|
|
|
|
|
def test_live_field_condition_on_required_field(pub):
|
|
# from https://dev.entrouvert.org/issues/27247
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.PageField(id='0', label='1st page', type='page'),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='1',
|
|
label='Bar',
|
|
items=['oui', 'non'],
|
|
display_mode='radio',
|
|
required=True,
|
|
varname='bar',
|
|
),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='2',
|
|
label='Foo',
|
|
size='40',
|
|
required=True,
|
|
hint='---',
|
|
items=['plop'],
|
|
condition={'type': 'django', 'value': 'form_var_bar == "oui"'},
|
|
),
|
|
fields.PageField(
|
|
id='3', label='1st page', type='page', condition={'type': 'python', 'value': 'True'}
|
|
),
|
|
fields.CommentField(type='comment', id='4', label='HELLO!'),
|
|
]
|
|
formdef.store()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none'
|
|
resp.form['f1'] = 'non'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert not live_resp.json['result']['2']['visible']
|
|
resp = resp.form.submit('submit')
|
|
assert 'HELLO' in resp.text
|
|
resp = resp.form.submit('previous')
|
|
resp.form['f1'] = 'oui'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert live_resp.json['result']['2']['visible']
|
|
resp = resp.form.submit('submit')
|
|
assert resp.pyquery('div.error').text() == 'required field'
|
|
assert 'HELLO' not in resp.text
|
|
|
|
|
|
def test_field_live_condition_multipages(pub):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.PageField(id='0', label='2nd page', type='page'),
|
|
fields.StringField(type='string', id='1', label='Bar', size='40', required=True, varname='bar'),
|
|
fields.StringField(
|
|
type='string',
|
|
id='2',
|
|
label='Foo',
|
|
size='40',
|
|
required=True,
|
|
varname='foo',
|
|
condition={'type': 'django', 'value': 'form_var_bar == "bye"'},
|
|
),
|
|
fields.PageField(id='3', label='1st page', type='page'),
|
|
fields.StringField(type='string', id='4', label='Baz', size='40', required=True, varname='baz'),
|
|
]
|
|
formdef.store()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none'
|
|
resp.form['f1'] = 'hello'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert not live_resp.json['result']['2']['visible']
|
|
resp.form['f1'] = 'bye'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert live_resp.json['result']['2']['visible']
|
|
resp.form['f1'] = 'bye'
|
|
resp.form['f2'] = 'bye'
|
|
resp = resp.form.submit('submit')
|
|
resp = resp.form.submit('previous')
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') is None
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert live_resp.json['result']['2']['visible']
|
|
resp = resp.form.submit('submit')
|
|
resp.form['f4'] = 'plop'
|
|
resp = resp.form.submit('submit')
|
|
assert 'Check values then click submit.' in resp.text
|
|
assert 'name="f1"' in resp.text
|
|
assert 'name="f2"' in resp.text
|
|
assert 'name="f4"' in resp.text
|
|
resp = resp.form.submit('submit')
|
|
|
|
|
|
def test_field_live_select_content(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='1', label='Bar', size='40', required=True, varname='bar'),
|
|
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='3',
|
|
label='Foo',
|
|
data_source={
|
|
'type': 'json',
|
|
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list?plop={{form_var_bar2}}{% endif %}',
|
|
},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '3'}).find('select')
|
|
resp.form['f1'] = 'hello'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert live_resp.json['result']['2']['visible']
|
|
assert live_resp.json['result']['3']['visible']
|
|
assert 'items' not in live_resp.json['result']['3']
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert live_resp.json['result']['2']['visible']
|
|
assert live_resp.json['result']['3']['visible']
|
|
assert 'items' in live_resp.json['result']['3']
|
|
resp.form['f3'].options = []
|
|
for item in live_resp.json['result']['3']['items']:
|
|
# simulate javascript filling the <select>
|
|
resp.form['f3'].options.append((item['id'], False, item['text']))
|
|
resp.form['f3'] = 'a'
|
|
resp = resp.form.submit('submit')
|
|
assert 'Check values then click submit.' in resp.text
|
|
assert 'name="f1"' in resp.text
|
|
assert 'name="f2"' in resp.text
|
|
assert 'name="f3"' in resp.text
|
|
resp = resp.form.submit('submit')
|
|
resp = resp.follow()
|
|
formdata = formdef.data_class().select()[0]
|
|
assert formdata.data['1'] == 'hello'
|
|
assert formdata.data['2'] == 'plop'
|
|
assert formdata.data['3'] == 'a'
|
|
assert formdata.data['3_display'] == 'b'
|
|
|
|
# create and use geojson datasource
|
|
NamedDataSource.wipe()
|
|
data_source = NamedDataSource(name='geofoobar')
|
|
data_source.data_source = {
|
|
'type': 'geojson',
|
|
'value': 'http://remote.example.net/geojson?plop={{form_var_bar2}}',
|
|
}
|
|
data_source.id_property = 'id'
|
|
data_source.label_template_property = '{{ text }}'
|
|
data_source.cache_duration = '5'
|
|
data_source.store()
|
|
formdef.fields[2].data_source = {'type': 'geofoobar'}
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '3'}).find('select')
|
|
resp.form['f1'] = 'hello'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert live_resp.json['result']['2']['visible']
|
|
assert live_resp.json['result']['3']['visible']
|
|
assert 'items' not in live_resp.json['result']['3']
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['1']['visible']
|
|
assert live_resp.json['result']['2']['visible']
|
|
assert live_resp.json['result']['3']['visible']
|
|
assert 'items' in live_resp.json['result']['3']
|
|
resp.form['f3'].options = []
|
|
for item in live_resp.json['result']['3']['items']:
|
|
# simulate javascript filling the <select>
|
|
resp.form['f3'].options.append((item['id'], False, item['text']))
|
|
resp.form['f3'] = '1'
|
|
resp = resp.form.submit('submit')
|
|
assert 'Check values then click submit.' in resp.text
|
|
assert 'name="f1"' in resp.text
|
|
assert 'name="f2"' in resp.text
|
|
assert 'name="f3"' in resp.text
|
|
resp = resp.form.submit('submit')
|
|
resp = resp.follow()
|
|
formdata = formdef.data_class().select()[0]
|
|
assert formdata.data['1'] == 'hello'
|
|
assert formdata.data['2'] == 'plop'
|
|
assert formdata.data['3'] == '1'
|
|
assert formdata.data['3_display'] == 'foo'
|
|
|
|
|
|
def test_field_live_select_content_on_workflow_form(pub, http_requests):
|
|
create_user(pub)
|
|
wf = Workflow(name='wf-title')
|
|
st1 = wf.add_status('Status1', 'st1')
|
|
|
|
# form displayed into the workflow
|
|
display_form = st1.add_action('form', id='_x')
|
|
display_form.by = ['_submitter']
|
|
display_form.varname = 'xxx'
|
|
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
|
|
display_form.formdef.fields = [
|
|
fields.StringField(type='string', id='1', label='Bar', size='40', required=True, varname='bar'),
|
|
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='3',
|
|
label='Foo',
|
|
required=False,
|
|
varname='foo',
|
|
data_source={
|
|
'type': 'json',
|
|
'value': '{% if xxx_var_bar2 %}http://remote.example.net/json-list?plop={{xxx_var_bar2}}{% endif %}',
|
|
},
|
|
),
|
|
]
|
|
wf.store()
|
|
|
|
# initial empty form
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'test'
|
|
formdef.fields = []
|
|
formdef.confirmation = False
|
|
formdef.workflow_id = wf.id
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = login(app, username='foo', password='foo').get('/test/')
|
|
assert 'Forms - test' in resp.text
|
|
|
|
resp = resp.form.submit('submit').follow()
|
|
assert 'The form has been recorded' in resp.text
|
|
|
|
assert 'data-live-url' in resp.html.find('form').attrs
|
|
assert 'fxxx_1' in resp.form.fields
|
|
assert 'fxxx_2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': 'xxx_2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': 'xxx_3'}).find('select')
|
|
resp = resp.form.submit('submit') # submit with error, to check <form> attributes
|
|
assert 'data-live-url' in resp.html.find('form').attrs
|
|
assert 'fxxx_1' in resp.form.fields
|
|
assert 'fxxx_2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': 'xxx_2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': 'xxx_3'}).find('select')
|
|
resp.form['fxxx_1'] = 'hello'
|
|
live_resp = app.post('/test/1/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['xxx_1']['visible']
|
|
assert live_resp.json['result']['xxx_2']['visible']
|
|
assert live_resp.json['result']['xxx_3']['visible']
|
|
assert 'items' not in live_resp.json['result']['xxx_3']
|
|
resp.form['fxxx_2'] = 'plop'
|
|
live_resp = app.post('/test/1/live?modified_field_id=xxx_2', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['xxx_1']['visible']
|
|
assert live_resp.json['result']['xxx_2']['visible']
|
|
assert live_resp.json['result']['xxx_3']['visible']
|
|
assert 'items' in live_resp.json['result']['xxx_3']
|
|
assert len(live_resp.json['result']['xxx_3']['items']) > 0
|
|
|
|
resp.form['fxxx_3'].options = []
|
|
for item in live_resp.json['result']['xxx_3']['items']:
|
|
# simulate javascript filling the <select>
|
|
resp.form['fxxx_3'].options.append((item['id'], False, item['text']))
|
|
resp.form['fxxx_3'] = 'a'
|
|
|
|
resp = resp.form.submit('submit')
|
|
assert 'invalid value selected' not in resp
|
|
resp = resp.follow()
|
|
formdata = formdef.data_class().select()[0]
|
|
assert formdata.workflow_data['xxx_var_bar'] == 'hello'
|
|
assert formdata.workflow_data['xxx_var_bar2'] == 'plop'
|
|
assert formdata.workflow_data['xxx_var_foo_raw'] == 'a'
|
|
assert formdata.workflow_data['xxx_var_foo'] == 'b'
|
|
|
|
|
|
def test_field_live_select_content_based_on_prefill(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(
|
|
type='string',
|
|
id='1',
|
|
label='Bar',
|
|
size='40',
|
|
required=True,
|
|
varname='bar',
|
|
prefill={'type': 'string', 'value': 'HELLO WORLD'},
|
|
),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='2',
|
|
label='Foo',
|
|
data_source={
|
|
'type': 'json',
|
|
'value': '{% if form_var_bar %}http://remote.example.net/json-list?plop={{form_var_bar}}{% endif %}',
|
|
},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '2'}).find('select')
|
|
assert resp.html.find('option', {'value': 'a'})
|
|
assert http_requests.get_last('url') == 'http://remote.example.net/json-list?plop=HELLO WORLD'
|
|
|
|
# check with autocomplete and a remote source with id
|
|
NamedDataSource.wipe()
|
|
data_source = NamedDataSource(name='foobar')
|
|
data_source.data_source = {
|
|
'type': 'json',
|
|
'value': 'http://remote.example.net/json?plop={{form_var_bar}}',
|
|
}
|
|
data_source.query_parameter = 'q'
|
|
data_source.id_parameter = 'id'
|
|
data_source.store()
|
|
|
|
formdef.fields[1].display_mode = 'autocomplete'
|
|
formdef.fields[1].data_source['type'] = 'foobar'
|
|
formdef.store()
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
|
|
|
|
def test_field_live_select_content_on_other_default_select_option(pub, http_requests):
|
|
create_user(pub)
|
|
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.ItemField(
|
|
type='item',
|
|
id='2',
|
|
label='Foo',
|
|
varname='bar2',
|
|
data_source={'type': 'json', 'value': 'http://remote.example.net/json-list'},
|
|
),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='3',
|
|
label='Foo',
|
|
data_source={
|
|
'type': 'json',
|
|
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list?plop={{form_var_bar2}}{% endif %}',
|
|
},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f2' in resp.form.fields
|
|
assert 'f3' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '3'}).find('select')
|
|
# javascript will make an initial call with ?modified_dield_id=init,
|
|
# simulate.
|
|
live_resp = app.post('/foo/live?modified_field_id=init', params=resp.form.submit_fields())
|
|
assert 'items' in live_resp.json['result']['3']
|
|
resp.form['f3'].options = []
|
|
for item in live_resp.json['result']['3']['items']:
|
|
# simulate javascript filling the <select>
|
|
resp.form['f3'].options.append((item['id'], False, item['text']))
|
|
resp.form['f3'] = 'a'
|
|
resp = resp.form.submit('submit')
|
|
assert 'Check values then click submit.' in resp.text
|
|
assert 'name="f2"' in resp.text
|
|
assert 'name="f3"' in resp.text
|
|
resp = resp.form.submit('submit')
|
|
resp = resp.follow()
|
|
formdata = formdef.data_class().select()[0]
|
|
assert formdata.data['2'] == 'a'
|
|
assert formdata.data['3'] == 'a'
|
|
|
|
|
|
def test_field_live_select(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='3',
|
|
label='Foo',
|
|
data_source={
|
|
'type': 'json',
|
|
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list-extra-with-disabled?plop={{form_var_bar2}}{% endif %}',
|
|
},
|
|
display_disabled_items=True,
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '3'}).find('select')
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['3']['items']) == 2
|
|
assert live_resp.json['result']['3']['items'][1]['disabled'] is True
|
|
|
|
formdef.fields[1].display_disabled_items = False
|
|
formdef.store()
|
|
resp = app.get('/foo/')
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['3']['items']) == 1
|
|
|
|
|
|
def test_field_live_items_checkboxes(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'),
|
|
fields.ItemsField(
|
|
type='items',
|
|
id='3',
|
|
label='Foo',
|
|
data_source={
|
|
'type': 'json',
|
|
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list?plop={{form_var_bar2}}{% endif %}',
|
|
},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '3'}).find('ul')
|
|
assert not resp.html.find('div', {'data-field-id': '3'}).find('ul li')
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['3']['items']) == 1
|
|
# simulate js, add relevant checkboxes
|
|
for option in live_resp.json['result']['3']['items']:
|
|
checkbox_name = '%s$element%s' % (
|
|
resp.html.find('div', {'data-field-id': '3'}).attrs['data-widget-name'],
|
|
option['id'],
|
|
)
|
|
resp.form.fields[checkbox_name] = Checkbox(
|
|
form=resp.form, name=checkbox_name, tag='input', value='yes', pos=10
|
|
)
|
|
resp.form.field_order.append((checkbox_name, resp.form.fields[checkbox_name]))
|
|
resp.form.fields[checkbox_name].checked = True
|
|
resp = resp.form.submit('submit') # -> validation
|
|
assert resp.pyquery('.CheckboxesWidget li label').text() == 'b'
|
|
resp = resp.form.submit('submit') # -> submitted
|
|
assert formdef.data_class().select()[0].data['3'] == ['a']
|
|
assert formdef.data_class().select()[0].data['3_display'] == 'b'
|
|
|
|
|
|
def test_field_live_items_select_multiple(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'),
|
|
fields.ItemsField(
|
|
type='items',
|
|
display_mode='autocomplete',
|
|
id='3',
|
|
label='Foo',
|
|
data_source={
|
|
'type': 'json',
|
|
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list?plop={{form_var_bar2}}{% endif %}',
|
|
},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '3'}).find('select')
|
|
assert not resp.html.find('div', {'data-field-id': '3'}).find('select option')
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['3']['items']) == 1
|
|
# simulate js, add relevant options
|
|
resp.form['f3[]'].options = [(x['id'], False, x['text']) for x in live_resp.json['result']['3']['items']]
|
|
resp.form['f3[]'].select_multiple(['a'])
|
|
resp = resp.form.submit('submit') # -> validation
|
|
assert resp.pyquery('select option[selected]').text() == 'b'
|
|
resp = resp.form.submit('submit') # -> submitted
|
|
assert formdef.data_class().select()[0].data['3'] == ['a']
|
|
assert formdef.data_class().select()[0].data['3_display'] == 'b'
|
|
|
|
|
|
def test_field_live_template_content(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='3',
|
|
label='Foo',
|
|
extra_css_class='template-whatever',
|
|
data_source={
|
|
'type': 'json',
|
|
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list-extra-with-disabled?plop={{form_var_bar2}}{% endif %}',
|
|
},
|
|
display_disabled_items=True,
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '3'}).find('select')
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['3']['items'][0]['foo'] == 'bar'
|
|
assert len(live_resp.json['result']['3']['items']) == 2
|
|
assert live_resp.json['result']['3']['items'][1]['disabled'] is True
|
|
|
|
formdef.fields[1].display_disabled_items = False
|
|
formdef.store()
|
|
resp = app.get('/foo/')
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['3']['items']) == 1
|
|
|
|
|
|
def test_field_live_timetable_select(pub, http_requests):
|
|
NamedDataSource.wipe()
|
|
data_source = NamedDataSource(name='foobar')
|
|
data_source.data_source = {
|
|
'type': 'json',
|
|
'value': 'http://remote.example.net/api/datetimes{% if form_var_bar2 %}?{% endif %}',
|
|
}
|
|
data_source.store()
|
|
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'),
|
|
fields.ItemField(
|
|
id='3',
|
|
type='item',
|
|
label='datetime',
|
|
display_mode='timetable',
|
|
data_source={'type': 'foobar'},
|
|
display_disabled_items=True,
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
|
|
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
|
|
data = {
|
|
"data": [
|
|
{"id": "1", "datetime": "2021-01-12 10:00:00", "text": "event 1", "api": {}},
|
|
{"id": "2", "datetime": "2021-01-13 10:20:00", "text": "event 2", "api": {}},
|
|
{
|
|
"id": "3",
|
|
"datetime": "2021-01-14 10:40:00",
|
|
"text": "event 3",
|
|
"api": {},
|
|
"disabled": True,
|
|
},
|
|
]
|
|
}
|
|
urlopen.side_effect = lambda *args: io.StringIO(json.dumps(data))
|
|
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '3'}).find('select')
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert 'datetime' in live_resp.json['result']['3']['items'][0]
|
|
assert 'api' not in live_resp.json['result']['3']['items'][0]
|
|
assert len(live_resp.json['result']['3']['items']) == 3
|
|
assert live_resp.json['result']['3']['items'][2]['disabled'] is True
|
|
|
|
formdef.fields[1].display_disabled_items = False
|
|
formdef.store()
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '3'}).find('select')
|
|
resp.form['f2'] = 'plop'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert 'datetime' in live_resp.json['result']['3']['items'][0]
|
|
assert 'api' not in live_resp.json['result']['3']['items'][0]
|
|
assert len(live_resp.json['result']['3']['items']) == 2
|
|
|
|
|
|
def test_field_live_comment_content(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='1', label='Bar', size='40', required=True, varname='bar'),
|
|
fields.StringField(type='string', id='2', label='Baz', size='40'),
|
|
fields.CommentField(id='5', label='bla {{form_var_bar}} bla', type='comment'),
|
|
fields.StringField(type='string', id='6', label='Bar2', size='40', required=True, varname='bar2'),
|
|
fields.CommentField(id='7', label='bla {{form_var_bar2}} bla', type='comment'),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
resp.form['f1'] = 'hello'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['5']['content'] == '<p>bla hello bla</p>'
|
|
resp.form['f1'] = 'toto'
|
|
live_resp = app.post('/foo/live?modified_field_id=1', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['5']['content'] == '<p>bla toto bla</p>'
|
|
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['5']['content'] == '<p>bla toto bla</p>'
|
|
|
|
# check evaluation of later fields
|
|
# <https://dev.entrouvert.org/issues/31922>
|
|
resp = app.get('/foo/')
|
|
resp.form['f1'] = 'hello'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['5']['content'] == '<p>bla hello bla</p>'
|
|
resp.form['f6'] = 'hello'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['7']['content'] == '<p>bla hello bla</p>'
|
|
|
|
|
|
def test_field_live_comment_content_from_structured_item_data(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.ItemField(
|
|
type='item',
|
|
id='1',
|
|
label='Foo',
|
|
varname='bar',
|
|
data_source={'type': 'json', 'value': 'http://remote.example.net/json-list-extra'},
|
|
),
|
|
fields.CommentField(id='7', label='bla {{form_var_bar_structured_foo}} bla', type='comment'),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
resp.form['f1'] = 'a'
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['7']['content'] == '<p>bla bar bla</p>'
|
|
|
|
|
|
def test_field_live_string_prefill(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='1', label='Bar', size='40', required=True, varname='bar'),
|
|
fields.StringField(
|
|
type='string',
|
|
id='2',
|
|
label='Bar2',
|
|
size='40',
|
|
required=True,
|
|
varname='bar2',
|
|
prefill={'type': 'string', 'value': '{{form_var_bar|default:""}}'},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.pyquery('#var_bar2.widget-prefilled') # second field is marked as prefilled
|
|
assert resp.form['f2'].value == ''
|
|
resp.form['f1'] = 'hello'
|
|
live_resp = app.post('/foo/live?modified_field_id=1&prefilled_2=on', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2'] == {'visible': True, 'content': 'hello'}
|
|
|
|
resp.form['f2'] = 'other' # manually changed -> widget-prefilled class will be removed
|
|
resp.form['f1'] = 'xxx'
|
|
live_resp = app.post('/foo/live?modified_field_id=1', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2'] == {'visible': True}
|
|
|
|
# check it's not possible to declare user change from frontoffice
|
|
live_resp = app.post('/foo/live?modified_field_id=user', params=resp.form.submit_fields(), status=403)
|
|
|
|
|
|
def test_field_live_bool_prefill(pub, http_requests):
|
|
CardDef.wipe()
|
|
carddef = CardDef()
|
|
carddef.name = 'foo'
|
|
carddef.digest_templates = {'default': '{{ form_var_foo }}'}
|
|
carddef.fields = [
|
|
fields.StringField(id='1', type='string', label='string', varname='foo'),
|
|
fields.BoolField(
|
|
type='bool',
|
|
id='2',
|
|
varname='bool',
|
|
),
|
|
]
|
|
carddef.store()
|
|
carddef.data_class().wipe()
|
|
carddata1 = carddef.data_class()()
|
|
carddata1.data = {
|
|
'1': 'bar',
|
|
'2': True,
|
|
}
|
|
carddata1.just_created()
|
|
carddata1.store()
|
|
carddata2 = carddef.data_class()()
|
|
carddata2.data = {
|
|
'1': 'baz',
|
|
'2': False,
|
|
}
|
|
carddata2.just_created()
|
|
carddata2.store()
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.ItemField(
|
|
type='item', id='1', label='foo', varname='foo', data_source={'type': 'carddef:foo'}
|
|
),
|
|
fields.BoolField(
|
|
type='bool',
|
|
id='2',
|
|
label='bool',
|
|
varname='bool',
|
|
prefill={'type': 'string', 'value': '{{ form_var_foo_live_var_bool }}'},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.pyquery('#var_bool.widget-prefilled') # second field is marked as prefilled
|
|
assert resp.form['f2'].value is None
|
|
resp.form['f1'] = str(carddata1.id)
|
|
live_resp = app.post('/foo/live?modified_field_id=1&prefilled_2=on', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2'] == {'visible': True, 'content': True}
|
|
|
|
resp.form['f2'] = False # manually changed -> widget-prefilled class will be removed
|
|
resp.form['f1'] = str(carddata2.id)
|
|
live_resp = app.post('/foo/live?modified_field_id=1', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2'] == {'visible': True}
|
|
|
|
|
|
def test_field_live_date_prefill(pub, http_requests):
|
|
pub.cfg['language'] = {'language': 'fr'}
|
|
pub.write_cfg()
|
|
CardDef.wipe()
|
|
carddef = CardDef()
|
|
carddef.name = 'foo'
|
|
carddef.digest_templates = {'default': '{{ form_var_foo }}'}
|
|
carddef.fields = [
|
|
fields.StringField(id='1', type='string', label='string', varname='foo'),
|
|
fields.DateField(
|
|
type='date',
|
|
id='2',
|
|
varname='date',
|
|
),
|
|
]
|
|
carddef.store()
|
|
carddef.data_class().wipe()
|
|
carddata1 = carddef.data_class()()
|
|
carddata1.data = {
|
|
'1': 'bar',
|
|
'2': datetime.date(2021, 10, 1).timetuple(),
|
|
}
|
|
carddata1.just_created()
|
|
carddata1.store()
|
|
carddata2 = carddef.data_class()()
|
|
carddata2.data = {
|
|
'1': 'baz',
|
|
'2': datetime.date(2021, 10, 30).timetuple(),
|
|
}
|
|
carddata2.just_created()
|
|
carddata2.store()
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.ItemField(
|
|
type='item', id='1', label='foo', varname='foo', data_source={'type': 'carddef:foo'}
|
|
),
|
|
fields.DateField(
|
|
type='date',
|
|
id='2',
|
|
label='date',
|
|
varname='date',
|
|
prefill={'type': 'string', 'value': '{{ form_var_foo_live_var_date }}'},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.pyquery('#var_date.widget-prefilled') # second field is marked as prefilled
|
|
assert resp.form['f2'].value == ''
|
|
resp.form['f1'] = str(carddata1.id)
|
|
live_resp = app.post('/foo/live?modified_field_id=1&prefilled_2=on', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2'] == {
|
|
'visible': True,
|
|
'content': '2021-10-01',
|
|
'text_content': '01/10/2021',
|
|
}
|
|
|
|
resp.form['f2'] = '2021-10-30' # manually changed -> widget-prefilled class will be removed
|
|
resp.form['f1'] = str(carddata2.id)
|
|
live_resp = app.post('/foo/live?modified_field_id=1', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2'] == {'visible': True}
|
|
|
|
|
|
def test_field_live_item_datasource_carddef_prefill(pub, http_requests):
|
|
CardDef.wipe()
|
|
|
|
carddef_related = CardDef()
|
|
carddef_related.name = 'bar'
|
|
carddef_related.digest_templates = {'default': '{{ form_var_bar }}'}
|
|
carddef_related.fields = [
|
|
fields.StringField(id='1', type='string', label='string', varname='bar'),
|
|
]
|
|
carddef_related.store()
|
|
carddef_related.data_class().wipe()
|
|
for value in ['A', 'B', 'C']:
|
|
carddata = carddef_related.data_class()()
|
|
carddata.data = {
|
|
'1': value,
|
|
}
|
|
carddata.just_created()
|
|
carddata.store()
|
|
|
|
carddef = CardDef()
|
|
carddef.name = 'foo'
|
|
carddef.digest_templates = {'default': '{{ form_var_foo }}'}
|
|
carddef.fields = [
|
|
fields.StringField(id='1', type='string', label='string', varname='foo'),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='2',
|
|
varname='item',
|
|
data_source={'type': 'carddef:bar'},
|
|
),
|
|
]
|
|
carddef.store()
|
|
carddef.data_class().wipe()
|
|
carddata1 = carddef.data_class()()
|
|
carddata1.data = {
|
|
'1': 'bar',
|
|
'2': '1',
|
|
'2_display': 'A',
|
|
}
|
|
carddata1.just_created()
|
|
carddata1.store()
|
|
carddata2 = carddef.data_class()()
|
|
carddata2.data = {
|
|
'1': 'baz',
|
|
'2': '2',
|
|
'2_display': 'B',
|
|
}
|
|
carddata2.just_created()
|
|
carddata2.store()
|
|
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.ItemField(
|
|
type='item', id='1', label='foo', varname='foo', data_source={'type': 'carddef:foo'}
|
|
),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='2',
|
|
label='item',
|
|
varname='item',
|
|
prefill={'type': 'string', 'value': '{{ form_var_foo_live_var_item }}'},
|
|
data_source={'type': 'carddef:bar'},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.pyquery('#var_item.widget-prefilled') # second field is marked as prefilled
|
|
assert resp.form['f2'].value == '1'
|
|
resp.form['f1'] = str(carddata2.id)
|
|
live_resp = app.post('/foo/live?modified_field_id=1&prefilled_2=on', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2'] == {'visible': True, 'content': '2'}
|
|
|
|
resp.form['f2'] = '3' # manually changed -> widget-prefilled class will be removed
|
|
resp.form['f1'] = str(carddata1.id)
|
|
live_resp = app.post('/foo/live?modified_field_id=1', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2'] == {'visible': True}
|
|
|
|
|
|
@mock.patch('wcs.qommon.misc.urlopen')
|
|
def test_field_live_item_datasource_prefill_with_request(urlopen, pub):
|
|
data = {'data': [{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux', 'x': 'bye'}]}
|
|
urlopen.side_effect = lambda *args: io.StringIO(json.dumps(data))
|
|
ds = {'type': 'json', 'value': 'http://remote.example.net/plop'}
|
|
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.ItemField(
|
|
id='1',
|
|
label='item',
|
|
data_source=ds,
|
|
varname='foo',
|
|
prefill={'type': 'string', 'value': '{{ request.GET.plop }}'},
|
|
),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='2',
|
|
label='item',
|
|
varname='item',
|
|
prefill={'type': 'string', 'value': '{{ form_var_foo }}'},
|
|
data_source=ds,
|
|
),
|
|
]
|
|
formdef.store()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/?plop=2')
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.pyquery('#var_item.widget-prefilled') # second field is marked as prefilled
|
|
assert resp.form['f1'].value == '2'
|
|
live_resp = app.post(
|
|
'/foo/live?modified_field_id=init&prefilled_1=on&prefilled_2=on', params=resp.form.submit_fields()
|
|
)
|
|
assert live_resp.json['result'] == {'2': {'visible': True, 'content': '2'}}
|
|
|
|
|
|
@mock.patch('wcs.qommon.misc.urlopen')
|
|
def test_field_live_item_datasource_prefill_with_request_with_q(urlopen, pub):
|
|
NamedDataSource.wipe()
|
|
data_source = NamedDataSource(name='foobar')
|
|
data_source.data_source = {
|
|
'type': 'json',
|
|
'value': 'http://remote.example.net/json?plop={{form_var_bar}}',
|
|
}
|
|
data_source.query_parameter = 'q'
|
|
data_source.id_parameter = 'id'
|
|
data_source.store()
|
|
|
|
data = {'data': [{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux', 'x': 'bye'}]}
|
|
urlopen.side_effect = lambda *args: io.StringIO(json.dumps(data))
|
|
ds = {'type': 'foobar'}
|
|
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.ItemField(
|
|
id='1',
|
|
label='item',
|
|
data_source=ds,
|
|
varname='foo',
|
|
prefill={'type': 'string', 'value': '{{ request.GET.plop }}'},
|
|
),
|
|
fields.ItemField(
|
|
type='item',
|
|
id='2',
|
|
label='item',
|
|
varname='item',
|
|
prefill={'type': 'string', 'value': '{{ form_var_foo }}'},
|
|
data_source=ds,
|
|
),
|
|
]
|
|
formdef.store()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/?plop=2')
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.pyquery('#var_item.widget-prefilled') # second field is marked as prefilled
|
|
assert resp.form['f1'].value == '2'
|
|
live_resp = app.post(
|
|
'/foo/live?modified_field_id=init&prefilled_1=on&prefilled_2=on', params=resp.form.submit_fields()
|
|
)
|
|
assert live_resp.json['result'] == {'2': {'visible': True, 'content': '2'}}
|
|
# check it has ?q=
|
|
assert urlopen.call_args[0][0] == 'http://remote.example.net/json?plop=&q=deux'
|
|
|
|
|
|
def test_field_live_block_string_prefill(pub, http_requests):
|
|
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|default:""}}'},
|
|
),
|
|
]
|
|
block.store()
|
|
|
|
formdef = FormDef()
|
|
formdef.name = 'form title'
|
|
formdef.fields = [
|
|
fields.StringField(id='1', label='test', type='string', varname='foo'),
|
|
fields.BlockField(id='2', label='test', type='block:foobar'),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get(formdef.get_url())
|
|
live_url = resp.html.find('form').attrs['data-live-url']
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.pyquery('[data-field-id="123"].widget-prefilled') # block/string
|
|
assert resp.form['f2$element0$f123'].value == ''
|
|
resp.form['f1'] = 'hello'
|
|
live_resp = app.post(live_url + '?modified_field_id=1&prefilled_123=on', params=resp.form.submit_fields())
|
|
assert live_resp.json['result'] == {
|
|
'1': {'visible': True},
|
|
'2': {'visible': True},
|
|
'2-123-0': {
|
|
'block_id': '2',
|
|
'block_row': 'element0',
|
|
'row': 0,
|
|
'content': 'hello',
|
|
'field_id': '123',
|
|
'visible': True,
|
|
},
|
|
}
|
|
|
|
|
|
def test_field_live_condition_unknown_page_id(pub):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.PageField(id='0', label='2nd page', type='page'),
|
|
fields.StringField(type='string', id='1', label='Bar', size='40', required=True, varname='bar'),
|
|
fields.StringField(
|
|
type='string',
|
|
id='2',
|
|
label='Foo',
|
|
size='40',
|
|
required=True,
|
|
varname='foo',
|
|
condition={'type': 'django', 'value': 'form_var_bar == "bye"'},
|
|
),
|
|
fields.PageField(id='3', label='1st page', type='page'),
|
|
fields.StringField(type='string', id='4', label='Baz', size='40', required=True, varname='baz'),
|
|
]
|
|
formdef.store()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none'
|
|
resp.form['f1'] = 'hello'
|
|
params = resp.form.submit_fields()
|
|
params = [(key, value if key != 'page_id' else 'eiuiu') for key, value in params]
|
|
app.post('/foo/live', params=params)
|
|
|
|
|
|
def test_field_live_locked_prefilled_field(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(type='string', id='1', label='Bar', size='40', required=True, varname='bar'),
|
|
fields.StringField(
|
|
type='string',
|
|
id='2',
|
|
label='locked',
|
|
size='40',
|
|
required=True,
|
|
prefill={'type': 'string', 'value': 'bla {{form_var_bar}} bla', 'locked': True},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
|
|
resp.form['f1'] = 'hello'
|
|
live_resp = app.post('/foo/live?prefilled_2=on', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2']['content'] == 'bla hello bla'
|
|
resp.form['f1'] = 'toto'
|
|
live_resp = app.post('/foo/live?modified_field_id=1&prefilled_2=on', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['2']['content'] == 'bla toto bla'
|
|
|
|
|
|
def test_field_live_locked_error_prefilled_field(pub, http_requests):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.StringField(
|
|
type='string',
|
|
id='2',
|
|
label='locked',
|
|
size='40',
|
|
required=True,
|
|
prefill={'type': 'string', 'value': 'bla {% if foo %}{{ foo }}{% end %}', 'locked': True},
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'readonly' in resp.form['f2'].attrs
|
|
assert not resp.form['f2'].attrs.get('value')
|
|
|
|
|
|
@pytest.mark.parametrize('field_type', ['item', 'string', 'email'])
|
|
def test_dynamic_item_field_from_custom_view_on_cards(pub, field_type):
|
|
pub.role_class.wipe()
|
|
pub.custom_view_class.wipe()
|
|
|
|
user = create_user(pub)
|
|
role = pub.role_class(name='xxx')
|
|
role.store()
|
|
user.roles = [role.id]
|
|
user.is_admin = True
|
|
user.store()
|
|
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'test'
|
|
formdef.fields = []
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
CardDef.wipe()
|
|
carddef = CardDef()
|
|
carddef.name = 'items'
|
|
carddef.digest_templates = {'default': '{{form_var_attr}}'}
|
|
carddef.workflow_roles = {'_editor': user.roles[0]}
|
|
carddef.fields = [
|
|
fields.StringField(id='1', type='string', label='string', varname='attr'),
|
|
]
|
|
if field_type == 'item':
|
|
carddef.fields.append(
|
|
fields.ItemField(id='0', type='item', label='item', varname='item', items=['foo', 'bar', 'baz'])
|
|
)
|
|
elif field_type == 'string':
|
|
carddef.fields.append(fields.StringField(id='0', type='string', label='string', varname='item'))
|
|
elif field_type == 'email':
|
|
carddef.fields.append(fields.EmailField(id='0', type='email', label='email', varname='item'))
|
|
carddef.store()
|
|
carddef.data_class().wipe()
|
|
baz_ids = set()
|
|
for i, value in enumerate(['foo', 'bar', 'baz'] * 10):
|
|
carddata = carddef.data_class()()
|
|
carddata.data = {
|
|
'0': value,
|
|
'1': 'attr%s' % i,
|
|
}
|
|
if field_type == 'item':
|
|
carddata.data['0_display'] = value
|
|
carddata.just_created()
|
|
carddata.store()
|
|
if value == 'baz':
|
|
baz_ids.add(str(carddata.id))
|
|
|
|
# create custom view
|
|
app = login(get_app(pub), username='foo', password='foo')
|
|
|
|
resp = app.get('/backoffice/data/items/')
|
|
assert resp.text.count('<tr') == 21 # thead + 20 items (max per page)
|
|
resp.forms['listing-settings']['filter-0'].checked = True
|
|
resp.forms['listing-settings']['filter-status'].checked = True
|
|
resp = resp.forms['listing-settings'].submit()
|
|
|
|
resp.forms['listing-settings']['filter'].value = 'recorded'
|
|
resp = resp.forms['listing-settings'].submit()
|
|
|
|
resp.forms['save-custom-view']['title'] = 'as data source'
|
|
resp.forms['save-custom-view']['visibility'] = 'datasource'
|
|
resp = resp.forms['save-custom-view'].submit().follow()
|
|
|
|
if field_type == 'item':
|
|
# some javascript to get a text input for filter value
|
|
assert resp.forms['listing-settings']['filter-0-value'].attrs['data-allow-template']
|
|
assert 'custom value' in [x[2] for x in resp.forms['listing-settings']['filter-0-value'].options]
|
|
resp.forms['listing-settings']['filter-0-value'].force_value('{{ form_var_blah }}')
|
|
else:
|
|
resp.forms['listing-settings']['filter-0-value'] = '{{ form_var_blah }}'
|
|
|
|
resp = resp.forms['listing-settings'].submit()
|
|
assert resp.forms['listing-settings']['filter-0-value'].value == '{{ form_var_blah }}'
|
|
assert resp.text.count('<tr') == 1 # thead only
|
|
|
|
# save custom view with filter
|
|
resp = resp.forms['save-custom-view'].submit().follow()
|
|
|
|
custom_view = pub.custom_view_class.select()[0]
|
|
|
|
# use custom view as source
|
|
ds = {'type': 'carddef:%s:%s' % (carddef.url_name, custom_view.slug)}
|
|
formdef.fields = [
|
|
fields.PageField(id='2', label='1st page', type='page'),
|
|
fields.ItemField(id='0', type='item', label='item', varname='blah', items=['foo', 'bar', 'baz']),
|
|
fields.ItemField(id='1', label='string', type='item', data_source=ds, display_disabled_items=True),
|
|
]
|
|
formdef.store()
|
|
|
|
resp = get_app(pub).get('/test/')
|
|
assert resp.form['f1'].options == [('', False, '---')]
|
|
resp.form['f0'] = 'baz'
|
|
live_resp = app.post('/test/live?modified_field_id=0', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['1']['items']) == 10
|
|
assert {str(x['id']) for x in live_resp.json['result']['1']['items']} == baz_ids
|
|
|
|
resp.form['f1'].options = []
|
|
for item in live_resp.json['result']['1']['items']:
|
|
# simulate javascript filling the <select>
|
|
resp.form['f1'].options.append((str(item['id']), False, item['text']))
|
|
|
|
resp.form['f1'] = resp.form['f1'].options[0][0]
|
|
resp = resp.form.submit('submit') # -> validation page
|
|
assert 'Technical error' not in resp.text
|
|
resp = resp.form.submit('submit') # -> submit
|
|
assert formdef.data_class().select()[0].data['1'] in baz_ids
|
|
assert formdef.data_class().select()[0].data['1_structured']['item'] == 'baz'
|
|
|
|
# same in autocomplete mode
|
|
formdef.fields[2].display_mode = 'autocomplete'
|
|
formdef.store()
|
|
app = get_app(pub)
|
|
resp = app.get('/test/')
|
|
# simulate select2 mode, with qommon.forms.js adding an extra hidden widget
|
|
resp.form.fields['f1_display'] = Hidden(form=resp.form, tag='input', name='f1_display', pos=10)
|
|
select2_url = resp.pyquery('select:last').attr['data-select2-url']
|
|
resp_json = app.get(select2_url + '?q=')
|
|
assert len(resp_json.json['data']) == 0
|
|
resp.form['f0'] = 'baz'
|
|
|
|
live_resp = app.post('/test/live?modified_field_id=0', params=resp.form.submit_fields())
|
|
new_select2_url = live_resp.json['result']['1']['source_url']
|
|
resp_json = app.get(new_select2_url + '?q=')
|
|
assert len(resp_json.json['data']) == 10
|
|
assert {str(x['id']) for x in resp_json.json['data']} == baz_ids
|
|
|
|
resp.form['f1'].force_value(str(resp_json.json['data'][0]['id']))
|
|
resp.form.fields['f1_display'].force_value(resp_json.json['data'][0]['text'])
|
|
|
|
resp = resp.form.submit('submit') # -> validation page
|
|
resp = resp.form.submit('submit') # -> submit
|
|
assert formdef.data_class().select()[0].data['1'] in baz_ids
|
|
assert formdef.data_class().select()[0].data['1_structured']['item'] == 'baz'
|
|
|
|
# delete custom view
|
|
pub.loggederror_class.wipe()
|
|
custom_view.remove_self()
|
|
resp = get_app(pub).get('/test/')
|
|
assert resp.form['f1'].options == []
|
|
assert pub.loggederror_class.count() == 1
|
|
logged_error = pub.loggederror_class.select()[0]
|
|
assert logged_error.formdef_id == formdef.id
|
|
assert logged_error.summary == '[DATASOURCE] Unknown custom view "as-data-source" for CardDef "items"'
|
|
|
|
|
|
def test_dynamic_items_field_from_custom_view_on_cards(pub):
|
|
pub.role_class.wipe()
|
|
pub.custom_view_class.wipe()
|
|
|
|
user = create_user(pub)
|
|
role = pub.role_class(name='xxx')
|
|
role.store()
|
|
user.roles = [role.id]
|
|
user.is_admin = True
|
|
user.store()
|
|
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'test'
|
|
formdef.fields = []
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
items = ['foo', 'bar', 'baz', 'buz']
|
|
CardDef.wipe()
|
|
carddef = CardDef()
|
|
carddef.name = 'items'
|
|
carddef.digest_templates = {'default': '{{form_var_attr}} - {{form_var_items}}'}
|
|
carddef.workflow_roles = {'_editor': user.roles[0]}
|
|
carddef.fields = [
|
|
fields.ItemsField(id='0', type='items', label='items', varname='items', items=items),
|
|
fields.StringField(id='1', type='string', label='string', varname='attr'),
|
|
]
|
|
carddef.store()
|
|
carddef.data_class().wipe()
|
|
foo_bar_ids = set()
|
|
for i, (v1, v2) in enumerate(itertools.product(items, items)):
|
|
if v1 == v2:
|
|
continue
|
|
carddata = carddef.data_class()()
|
|
carddata.data = {
|
|
'0': [v1, v2],
|
|
'0_display': '%s,%s' % (v1, v2),
|
|
'1': 'attr%s' % i,
|
|
}
|
|
carddata.just_created()
|
|
carddata.store()
|
|
if 'foo' in {v1, v2}:
|
|
foo_bar_ids.add(str(carddata.id))
|
|
|
|
# create custom view
|
|
app = login(get_app(pub), username='foo', password='foo')
|
|
|
|
resp = app.get('/backoffice/data/items/?order_by=id')
|
|
assert resp.text.count('<tr') == 13 # thead + 12 items
|
|
resp.forms['listing-settings']['filter-0'].checked = True
|
|
resp.forms['listing-settings']['filter-status'].checked = True
|
|
resp = resp.forms['listing-settings'].submit()
|
|
|
|
resp.forms['listing-settings']['filter'].value = 'recorded'
|
|
resp = resp.forms['listing-settings'].submit()
|
|
|
|
resp.forms['save-custom-view']['title'] = 'as data source'
|
|
resp.forms['save-custom-view']['visibility'] = 'datasource'
|
|
resp = resp.forms['save-custom-view'].submit().follow()
|
|
|
|
assert resp.forms['listing-settings']['filter-0-value'].attrs['data-allow-template']
|
|
assert 'custom value' in [x[2] for x in resp.forms['listing-settings']['filter-0-value'].options]
|
|
resp.forms['listing-settings']['filter-0-value'].force_value('{{ form_var_blah }}')
|
|
|
|
resp = resp.forms['listing-settings'].submit()
|
|
assert resp.forms['listing-settings']['filter-0-value'].value == '{{ form_var_blah }}'
|
|
assert resp.text.count('<tr') == 1 # thead only
|
|
|
|
# save custom view with filter
|
|
resp = resp.forms['save-custom-view'].submit().follow()
|
|
|
|
custom_view = pub.custom_view_class.select()[0]
|
|
|
|
# use custom view as source
|
|
ds = {'type': 'carddef:%s:%s' % (carddef.url_name, custom_view.slug)}
|
|
formdef.fields = [
|
|
fields.PageField(id='2', label='1st page', type='page'),
|
|
fields.ItemsField(id='0', type='items', label='items', varname='blah', items=items),
|
|
fields.ItemField(id='1', label='string', type='item', data_source=ds, display_disabled_items=True),
|
|
]
|
|
formdef.store()
|
|
|
|
resp = get_app(pub).get('/test/')
|
|
assert resp.form['f1'].options == [('', False, '---')]
|
|
resp.form['f0$element0'] = 'foo'
|
|
live_resp = app.post('/test/live?modified_field_id=0', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['1']['items']) == 6
|
|
assert {str(x['id']) for x in live_resp.json['result']['1']['items']} == foo_bar_ids
|
|
|
|
resp.form['f1'].options = []
|
|
for item in live_resp.json['result']['1']['items']:
|
|
# simulate javascript filling the <select>
|
|
resp.form['f1'].options.append((str(item['id']), False, item['text']))
|
|
|
|
resp.form['f1'] = resp.form['f1'].options[0][0]
|
|
resp = resp.form.submit('submit') # -> validation page
|
|
assert 'Technical error' not in resp.text
|
|
resp = resp.form.submit('submit') # -> submit
|
|
assert formdef.data_class().select()[0].data['1'] in foo_bar_ids
|
|
assert formdef.data_class().select()[0].data['1_structured']['text'] == 'attr1 - foo,bar'
|
|
|
|
# same in autocomplete mode
|
|
formdef.fields[2].display_mode = 'autocomplete'
|
|
formdef.store()
|
|
app = get_app(pub)
|
|
resp = app.get('/test/')
|
|
# simulate select2 mode, with qommon.forms.js adding an extra hidden widget
|
|
resp.form.fields['f1_display'] = Hidden(form=resp.form, tag='input', name='f1_display', pos=10)
|
|
select2_url = resp.pyquery('select:last').attr['data-select2-url']
|
|
resp_json = app.get(select2_url + '?q=')
|
|
assert len(resp_json.json['data']) == 0
|
|
resp.form['f0$element0'] = 'foo'
|
|
|
|
live_resp = app.post('/test/live?modified_field_id=0', params=resp.form.submit_fields())
|
|
new_select2_url = live_resp.json['result']['1']['source_url']
|
|
resp_json = app.get(new_select2_url + '?q=')
|
|
assert len(resp_json.json['data']) == 6
|
|
assert {str(x['id']) for x in resp_json.json['data']} == foo_bar_ids
|
|
|
|
resp.form['f1'].force_value(str(resp_json.json['data'][0]['id']))
|
|
resp.form.fields['f1_display'].force_value(resp_json.json['data'][0]['text'])
|
|
|
|
resp = resp.form.submit('submit') # -> validation page
|
|
resp = resp.form.submit('submit') # -> submit
|
|
assert formdef.data_class().select()[0].data['1'] in foo_bar_ids
|
|
assert formdef.data_class().select()[0].data['1_structured']['text'] == 'attr1 - foo,bar'
|
|
|
|
# delete custom view
|
|
pub.loggederror_class.wipe()
|
|
custom_view.remove_self()
|
|
resp = get_app(pub).get('/test/')
|
|
assert resp.form['f1'].options == []
|
|
assert pub.loggederror_class.count() == 1
|
|
logged_error = pub.loggederror_class.select()[0]
|
|
assert logged_error.formdef_id == formdef.id
|
|
assert logged_error.summary == '[DATASOURCE] Unknown custom view "as-data-source" for CardDef "items"'
|
|
|
|
|
|
def test_dynamic_internal_id_from_custom_view_on_cards(pub):
|
|
pub.role_class.wipe()
|
|
pub.custom_view_class.wipe()
|
|
|
|
user = create_user(pub)
|
|
role = pub.role_class(name='xxx')
|
|
role.store()
|
|
user.roles = [role.id]
|
|
user.is_admin = True
|
|
user.store()
|
|
|
|
CardDef.wipe()
|
|
carddef = CardDef()
|
|
carddef.name = 'items'
|
|
carddef.digest_templates = {'default': '{{form_var_attr}}'}
|
|
carddef.workflow_roles = {'_editor': user.roles[0]}
|
|
carddef.fields = [
|
|
fields.StringField(id='1', type='string', label='string', varname='attr'),
|
|
fields.BoolField(
|
|
type='bool',
|
|
id='2',
|
|
varname='bool',
|
|
),
|
|
fields.StringField(id='3', type='string', label='string', varname='attr2'),
|
|
]
|
|
carddef.store()
|
|
carddef.data_class().wipe()
|
|
for i in range(10):
|
|
carddata = carddef.data_class()()
|
|
carddata.data = {
|
|
'1': 'attr%s' % i,
|
|
'2': bool(i % 2),
|
|
'3': str(i + 1),
|
|
}
|
|
carddata.just_created()
|
|
carddata.store()
|
|
|
|
custom_view = pub.custom_view_class()
|
|
custom_view.title = 'as datasource'
|
|
custom_view.formdef = carddef
|
|
custom_view.columns = {'list': [{'id': 'id'}]}
|
|
custom_view.filters = {
|
|
'filter-internal-id': 'on',
|
|
'filter-internal-id-value': '{{ form_var_num }}',
|
|
'filter-internal-id-operator': 'eq',
|
|
}
|
|
custom_view.visibility = 'datasource'
|
|
custom_view.store()
|
|
|
|
ds = {'type': 'carddef:%s:%s' % (carddef.url_name, custom_view.slug)}
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'test'
|
|
formdef.fields = [
|
|
fields.StringField(id='0', type='string', label='num', varname='num'),
|
|
fields.ItemField(id='1', label='item', type='item', data_source=ds, display_disabled_items=True),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = login(get_app(pub), username='foo', password='foo')
|
|
|
|
resp = app.get('/backoffice/data/items/as-datasource/')
|
|
assert resp.text.count('<tr') == 1 # thead only
|
|
|
|
resp = get_app(pub).get('/test/')
|
|
assert resp.form['f1'].options == [('', False, '---')]
|
|
resp.form['f0'] = '3'
|
|
live_resp = app.post('/test/live?modified_field_id=0', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['1']['items']) == 1
|
|
assert {x['id'] for x in live_resp.json['result']['1']['items']} == {3}
|
|
|
|
custom_view.filters['filter-internal-id-operator'] = 'ne'
|
|
custom_view.store()
|
|
live_resp = app.post('/test/live?modified_field_id=0', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['1']['items']) == 9
|
|
assert {x['id'] for x in live_resp.json['result']['1']['items']} == {1, 2, 4, 5, 6, 7, 8, 9, 10}
|
|
|
|
custom_view.filters['filter-internal-id-operator'] = 'lte'
|
|
custom_view.store()
|
|
live_resp = app.post('/test/live?modified_field_id=0', params=resp.form.submit_fields())
|
|
assert len(live_resp.json['result']['1']['items']) == 3
|
|
assert {x['id'] for x in live_resp.json['result']['1']['items']} == {1, 2, 3}
|
|
|
|
formdef.fields[0] = fields.ComputedField(
|
|
id='0',
|
|
label='computed',
|
|
type='computed',
|
|
varname='num',
|
|
value_template='{{ cards|objects:"items"|filter_by:"bool"|filter_value:True|getlist:"form_internal_id"|list }}',
|
|
)
|
|
formdef.store()
|
|
|
|
custom_view.filters['filter-internal-id-operator'] = 'eq'
|
|
custom_view.store()
|
|
resp = get_app(pub).get('/test/')
|
|
assert {int(x[0]) for x in resp.form['f1'].options} == {2, 4, 6, 8, 10}
|
|
|
|
custom_view.filters['filter-internal-id-operator'] = 'ne'
|
|
custom_view.store()
|
|
resp = get_app(pub).get('/test/')
|
|
assert {int(x[0]) for x in resp.form['f1'].options} == {1, 3, 5, 7, 9}
|
|
|
|
for operator in ['lt', 'lte', 'gt', 'gte']:
|
|
pub.loggederror_class.wipe()
|
|
# list of values not allowed with theese operators
|
|
custom_view.filters['filter-internal-id-operator'] = operator
|
|
custom_view.store()
|
|
resp = get_app(pub).get('/test/')
|
|
assert resp.form['f1'].options == [('', False, '---')]
|
|
assert pub.loggederror_class.count() == 1
|
|
logged_error = pub.loggederror_class.select()[0]
|
|
assert logged_error.formdef_id == formdef.id
|
|
assert (
|
|
logged_error.summary
|
|
== 'Invalid value "[2, 4, 6, 8, 10]" for custom view "as-datasource", CardDef "items", field "internal-id", operator "%s"'
|
|
% operator
|
|
)
|
|
|
|
# not integers
|
|
formdef.fields[
|
|
0
|
|
].value_template = '{{ cards|objects:"items"|filter_by:"bool"|filter_value:True|getlist:"attr"|list }}'
|
|
formdef.store()
|
|
custom_view.filters['filter-internal-id-operator'] = 'eq'
|
|
custom_view.store()
|
|
pub.loggederror_class.wipe()
|
|
resp = get_app(pub).get('/test/')
|
|
assert resp.form['f1'].options == [('', False, '---')]
|
|
assert pub.loggederror_class.count() == 1
|
|
logged_error = pub.loggederror_class.select()[0]
|
|
assert logged_error.formdef_id == formdef.id
|
|
assert (
|
|
logged_error.summary == 'Invalid value "[\'attr1\', \'attr3\', \'attr5\', \'attr7\', \'attr9\']" '
|
|
'for custom view "as-datasource", CardDef "items", field "internal-id", operator "eq"'
|
|
)
|
|
|
|
# empty list
|
|
formdef.fields[
|
|
0
|
|
].value_template = (
|
|
'{{ cards|objects:"items"|filter_by:"attr"|filter_value:"unknown"|getlist:"form_internal_id"|list }}'
|
|
)
|
|
formdef.store()
|
|
custom_view.filters['filter-internal-id-operator'] = 'eq'
|
|
custom_view.store()
|
|
resp = get_app(pub).get('/test/')
|
|
assert resp.form['f1'].options == [('', False, '---')]
|
|
custom_view.filters['filter-internal-id-operator'] = 'ne'
|
|
custom_view.store()
|
|
resp = get_app(pub).get('/test/')
|
|
assert {int(x[0]) for x in resp.form['f1'].options} == {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
|
|
|
# attr2 is filled with integers
|
|
formdef.fields[
|
|
0
|
|
].value_template = '{{ cards|objects:"items"|filter_by:"bool"|filter_value:True|getlist:"attr2"|list }}'
|
|
formdef.store()
|
|
resp = get_app(pub).get('/test/')
|
|
assert {int(x[0]) for x in resp.form['f1'].options} == {1, 3, 5, 7, 9}
|
|
|
|
|
|
def test_item_field_from_cards_check_lazy_live(pub):
|
|
create_user(pub)
|
|
|
|
CardDef.wipe()
|
|
carddef = CardDef()
|
|
carddef.name = 'items'
|
|
carddef.digest_templates = {'default': '{{form_var_name}}'}
|
|
carddef.fields = [
|
|
fields.StringField(id='0', label='string', varname='name'),
|
|
fields.StringField(id='1', label='string', varname='attr'),
|
|
]
|
|
carddef.store()
|
|
carddef.data_class().wipe()
|
|
for i, value in enumerate(['foo', 'bar', 'baz']):
|
|
carddata = carddef.data_class()()
|
|
carddata.data = {
|
|
'0': value,
|
|
'1': 'attr%s' % i,
|
|
}
|
|
carddata.just_created()
|
|
carddata.store()
|
|
|
|
ds = {'type': 'carddef:%s' % carddef.url_name}
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'test'
|
|
formdef.fields = [
|
|
fields.PageField(id='0', label='1st page', type='page'),
|
|
fields.ItemField(id='1', label='string', type='item', varname='item', data_source=ds),
|
|
fields.PageField(id='2', label='2nd page', type='page'),
|
|
fields.CommentField(id='3', label='live value: {{ form_var_item_live_var_attr }}', type='comment'),
|
|
fields.PageField(id='4', label='3rd page', type='page'),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
resp = get_app(pub).get('/test/')
|
|
resp.form['f1'] = '2'
|
|
resp = resp.form.submit('submit') # -> 2nd page
|
|
assert 'live value: attr1' in resp
|
|
|
|
# add a field with a condition on first page and third page
|
|
formdef.fields[1:1] = [
|
|
fields.StringField(
|
|
id='5',
|
|
label='field with condition',
|
|
type='string',
|
|
required=False,
|
|
condition={'type': 'django', 'value': '1'},
|
|
),
|
|
]
|
|
formdef.fields.append(
|
|
fields.StringField(
|
|
id='6',
|
|
label='second field with condition',
|
|
type='string',
|
|
required=False,
|
|
condition={'type': 'django', 'value': '1'},
|
|
)
|
|
)
|
|
formdef.store()
|
|
resp = get_app(pub).get('/test/')
|
|
resp.form['f1'] = '2'
|
|
resp = resp.form.submit('submit') # -> 2nd page
|
|
assert 'live value: attr1' in resp
|
|
resp = resp.form.submit('submit') # -> 3rd page
|
|
resp = resp.form.submit('previous') # -> 2nd page
|
|
assert 'live value: attr1' in resp
|
|
|
|
|
|
@mock.patch('wcs.qommon.misc.urlopen')
|
|
def test_field_live_condition_data_source_error(urlopen, pub):
|
|
ds = {'type': 'json', 'value': 'http://www.example.net/plop'}
|
|
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'Foo'
|
|
formdef.fields = [
|
|
fields.ItemField(id='1', label='string', data_source=ds, varname='foo'),
|
|
fields.StringField(
|
|
id='2',
|
|
label='bar',
|
|
required=True,
|
|
varname='bar',
|
|
condition={'type': 'django', 'value': 'form_var_foo_x == "bye"'},
|
|
),
|
|
]
|
|
formdef.store()
|
|
|
|
data = {'data': [{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux', 'x': 'bye'}]}
|
|
urlopen.side_effect = lambda *args: io.StringIO(json.dumps(data))
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/foo/')
|
|
assert 'f1' in resp.form.fields
|
|
assert 'f2' not in resp.form.fields
|
|
resp.form['f1'] = '2'
|
|
|
|
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',
|
|
'result': 'error',
|
|
}
|
|
|
|
live_resp = app.post('/foo/live', params=resp.form.submit_fields())
|
|
assert live_resp.json == {'result': {'1': {'visible': True}, '2': {'visible': True}}}
|
|
|
|
|
|
def test_comment_from_card_field(pub):
|
|
create_user(pub)
|
|
|
|
CardDef.wipe()
|
|
carddef = CardDef()
|
|
carddef.name = 'Template'
|
|
carddef.digest_templates = {'default': '{{ form_var_template }}'}
|
|
carddef.fields = [
|
|
fields.StringField(id='0', label='string', varname='template'),
|
|
]
|
|
carddef.store()
|
|
carddef.data_class().wipe()
|
|
for i, value in enumerate(['foo', 'bar']):
|
|
carddata = carddef.data_class()()
|
|
carddata.data = {
|
|
'0': "%s {{ form_var_foo }}" % value,
|
|
}
|
|
carddata.just_created()
|
|
carddata.store()
|
|
|
|
ds = {'type': 'carddef:%s' % carddef.url_name}
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'test'
|
|
formdef.fields = [
|
|
fields.StringField(id='0', label='string', varname='foo'),
|
|
fields.ItemField(id='1', label='card', type='item', varname='card', data_source=ds),
|
|
fields.CommentField(
|
|
id='3',
|
|
label='X{{ form_var_card_live_var_template }}Y{{ form_var_card_live_var_template|as_template }}Z',
|
|
type='comment',
|
|
),
|
|
]
|
|
formdef.store()
|
|
formdef.data_class().wipe()
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/test/')
|
|
resp.form['f0'] = 'plop'
|
|
resp.form['f1'] = '1'
|
|
live_resp = app.post('/test/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['3']['content'] == '<p>Xfoo {{ form_var_foo }}Yfoo plopZ</p>'
|
|
resp.form['f1'] = '2'
|
|
live_resp = app.post('/test/live', params=resp.form.submit_fields())
|
|
assert live_resp.json['result']['3']['content'] == '<p>Xbar {{ form_var_foo }}Ybar plopZ</p>'
|