forms: prevent autosave from overwriting session's data (#58208)
gitea-wip/wcs/pipeline/head Build started... Details
gitea/wcs/pipeline/head Something is wrong with the build of this commit Details

This commit is contained in:
Frédéric Péters 2021-11-05 16:31:20 +01:00 committed by Benjamin Dauvergne
parent 827d7d4898
commit d9f1f6e378
3 changed files with 59 additions and 4 deletions

View File

@ -4567,6 +4567,53 @@ def test_form_autosave_with_parameterized_datasource(pub):
assert formdef.data_class().select()[0].data['3_display'] == 'barbar'
def test_form_autosave_never_overwrite(mocker, pub, settings):
create_user(pub)
formdef = create_formdef()
formdef.data_class().wipe()
formdef.fields = [
fields.PageField(id='0', label='1st page', type='page'),
fields.StringField(id='1', label='string1'),
fields.PageField(id='2', label='2nd page', type='page'),
fields.StringField(id='3', label='string2'),
]
formdef.store()
app = get_app(pub)
login(app, username='foo', password='foo')
resp = app.get('/test/')
resp.form.set('f1', '1')
# go to the second page
resp = resp.form.submit('submit')
resp.form.set('f3', '1')
# autosave wrong data
autosave_data = dict(resp.form.submit_fields())
autosave_data['f3'] = 'wtf!'
resp_autosave = app.post('/test/autosave', params=autosave_data)
assert resp_autosave.json == {'result': 'success'}
# check the draft is fucked
data = formdef.data_class().select()[0].data
assert data['3'] == 'wtf!'
# now finish submitting
resp = resp.form.submit('submit') # -> validation page
# autosave wrong data
# _ajax_form_token is just a form_token, so take the current one to
# simulate a rogue autosave from the second page
autosave_data['_ajax_form_token'] = resp.form['_form_id'].value
resp_autosave = app.post('/test/autosave', params=autosave_data)
assert resp_autosave.json == {'result': 'success'}
data = formdef.data_class().select()[0].data
assert data['3'] == 'wtf!'
# validate
resp = resp.form.submit('submit') # -> submit
# great everything is still fine in the end
assert formdef.data_class().select()[0].data == {'1': '1', '3': '1'}
def test_form_string_field_autocomplete(pub):
formdef = create_formdef()
formdef.fields = [fields.StringField(id='0', label='string', type='string', required=False)]

View File

@ -1354,9 +1354,9 @@ class FormPage(Directory, FormTemplateMixin):
def autosave(self):
get_response().set_content_type('application/json')
get_request().ignore_session = True
def result_error(reason):
get_request().ignore_session = True
return json.dumps({'result': 'error', 'reason': reason})
ajax_form_token = get_request().form.get('_ajax_form_token')
@ -1418,6 +1418,7 @@ class FormPage(Directory, FormTemplateMixin):
def save_draft(self, data, page_no=None):
filled = self.get_current_draft() or self.formdef.data_class()()
new_draft = bool(filled.id is None)
if filled.id and filled.status != 'draft':
raise SubmittedDraftException()
filled.data = data
@ -1436,9 +1437,12 @@ class FormPage(Directory, FormTemplateMixin):
filled.store()
if not filled.user_id:
get_session().mark_anonymous_formdata(filled)
if get_session().mark_anonymous_formdata(filled):
get_session().store()
data['draft_formdata_id'] = filled.id
if new_draft:
data['draft_formdata_id'] = filled.id
get_session().store()
self.set_tracking_code(filled, data)
get_logger().info('form %s - saving draft (id: %s)' % (self.formdef.name, filled.id))

View File

@ -59,7 +59,11 @@ class BasicSession(Session):
def mark_anonymous_formdata(self, formdata):
if not self.anonymous_formdata_keys:
self.anonymous_formdata_keys = {}
self.anonymous_formdata_keys[formdata.get_object_key()] = True
key = formdata.get_object_key()
if key not in self.anonymous_formdata_keys:
self.anonymous_formdata_keys[key] = True
return True
return False
def is_anonymous_submitter(self, formdata):
if not self.anonymous_formdata_keys: