From f8436313ec22d781b2fc9d11b71b43805c2d584c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Tue, 18 Aug 2015 11:09:33 +0200 Subject: [PATCH 1/2] forms: add a new option to prepend a CAPTCHA page for anonymous users (#7859) --- tests/test_form_pages.py | 30 ++++++++++++++++++++++++++++++ wcs/admin/forms.py | 7 ++++++- wcs/formdef.py | 4 +++- wcs/forms/root.py | 31 +++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py index aa49cd4..54f3ae4 100644 --- a/tests/test_form_pages.py +++ b/tests/test_form_pages.py @@ -941,3 +941,33 @@ query_string_allowed_vars = foo,bar assert resp.location == 'http://example.net/?foo=bar' os.unlink(os.path.join(pub.app_dir, 'site-options.cfg')) + +def test_form_captcha(pub): + user = create_user(pub) + formdef = create_formdef() + formdef.data_class().wipe() + formdef.fields = [fields.StringField(id='0', label='Some field')] + formdef.has_captcha = True + formdef.store() + + # test authentic users are not presented with a captcha + resp = login(get_app(pub), username='foo', password='foo').get('/') + resp = resp.click('test') + assert 'Some field' in resp.body + + # check anonymous user gets the captcha + app = get_app(pub) + resp = app.get('/') + resp = resp.click('test') + assert 'form_captcha' in resp.body + + session_id = app.cookies.values()[0].strip('"') + session = BasicSession.get(session_id) + resp.forms[0]['captcha$q'] = session.get_captcha_token(resp.forms[0]['captcha$token'].value)['answer'] + resp = resp.forms[0].submit() + assert 'Some field' in resp.body + + # and check it gets it only once + resp = app.get('/') + resp = resp.click('test') + assert 'Some field' in resp.body diff --git a/wcs/admin/forms.py b/wcs/admin/forms.py index 4435b51..6305a40 100644 --- a/wcs/admin/forms.py +++ b/wcs/admin/forms.py @@ -355,6 +355,8 @@ class FormDefPage(Directory): r += htmltext('
  • %s
  • ') % _('Publication Date: %s') % self.formdef.publication_date if self.formdef.expiration_date: r += htmltext('
  • %s
  • ') % _('Expiration Date: %s') % self.formdef.expiration_date + if self.formdef.has_captcha: + r += htmltext('
  • %s
  • ') % _('Add CAPTCHA for anonymous users') r += htmltext('') r += htmltext('') r += htmltext('') @@ -596,6 +598,9 @@ class FormDefPage(Directory): form.add(DateTimeWidget, 'expiration_date', title=_('Expiration Date'), value=self.formdef.expiration_date) + form.add(CheckboxWidget, 'has_captcha', + title=_('Prepend a CAPTCHA page for anonymous users'), + value=self.formdef.has_captcha) form.add_submit('submit', _('Submit')) form.add_submit('cancel', _('Cancel')) @@ -606,7 +611,7 @@ class FormDefPage(Directory): attrs = ['confirmation', 'only_allow_one', 'disabled', 'enable_tracking_codes', 'private_status_and_history', 'disabled_redirection', 'publication_date', - 'expiration_date', 'always_advertise'] + 'expiration_date', 'always_advertise', 'has_captcha'] for f in attrs: widget = form.get_widget(f) if widget: diff --git a/wcs/formdef.py b/wcs/formdef.py index 97a66cf..90ffd94 100644 --- a/wcs/formdef.py +++ b/wcs/formdef.py @@ -77,6 +77,7 @@ class FormDef(StorableObject): always_advertise = False publication_date = None expiration_date = None + has_captcha = False acl_read = 'owner' # one of ('none', 'owner', 'roles', 'all') private_status_and_history = False @@ -92,7 +93,8 @@ class FormDef(StorableObject): 'disabled_redirection',] BOOLEAN_ATTRIBUTES = ['discussion', 'detailed_emails', 'disabled', 'only_allow_one', 'enable_tracking_codes', - 'always_advertise', 'private_status_and_history'] + 'always_advertise', 'private_status_and_history', + 'has_captcha'] def migrate(self): changed = False diff --git a/wcs/forms/root.py b/wcs/forms/root.py index b5c4ea7..aa682c4 100644 --- a/wcs/forms/root.py +++ b/wcs/forms/root.py @@ -291,12 +291,34 @@ class FormPage(Directory): r += htmltext('') return r.getvalue() + def initial_captcha_page(self): + form = Form() + form.add_captcha(hint='') + form.add_submit('submit', _('Next')) + form.add_submit('cancel', _('Cancel')) + + if form.get_submit() == 'cancel': + return redirect(get_publisher().get_root_url()) + + if not form.is_submitted() or form.has_errors(): + html_top(self.formdef.name) + r = TemplateIO(html=True) + r += TextsDirectory.get_html_text('captcha-page') + r += form.render() + return r.getvalue() + + return self.page(0) + def page(self, page_no, page_change = True, log_detail = None, editing = None): r = TemplateIO(html=True) displayed_fields = [] session = get_session() + if page_no == 0 and self.formdef.has_captcha: + if not session.get_user() and not session.won_captcha: + return self.initial_captcha_page() + if page_no > 0: magictoken = get_request().form['magictoken'] self.feed_current_data(magictoken) @@ -1356,6 +1378,15 @@ TextsDirectory.register('welcome-logged', TextsDirectory.register('welcome-unlogged', N_('Welcome text on home page for unlogged users')) +TextsDirectory.register('captcha-page', + N_('Explanation text on the CAPTCHA page'), + default = N_('''

    Verification

    + +

    +In order to proceed you need to complete this simple question. +

    ''')) + + TextsDirectory.register('form-recorded', N_('Message when a form has been recorded'), hint = N_('Available variables: date, number'), -- 2.5.0