misc: re-prefill if value was not modified (#28117)
This commit is contained in:
parent
b517204ca0
commit
0c04b5e3ee
|
@ -2826,6 +2826,101 @@ def test_form_page_formula_prefill_items_field(pub):
|
|||
assert resp.form['f0$element2'].checked
|
||||
|
||||
|
||||
def test_form_page_changing_prefill(pub):
|
||||
formdef = create_formdef()
|
||||
formdef.data_class().wipe()
|
||||
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.StringField(id='3', label='string 2',
|
||||
prefill={'type': 'string', 'value': '{{ form_var_foo }} World'}),
|
||||
fields.PageField(id='4', label='3rd page', type='page'),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
resp.form['f1'] = 'Hello'
|
||||
resp = resp.form.submit('submit') # -> 2nd page
|
||||
assert resp.form['f3'].value == 'Hello World'
|
||||
resp = resp.form.submit('submit') # -> 3rd page
|
||||
resp = resp.form.submit('previous') # back to 2nd page
|
||||
assert resp.form['f3'].value == 'Hello World'
|
||||
resp = resp.form.submit('previous') # back to 1st page
|
||||
assert resp.form['f1'].value == 'Hello'
|
||||
resp.form['f1'] = 'Goodbye Cruel'
|
||||
resp = resp.form.submit('submit') # -> 2nd page
|
||||
assert resp.form['f3'].value == 'Goodbye Cruel World'
|
||||
resp = resp.form.submit('submit') # -> 3rd page
|
||||
resp = resp.form.submit('previous') # back to 2nd page
|
||||
resp.form['f3'].value = 'Changed value'
|
||||
resp = resp.form.submit('previous') # back to 1st page
|
||||
resp = resp.form.submit('submit') # -> 2nd page
|
||||
assert resp.form['f3'].value == 'Changed value'
|
||||
resp = resp.form.submit('submit') # -> 3rd page
|
||||
resp = resp.form.submit('submit') # -> 2nd page
|
||||
assert resp.form['f3'].value == 'Changed value'
|
||||
|
||||
|
||||
def test_form_page_changing_prefill_draft(pub):
|
||||
formdef = create_formdef()
|
||||
formdef.data_class().wipe()
|
||||
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.StringField(id='3', label='string 2',
|
||||
prefill={'type': 'string', 'value': '{{ form_var_foo }} World'}),
|
||||
fields.PageField(id='4', label='3rd page', type='page'),
|
||||
]
|
||||
formdef.enable_tracking_codes = True
|
||||
formdef.store()
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
resp.form['f1'] = 'Hello'
|
||||
resp = resp.form.submit('submit') # -> 2nd page
|
||||
assert resp.form['f3'].value == 'Hello World'
|
||||
resp = resp.form.submit('submit') # -> 3rd page
|
||||
resp = resp.form.submit('previous') # back to 2nd page
|
||||
assert resp.form['f3'].value == 'Hello World'
|
||||
resp = resp.form.submit('submit') # -> 3rd page
|
||||
tracking_code = get_displayed_tracking_code(resp)
|
||||
|
||||
# start with a new session and restore draft using the tracking code
|
||||
resp = get_app(pub).get('/')
|
||||
resp.form['code'] = tracking_code
|
||||
resp = resp.form.submit().follow().follow().follow()
|
||||
assert_current_page(resp, '3rd page')
|
||||
resp = resp.forms[1].submit('previous') # back to 2nd page
|
||||
assert resp.forms[1]['f3'].value == 'Hello World'
|
||||
resp = resp.forms[1].submit('previous') # back to 1st page
|
||||
assert resp.forms[1]['f1'].value == 'Hello'
|
||||
resp.forms[1]['f1'] = 'Goodbye Cruel'
|
||||
resp = resp.forms[1].submit('submit') # -> 2nd page
|
||||
assert resp.forms[1]['f3'].value == 'Goodbye Cruel World'
|
||||
|
||||
|
||||
def test_prefill_query_parameter(pub):
|
||||
formdef = create_formdef()
|
||||
formdef.data_class().wipe()
|
||||
formdef.fields = [
|
||||
fields.PageField(id='0', label='1st page', type='page'),
|
||||
fields.StringField(id='1', label='str',
|
||||
varname='foo', required=False,
|
||||
prefill={'type': 'string', 'value': '{{request.GET.prefill}}'}),
|
||||
fields.PageField(id='2', label='2nd page', type='page'),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
resp = get_app(pub).get('/test/?prefill=Hello')
|
||||
assert resp.form['f1'].value == 'Hello'
|
||||
resp = resp.form.submit('submit') # -> 2nd page
|
||||
resp = resp.form.submit('previous') # back to 1st page
|
||||
# check it has not be reset to the empty string (as there's no request.GET
|
||||
# anymore)
|
||||
assert resp.form['f1'].value == 'Hello'
|
||||
|
||||
|
||||
def test_form_captcha(pub):
|
||||
user = create_user(pub)
|
||||
formdef = create_formdef()
|
||||
|
|
|
@ -279,8 +279,8 @@ class FormFillPage(PublicFormFillPage):
|
|||
formdata.remove_self()
|
||||
return redirect(url)
|
||||
|
||||
def save_draft(self, data, page_no):
|
||||
formdata = super(FormFillPage, self).save_draft(data, page_no)
|
||||
def save_draft(self, data, page_no=None):
|
||||
formdata = super(FormFillPage, self).save_draft(data, page_no=page_no)
|
||||
formdata.backoffice_submission = True
|
||||
if not formdata.submission_context:
|
||||
formdata.submission_context = {}
|
||||
|
|
|
@ -244,6 +244,7 @@ class FormData(StorableObject):
|
|||
criticality_level = 0
|
||||
digest = None
|
||||
|
||||
prefilling_data = None
|
||||
workflow_data = None
|
||||
workflow_roles = None
|
||||
geolocations = None
|
||||
|
|
|
@ -311,6 +311,7 @@ class FormStatusPage(Directory, FormTemplateMixin):
|
|||
# add back file to session
|
||||
tempfile = session.add_tempfile(form_data[field.id], storage=field.storage)
|
||||
form_data[field.id].token = tempfile['token']
|
||||
form_data['prefilling_data'] = filled.prefilling_data or {}
|
||||
form_data['is_recalled_draft'] = True
|
||||
form_data['draft_formdata_id'] = filled.id
|
||||
form_data['page_no'] = filled.page_no
|
||||
|
|
|
@ -377,9 +377,20 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
# "live prefill", regardless of existing data.
|
||||
form.get_widget('f%s' % k).prefill_attributes = field.get_prefill_attributes()
|
||||
|
||||
should_prefill = bool(field.prefill)
|
||||
|
||||
if k in data:
|
||||
# existing value, update it with the new computed value
|
||||
# if it's the same that was previously computed.
|
||||
prefill_value = v
|
||||
v = data[k]
|
||||
elif field.prefill:
|
||||
if data.get('prefilling_data', {}).get(k) == data[k]:
|
||||
# replace value with new value computed for prefill
|
||||
v = prefill_value
|
||||
else:
|
||||
should_prefill = False
|
||||
|
||||
if should_prefill:
|
||||
if get_request().is_in_backoffice() and (
|
||||
field.prefill and field.prefill.get('type') == 'geoloc'):
|
||||
# turn off prefilling from geolocation attributes if
|
||||
|
@ -393,6 +404,12 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
form.get_widget('f%s' % k).clear_error()
|
||||
|
||||
if v is not None:
|
||||
# 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'][k] = v
|
||||
if not isinstance(v, str) and field.convert_value_to_str:
|
||||
v = field.convert_value_to_str(v)
|
||||
form.get_widget('f%s' % k).set_value(v)
|
||||
|
@ -412,6 +429,9 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
# include prefilled data
|
||||
transient_formdata = self.get_transient_formdata()
|
||||
transient_formdata.data.update(self.formdef.get_data(form))
|
||||
if self.has_draft_support():
|
||||
# save to get prefilling data in database
|
||||
self.save_draft(form_data)
|
||||
else:
|
||||
req.form = {}
|
||||
|
||||
|
@ -553,6 +573,7 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
formdata._formdef = self.formdef
|
||||
formdata.user = get_request().user
|
||||
formdata.data = get_session().get_by_magictoken(magictoken, {})
|
||||
formdata.prefilling_data = formdata.data.get('prefilling_data', {})
|
||||
|
||||
if self.edit_mode:
|
||||
# keep associated user as it may be required as a parameter in
|
||||
|
@ -1117,13 +1138,15 @@ class FormPage(Directory, FormTemplateMixin):
|
|||
|
||||
return json.dumps({'result': 'success'})
|
||||
|
||||
def save_draft(self, data, page_no):
|
||||
def save_draft(self, data, page_no=None):
|
||||
filled = self.get_current_draft() or self.formdef.data_class()()
|
||||
if filled.id and filled.status != 'draft':
|
||||
raise SubmittedDraftException()
|
||||
filled.data = data
|
||||
filled.prefilling_data = data.get('prefilling_data')
|
||||
filled.status = 'draft'
|
||||
filled.page_no = page_no
|
||||
if page_no is not None:
|
||||
filled.page_no = page_no
|
||||
filled.receipt_time = time.localtime()
|
||||
session = get_session()
|
||||
if get_request().is_in_backoffice():
|
||||
|
|
34
wcs/sql.py
34
wcs/sql.py
|
@ -488,7 +488,7 @@ def do_formdef_tables(formdef, conn=None, cur=None, rebuild_views=False, rebuild
|
|||
'actions_roles_array', 'backoffice_submission',
|
||||
'submission_context', 'submission_agent_id', 'submission_channel',
|
||||
'criticality_level', 'last_update_time',
|
||||
'digest', 'user_label'])
|
||||
'digest', 'user_label', 'prefilling_data',])
|
||||
|
||||
# migrations
|
||||
if not 'fts' in existing_fields:
|
||||
|
@ -538,6 +538,9 @@ def do_formdef_tables(formdef, conn=None, cur=None, rebuild_views=False, rebuild
|
|||
if not 'user_label' in existing_fields:
|
||||
cur.execute('''ALTER TABLE %s ADD COLUMN user_label varchar''' % table_name)
|
||||
|
||||
if 'prefilling_data' not in existing_fields:
|
||||
cur.execute('''ALTER TABLE %s ADD COLUMN prefilling_data bytea''' % table_name)
|
||||
|
||||
# add new fields
|
||||
for field in formdef.get_all_fields():
|
||||
assert field.id is not None
|
||||
|
@ -1484,6 +1487,7 @@ class SqlDataMixin(SqlMixin):
|
|||
('page_no', 'varchar'),
|
||||
('anonymised', 'timestamptz'),
|
||||
('workflow_data', 'bytea'),
|
||||
('prefilling_data', 'bytea'),
|
||||
('id_display', 'varchar'),
|
||||
('workflow_roles', 'bytea'),
|
||||
('workflow_roles_array', 'text[]'),
|
||||
|
@ -1586,12 +1590,13 @@ class SqlDataMixin(SqlMixin):
|
|||
'user_id': self.user_id,
|
||||
'status': self.status,
|
||||
'page_no': self.page_no,
|
||||
'workflow_data': bytearray(pickle.dumps(self.workflow_data, protocol=2)),
|
||||
'workflow_data': self.workflow_data,
|
||||
'id_display': self.id_display,
|
||||
'anonymised': self.anonymised,
|
||||
'tracking_code': self.tracking_code,
|
||||
'backoffice_submission': self.backoffice_submission,
|
||||
'submission_context': self.submission_context,
|
||||
'prefilling_data': self.prefilling_data,
|
||||
'submission_agent_id': self.submission_agent_id,
|
||||
'submission_channel': self.submission_channel,
|
||||
'criticality_level': self.criticality_level,
|
||||
|
@ -1605,15 +1610,14 @@ class SqlDataMixin(SqlMixin):
|
|||
else:
|
||||
sql_dict['receipt_time'] = None
|
||||
if self.workflow_roles:
|
||||
sql_dict['workflow_roles'] = bytearray(pickle.dumps(self.workflow_roles, protocol=2))
|
||||
sql_dict['workflow_roles_array'] = [str(x) for x in self.workflow_roles.values() if x is not None]
|
||||
else:
|
||||
sql_dict['workflow_roles'] = None
|
||||
sql_dict['workflow_roles_array'] = None
|
||||
if self.submission_context:
|
||||
sql_dict['submission_context'] = bytearray(pickle.dumps(self.submission_context, protocol=2))
|
||||
else:
|
||||
sql_dict['submission_context'] = None
|
||||
for attr in ('workflow_data', 'workflow_roles', 'submission_context', 'prefilling_data'):
|
||||
if getattr(self, attr):
|
||||
sql_dict[attr] = bytearray(pickle.dumps(getattr(self, attr), protocol=2))
|
||||
else:
|
||||
sql_dict[attr] = None
|
||||
|
||||
for field in (self._formdef.geolocations or {}).keys():
|
||||
value = (self.geolocations or {}).get(field)
|
||||
|
@ -1753,12 +1757,9 @@ class SqlDataMixin(SqlMixin):
|
|||
setattr(o, static_field[0], str_encode(value))
|
||||
if o.receipt_time:
|
||||
o.receipt_time = o.receipt_time.timetuple()
|
||||
if o.workflow_data:
|
||||
o.workflow_data = pickle_loads(o.workflow_data)
|
||||
if o.workflow_roles:
|
||||
o.workflow_roles = pickle_loads(o.workflow_roles)
|
||||
if o.submission_context:
|
||||
o.submission_context = pickle_loads(o.submission_context)
|
||||
for attr in ('workflow_data', 'workflow_roles', 'submission_context', 'prefilling_data'):
|
||||
if getattr(o, attr):
|
||||
setattr(o, attr, pickle_loads(getattr(o, attr)))
|
||||
|
||||
o.geolocations = {}
|
||||
for i, field in enumerate((cls._formdef.geolocations or {}).keys()):
|
||||
|
@ -2679,7 +2680,7 @@ def get_yearly_totals(period_start=None, period_end=None, criterias=None):
|
|||
return result
|
||||
|
||||
|
||||
SQL_LEVEL = 42
|
||||
SQL_LEVEL = 43
|
||||
|
||||
|
||||
def migrate_global_views(conn, cur):
|
||||
|
@ -2753,7 +2754,7 @@ def migrate():
|
|||
raise RuntimeError()
|
||||
if sql_level < 1: # 1: introduction of tracking_code table
|
||||
do_tracking_code_table()
|
||||
if sql_level < 38:
|
||||
if sql_level < 43:
|
||||
# 2: introduction of formdef_id in views
|
||||
# 5: add concerned_roles_array, is_at_endpoint and fts to views
|
||||
# 7: add backoffice_submission to tables
|
||||
|
@ -2772,6 +2773,7 @@ def migrate():
|
|||
# 31: add user_label to formdata
|
||||
# 33: add anonymised field to global view
|
||||
# 38: extract submission_agent_id to its own column
|
||||
# 43: add prefilling_data to formdata
|
||||
migrate_views(conn, cur)
|
||||
if sql_level < 40:
|
||||
# 3: introduction of _structured for user fields
|
||||
|
|
Loading…
Reference in New Issue