forms: always enable drafts (#27476)

This commit is contained in:
Frédéric Péters 2018-10-19 16:03:16 +02:00
parent 1bcfd42502
commit 08ea74c03c
5 changed files with 66 additions and 50 deletions

View File

@ -1369,7 +1369,7 @@ def test_user_drafts(pub, local_user):
formdef.store()
resp = get_app(pub).get(sign_uri('/api/user/drafts', user=local_user))
assert resp.json['err'] == 0
assert len(resp.json['data']) == 0
assert len(resp.json['data']) == 1
formdef.enable_tracking_codes = True
formdef.disabled = True

View File

@ -1715,12 +1715,6 @@ def test_form_direct_draft_access(pub):
formdata.store()
resp = login(get_app(pub), 'foo', 'foo').get('/test/%s' % formdata.id, status=403)
formdata.user_id = user.id
formdata.store()
formdef.enable_tracking_codes = False
formdef.store()
resp = login(get_app(pub), 'foo', 'foo').get('/test/%s' % formdata.id, status=403)
def form_password_field_submit(pub, password):
password = unicode(password).encode(pub.site_charset)
formdef = create_formdef()
@ -1959,7 +1953,7 @@ def test_preview_form(pub):
next_page = next_page.forms[0].submit('submit')
assert next_page.status_int == 302
assert next_page.location == 'http://example.net/preview/test/'
assert formdef.data_class().count() == 0
assert len([x for x in formdef.data_class().select() if not x.is_draft()]) == 0
def test_form_item_data_source_field_submit(pub):
def submit_item_data_source_field(ds):
@ -4388,8 +4382,9 @@ def test_form_page_profile_verified_prefill(pub):
resp.form['f0'].value = 'Hello' # try again changing the value
resp = resp.form.submit('submit')
assert formdef.data_class().count() == 1
assert formdef.data_class().select()[0].data['0'] == 'foo@localhost'
formdatas = [x for x in formdef.data_class().select() if not x.is_draft()]
assert len(formdatas) == 1
assert formdatas[0].data['0'] == 'foo@localhost'
resp = login(get_app(pub), username='foo', password='foo').get('/test/')
assert resp.form['f0'].value == 'foo@localhost'
@ -4444,8 +4439,9 @@ def test_form_page_profile_verified_date_prefill(pub):
resp.form['f0'].value = '2018-09-24' # try again changing the value
resp = resp.form.submit('submit')
assert formdef.data_class().count() == 1
assert time.strftime('%Y-%m-%d', formdef.data_class().select()[0].data['0']) == '2018-09-27'
formdatas = [x for x in formdef.data_class().select() if not x.is_draft()]
assert len(formdatas) == 1
assert time.strftime('%Y-%m-%d', formdatas[0].data['0']) == '2018-09-27'
def test_form_page_profile_verified_radio_item_prefill(pub):
user = create_user(pub)

View File

@ -611,7 +611,7 @@ class ApiUserDirectory(Directory):
if form.is_draft():
if not include_drafts:
continue
if form.formdef.is_disabled() or not form.formdef.enable_tracking_codes:
if form.formdef.is_disabled():
# the form or its draft support has been disabled
continue
elif not include_non_drafts:

View File

@ -232,6 +232,14 @@ class FormPage(Directory, FormTemplateMixin):
return True
return False
def has_draft_support(self):
if self.edit_mode:
return False
if self.formdef.enable_tracking_codes:
return True
session = get_session()
return session.has_user()
def step(self, step_no, current_page):
get_logger().info('form %s - step %s' % (self.formdef.name, step_no))
@ -284,7 +292,7 @@ class FormPage(Directory, FormTemplateMixin):
magictoken = get_request().form.get('magictoken')
if magictoken:
form_data = session.get_by_magictoken(magictoken, {})
if self.formdef.enable_tracking_codes and not self.edit_mode:
if self.has_draft_support():
form.attrs['data-has-draft'] = 'yes'
else:
form_data = {}
@ -400,7 +408,7 @@ class FormPage(Directory, FormTemplateMixin):
form.add_hidden('page_id', page.id)
form.add_submit('cancel', _('Cancel'), css_class = 'cancel')
if self.formdef.enable_tracking_codes and not self.edit_mode:
if self.has_draft_support():
form.add_submit('savedraft', _('Save Draft'), css_class = 'save-draft',
attrs={'style': 'display: none'})
@ -410,7 +418,7 @@ class FormPage(Directory, FormTemplateMixin):
'form_side': lambda: self.form_side(0, page, data=data, magictoken=magictoken),
'steps': lambda: self.step(0, page),
}
if self.formdef.enable_tracking_codes and data:
if self.has_draft_support() and data:
context['tracking_code_box'] = lambda: self.tracking_code_box(data, magictoken)
return template.QommonTemplateResponse(
@ -422,7 +430,7 @@ class FormPage(Directory, FormTemplateMixin):
(tracking code and steps).'''
r = TemplateIO(html=True)
r += htmltext('<div id="side">')
if self.formdef.enable_tracking_codes and data:
if self.has_draft_support() and data:
# display tracking code box if they are enabled and there's some
# data (e.g. the user is not on a insufficient authenticiation
# context page)
@ -433,33 +441,39 @@ class FormPage(Directory, FormTemplateMixin):
def tracking_code_box(self, data, magictoken):
'''Create the tracking code box, it displays the current tracking code
and a 'remove draft' button if the current form is a draft that has
been recalled.'''
if enabled, and a 'remove draft' button if the current form is a draft
that has been recalled.'''
r = TemplateIO(html=True)
r += htmltext('<div id="tracking-code">')
r += htmltext('<h3>%s</h3>') % _('Tracking code')
if self.formdef.enable_tracking_codes:
r += htmltext('<div class="tracking-code-part">')
r += htmltext('<h3>%s</h3>') % _('Tracking code')
tracking_code = None
draft_formdata_id = data.get('draft_formdata_id')
if draft_formdata_id:
formdata = self.formdef.data_class().get(draft_formdata_id)
tracking_code = formdata.tracking_code
else:
tracking_code = data.get('future_tracking_code')
tracking_code = None
draft_formdata_id = data.get('draft_formdata_id')
if draft_formdata_id:
formdata = self.formdef.data_class().get(draft_formdata_id)
tracking_code = formdata.tracking_code
else:
tracking_code = data.get('future_tracking_code')
if tracking_code:
get_response().add_javascript(['jquery.js', 'jquery-ui.js', 'popup.js'])
r += htmltext('<a rel="popup" href="%s">%s</a>') % (
'code/%s/' % tracking_code, tracking_code)
r += TextsDirectory.get_html_text('tracking-code-short-text')
if tracking_code:
get_response().add_javascript(['jquery.js', 'jquery-ui.js', 'popup.js'])
r += htmltext('<a rel="popup" href="%s">%s</a>') % (
'code/%s/' % tracking_code, tracking_code)
r += TextsDirectory.get_html_text('tracking-code-short-text')
r += htmltext('</div>') # <!-- .tracking-code-part -->
if data.get('is_recalled_draft'):
r += htmltext('<form action="removedraft" method="POST">')
r += htmltext('<input type="hidden" name="magictoken" value="%s">') % magictoken
r += htmltext('<button>%s</button>') % _('Remove Draft')
r += htmltext('</form>')
r += htmltext('</div>') # <!-- #tracking-code -->
return r.getvalue()
text = r.getvalue()
if not text:
return ''
return htmltext('<div id="tracking-code">') + text + htmltext('</div>')
def get_transient_formdata(self, magictoken=Ellipsis):
if magictoken is Ellipsis:
@ -559,7 +573,7 @@ class FormPage(Directory, FormTemplateMixin):
# [session_var_id] is available on the first page.
session.force()
if self.formdef.enable_tracking_codes:
if self.has_draft_support():
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
@ -592,7 +606,7 @@ class FormPage(Directory, FormTemplateMixin):
# first hit on first page, if tracking code are enabled and we
# are not editing an existing formdata, generate a new tracking
# code.
if not self.edit_mode and self.formdef.enable_tracking_codes and not get_request().form.has_key('mt'):
if not self.edit_mode and self.has_draft_support() and not get_request().form.has_key('mt'):
tracking_code = get_publisher().tracking_code_class()
tracking_code.store()
token = randbytes(8)
@ -622,7 +636,7 @@ class FormPage(Directory, FormTemplateMixin):
form.add_hidden('magictoken', '-1')
form.add_submit('cancel')
if self.formdef.enable_tracking_codes:
if self.has_draft_support():
form.add_submit('removedraft')
form.add_submit('savedraft')
@ -723,21 +737,21 @@ class FormPage(Directory, FormTemplateMixin):
displayed_fields=submitted_fields,
transient_formdata=transient_formdata)
form.add_submit('previous')
if self.formdef.enable_tracking_codes:
if self.has_draft_support():
form.add_submit('removedraft')
form.add_submit('savedraft')
form.add_submit('submit')
if page_no > 0 and form.get_submit() == 'previous':
return self.previous_page(page_no, magictoken)
if self.formdef.enable_tracking_codes and form.get_submit() == 'removedraft':
if self.has_draft_support() and form.get_submit() == 'removedraft':
return self.removedraft()
form_data = session.get_by_magictoken(magictoken, {})
data = self.formdef.get_data(form)
form_data.update(data)
if self.formdef.enable_tracking_codes and form.get_submit() == 'savedraft':
if self.has_draft_support() and form.get_submit() == 'savedraft':
filled = self.save_draft(form_data, page_no)
return redirect(filled.get_url().rstrip('/'))
@ -796,8 +810,8 @@ class FormPage(Directory, FormTemplateMixin):
get_session().message = ('error', _('This form has already been submitted.'))
return redirect(get_publisher().get_backoffice_url() + '/submission/')
return template.error_page(_('This form has already been submitted.'))
elif self.formdef.enable_tracking_codes and not self.edit_mode:
# if there's no draft yet and tracking codes are enabled, create one
elif self.has_draft_support():
# if there's no draft yet and drafts are supported, create one
filled = self.save_draft(form_data, page_no)
# the page has been successfully submitted, maybe new pages
@ -828,7 +842,7 @@ class FormPage(Directory, FormTemplateMixin):
form.add_hidden('page', '-1')
form.add_hidden('magictoken', '-1')
form.add_submit('cancel')
if self.formdef.enable_tracking_codes:
if self.has_draft_support():
form.add_submit('removedraft')
form.add_submit('savedraft')
@ -863,10 +877,10 @@ class FormPage(Directory, FormTemplateMixin):
if form.get_submit() == 'previous':
return self.previous_page(len(self.pages), magictoken)
if self.formdef.enable_tracking_codes and form.get_submit() == 'removedraft':
if self.has_draft_support() and form.get_submit() == 'removedraft':
return self.removedraft()
if self.formdef.enable_tracking_codes and form.get_submit() == 'savedraft':
if self.has_draft_support() and form.get_submit() == 'savedraft':
filled = self.save_draft(form_data, page_no = -1)
return redirect(filled.get_url().rstrip('/'))
@ -1114,7 +1128,7 @@ class FormPage(Directory, FormTemplateMixin):
return redirect(url)
def set_tracking_code(self, formdata, magictoken_data=None):
if not self.formdef.enable_tracking_codes:
if not self.has_draft_support():
return
if formdata.tracking_code:
return
@ -1185,7 +1199,7 @@ class FormPage(Directory, FormTemplateMixin):
form.add_submit('previous', _('Previous'))
form.add_submit('cancel', _('Cancel'), css_class = 'cancel')
session = get_session()
if self.formdef.enable_tracking_codes:
if self.has_draft_support():
form.add_submit('savedraft', _('Save Draft'), css_class = 'save-draft',
attrs={'style': 'display: none'})
form.add_hidden('step', '2')
@ -1199,7 +1213,7 @@ class FormPage(Directory, FormTemplateMixin):
magictoken=magictoken),
'steps': lambda: self.step(1, None),
}
if self.formdef.enable_tracking_codes and data:
if self.has_draft_support() and data:
context['tracking_code_box'] = lambda: self.tracking_code_box(data, magictoken)
return template.QommonTemplateResponse(
@ -1234,7 +1248,7 @@ class FormPage(Directory, FormTemplateMixin):
return redirect(get_publisher().get_backoffice_url() + '/submission/')
return PublicFormStatusPage(self.formdef, filled)
if not (get_request().is_in_backoffice() or filled.formdef.enable_tracking_codes):
if not (get_request().is_in_backoffice() or self.has_draft_support()):
# don't allow restoring drafts if drafts are no longer enabled for
# this form.
raise errors.AccessForbiddenError()

View File

@ -195,6 +195,12 @@ class Session(QommonSession, CaptchaSession, StorableObject):
except OSError:
pass
def has_user(self):
user_id = QuixoteSession.get_user(self)
if user_id and not str(user_id).startswith('anonymous-'):
return True
return False
def get_user(self):
user_id = QuixoteSession.get_user(self)
if user_id: