forms: don't let autosave() replace values that were submitted later on (#9701)
This commit is contained in:
parent
926780efa6
commit
92e5188522
|
@ -2089,6 +2089,21 @@ def test_form_autosave(pub):
|
|||
assert formdef.data_class().select()[0].data['1'] == 'foobar3'
|
||||
assert formdef.data_class().select()[0].data['3'] == 'xxx3'
|
||||
|
||||
# make sure autosave() doesn't destroy data that would have been submitted
|
||||
# in the meantime
|
||||
formdef.data_class().wipe()
|
||||
app = get_app(pub)
|
||||
resp = app.get('/test/')
|
||||
resp.form['f1'] = 'foobar'
|
||||
autosave_fields = resp.form.submit_fields()
|
||||
resp.form['f1'] = 'foobar3'
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert formdef.data_class().select()[0].data['1'] == 'foobar3'
|
||||
|
||||
# post content with 'foobar' as value, it should not be saved
|
||||
ajax_resp = app.post('/test/autosave', params=autosave_fields)
|
||||
assert json.loads(ajax_resp.body)['result'] == 'error'
|
||||
assert formdef.data_class().select()[0].data['1'] == 'foobar3'
|
||||
|
||||
def test_file_field_validation(pub, fargo_url):
|
||||
user = create_user(pub)
|
||||
|
|
|
@ -30,7 +30,8 @@ try:
|
|||
except ImportError:
|
||||
qrcode = None
|
||||
|
||||
from quixote import get_publisher, get_request, get_response, get_session, redirect
|
||||
from quixote import (get_publisher, get_request, get_response, get_session,
|
||||
get_session_manager, redirect)
|
||||
from quixote.directory import Directory, AccessControlled
|
||||
from quixote.util import randbytes
|
||||
from quixote.form.widget import *
|
||||
|
@ -344,6 +345,8 @@ class FormPage(Directory):
|
|||
self.feed_current_data(magictoken)
|
||||
|
||||
form = self.formdef.create_form(page_no, displayed_fields)
|
||||
if getattr(session, 'ajax_form_token', None):
|
||||
form.add_hidden('_ajax_form_token', session.ajax_form_token)
|
||||
if get_request().is_in_backoffice():
|
||||
form.attrs['data-is-backoffice'] = 'true'
|
||||
form.action = self.action_url
|
||||
|
@ -512,6 +515,18 @@ class FormPage(Directory):
|
|||
return redirect(self.check_disabled())
|
||||
|
||||
session = get_session()
|
||||
if self.formdef.enable_tracking_codes:
|
||||
if get_request().form.get('_ajax_form_token'):
|
||||
# _ajax_form_token is immediately removed, this prevents
|
||||
# late autosave() to overwrite data after the user went to a
|
||||
# different page.
|
||||
try:
|
||||
session.remove_form_token(get_request().form.get('_ajax_form_token'))
|
||||
except ValueError:
|
||||
# already got removed, this may be because the form got
|
||||
# submitted twice.
|
||||
pass
|
||||
session.ajax_form_token = session.create_form_token()
|
||||
|
||||
if get_request().form.get('magictoken'):
|
||||
no_magic = object()
|
||||
|
@ -808,6 +823,9 @@ class FormPage(Directory):
|
|||
def result_error(reason):
|
||||
return json.dumps({'result': 'error', 'reason': reason})
|
||||
|
||||
if not get_session().has_form_token(get_request().form.get('_ajax_form_token')):
|
||||
return result_error('obsolete ajax form token')
|
||||
|
||||
try:
|
||||
page_no = int(get_request().form.get('page'))
|
||||
except TypeError:
|
||||
|
@ -831,6 +849,12 @@ class FormPage(Directory):
|
|||
return result_error('nothing to save')
|
||||
|
||||
form_data.update(data)
|
||||
|
||||
# reload session to make sure _ajax_form_token is still valid
|
||||
session = get_session_manager().get(get_session().id)
|
||||
if not session.has_form_token(get_request().form.get('_ajax_form_token')):
|
||||
return result_error('obsolete ajax form token (late check)')
|
||||
|
||||
draft_formdata = self.save_draft(form_data, page_no)
|
||||
|
||||
return json.dumps({'result': 'success'})
|
||||
|
|
Loading…
Reference in New Issue