From a66ac88b68f4cea8da2177ed303de786bf9c98ec Mon Sep 17 00:00:00 2001 From: pppls Date: Tue, 28 Sep 2021 18:40:34 +0200 Subject: [PATCH 1/5] Implement the functionality for a simple captcha, based on https://github.com/acarasimon96/wagtail-django-simple-captcha and https://github.com/springload/wagtail-django-recaptcha --- coderedcms/forms.py | 14 ++++++++++++++ coderedcms/models/page_models.py | 10 +++++++++- requirements-dev.txt | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/coderedcms/forms.py b/coderedcms/forms.py index e56cf2ed..30908cfa 100755 --- a/coderedcms/forms.py +++ b/coderedcms/forms.py @@ -4,6 +4,7 @@ import csv import os import re +from captcha.fields import CaptchaField from django import forms from django.core.exceptions import ValidationError from django.db import models @@ -107,10 +108,19 @@ class CoderedTimeField(forms.TimeField): class CoderedFormBuilder(FormBuilder): + CAPTCHA_FIELD_NAME = 'wagtailcaptcha' """ Enhance wagtail FormBuilder with additional custom fields. """ + @property + def formfields(self): + # Add wagtailcaptcha to formfields property + fields = super(CoderedFormBuilder, self).formfields + fields[self.CAPTCHA_FIELD_NAME] = CaptchaField(label='') + + return fields + def create_file_field(self, field, options): return SecureFileField(**options) @@ -123,6 +133,10 @@ def create_datetime_field(self, field, options): def create_time_field(self, field, options): return CoderedTimeField(**options) + @staticmethod + def remove_captcha_field(form): + form.fields.pop(CoderedFormBuilder.CAPTCHA_FIELD_NAME, None) + form.cleaned_data.pop(CoderedFormBuilder.CAPTCHA_FIELD_NAME, None) class CoderedSubmissionsListView(WagtailSubmissionsListView): def get_csv_response(self, context): diff --git a/coderedcms/models/page_models.py b/coderedcms/models/page_models.py index abfeea1f..78f58aa1 100755 --- a/coderedcms/models/page_models.py +++ b/coderedcms/models/page_models.py @@ -1489,6 +1489,14 @@ def __init__(self, *args, **kwargs): name, ext = os.path.splitext(self.template) self.landing_page_template = name + '_landing' + ext + def process_form_submission(self, request, form, form_submission, processed_data): + """ + Change process_form_submission function such that + captcha is removed upon submission + """ + CoderedFormBuilder.remove_captcha_field(form) + return super(CoderedFormPage, self).process_form_submission(request, form, form_submission, processed_data) + def get_form_fields(self): """ Form page expects `form_fields` to be declared. @@ -1685,7 +1693,7 @@ class Meta: CoderedFormMixin.body_content_panels + [ InlinePanel('confirmation_emails', label=_('Confirmation Emails')) ] - + def process_form_post(self, form, request): if form.is_valid(): is_complete = self.steps.update_data() diff --git a/requirements-dev.txt b/requirements-dev.txt index 9145c393..396138ac 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,3 +5,4 @@ libsass twine wheel +django-simple-captcha \ No newline at end of file From 8edb16edfc3242694c7aae4498cc07bdefe85a6d Mon Sep 17 00:00:00 2001 From: pppls Date: Sat, 2 Oct 2021 10:51:03 +0200 Subject: [PATCH 2/5] add working basic, sass, and test project_template for inclusion of captcha --- .../project_template/basic/project_name/settings/base.py | 3 +++ coderedcms/project_template/basic/project_name/urls.py | 4 ++++ .../project_template/basic/website/migrations/0001_initial.py | 3 +++ .../project_template/sass/project_name/settings/base.py | 4 ++++ coderedcms/project_template/sass/project_name/urls.py | 3 +++ .../project_template/sass/website/migrations/0001_initial.py | 3 +++ coderedcms/tests/settings.py | 3 +++ coderedcms/tests/urls.py | 3 +++ 8 files changed, 26 insertions(+) diff --git a/coderedcms/project_template/basic/project_name/settings/base.py b/coderedcms/project_template/basic/project_name/settings/base.py index a31e86e2..2206ac0c 100755 --- a/coderedcms/project_template/basic/project_name/settings/base.py +++ b/coderedcms/project_template/basic/project_name/settings/base.py @@ -25,6 +25,9 @@ # Application definition INSTALLED_APPS = [ + #django-simple-catpcha + 'captcha', + # This project 'website', diff --git a/coderedcms/project_template/basic/project_name/urls.py b/coderedcms/project_template/basic/project_name/urls.py index c59759a4..db3e2df2 100644 --- a/coderedcms/project_template/basic/project_name/urls.py +++ b/coderedcms/project_template/basic/project_name/urls.py @@ -17,6 +17,9 @@ # Search path('search/', include(coderedsearch_urls)), + # Captcha + path('captcha/', include('captcha.urls')), + # For anything not caught by a more specific rule above, hand over to # the page serving mechanism. This should be the last pattern in # the list: @@ -25,6 +28,7 @@ # Alternatively, if you want CMS pages to be served from a subpath # of your site, rather than the site root: # re_path(r"^pages/", include(codered_urls)), + ] diff --git a/coderedcms/project_template/basic/website/migrations/0001_initial.py b/coderedcms/project_template/basic/website/migrations/0001_initial.py index 3d9c090a..2871e72f 100644 --- a/coderedcms/project_template/basic/website/migrations/0001_initial.py +++ b/coderedcms/project_template/basic/website/migrations/0001_initial.py @@ -6,6 +6,8 @@ """ {% endcomment %} {% verbatim %} +# Generated by Django 3.2.7 on 2021-10-01 17:27 + import coderedcms.blocks.base_blocks import coderedcms.blocks.html_blocks from django.conf import settings @@ -136,4 +138,5 @@ class Migration(migrations.Migration): bases=('coderedcms.coderedpage',), ), ] + {% endverbatim %} diff --git a/coderedcms/project_template/sass/project_name/settings/base.py b/coderedcms/project_template/sass/project_name/settings/base.py index 5b9ec0ff..2d69c860 100644 --- a/coderedcms/project_template/sass/project_name/settings/base.py +++ b/coderedcms/project_template/sass/project_name/settings/base.py @@ -24,6 +24,9 @@ # Application definition INSTALLED_APPS = [ + #django-simple-captcha + 'captcha', + # This project 'website', @@ -61,6 +64,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', "django.contrib.sitemaps", + ] MIDDLEWARE = [ diff --git a/coderedcms/project_template/sass/project_name/urls.py b/coderedcms/project_template/sass/project_name/urls.py index 1e2276c5..a358adec 100644 --- a/coderedcms/project_template/sass/project_name/urls.py +++ b/coderedcms/project_template/sass/project_name/urls.py @@ -17,6 +17,9 @@ # Search path('search/', include(coderedsearch_urls)), + # Captcha + path('captcha/', include('captcha.urls')), + # For anything not caught by a more specific rule above, hand over to # the page serving mechanism. This should be the last pattern in # the list: diff --git a/coderedcms/project_template/sass/website/migrations/0001_initial.py b/coderedcms/project_template/sass/website/migrations/0001_initial.py index 3d9c090a..2871e72f 100644 --- a/coderedcms/project_template/sass/website/migrations/0001_initial.py +++ b/coderedcms/project_template/sass/website/migrations/0001_initial.py @@ -6,6 +6,8 @@ """ {% endcomment %} {% verbatim %} +# Generated by Django 3.2.7 on 2021-10-01 17:27 + import coderedcms.blocks.base_blocks import coderedcms.blocks.html_blocks from django.conf import settings @@ -136,4 +138,5 @@ class Migration(migrations.Migration): bases=('coderedcms.coderedpage',), ), ] + {% endverbatim %} diff --git a/coderedcms/tests/settings.py b/coderedcms/tests/settings.py index 32bf5068..9843fd9f 100755 --- a/coderedcms/tests/settings.py +++ b/coderedcms/tests/settings.py @@ -63,6 +63,9 @@ 'django.contrib.messages', 'django.contrib.staticfiles', "django.contrib.sitemaps", + + #django-simple-catpcha + 'captcha', ] MIDDLEWARE = [ diff --git a/coderedcms/tests/urls.py b/coderedcms/tests/urls.py index c8692307..3894ee2f 100755 --- a/coderedcms/tests/urls.py +++ b/coderedcms/tests/urls.py @@ -16,6 +16,9 @@ # Search path('search/', include(coderedsearch_urls)), + # Captcha + path('captcha/', include('captcha.urls')), + # For anything not caught by a more specific rule above, hand over to # the page serving mechanism. This should be the last pattern in # the list: From dc4139c132e4cb9320cf2fd39c5738dd35d29d76 Mon Sep 17 00:00:00 2001 From: pppls Date: Sat, 2 Oct 2021 11:42:37 +0200 Subject: [PATCH 3/5] add doc --- docs/features/page_types/form_pages.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/page_types/form_pages.rst b/docs/features/page_types/form_pages.rst index fc3fee87..7190aa4d 100755 --- a/docs/features/page_types/form_pages.rst +++ b/docs/features/page_types/form_pages.rst @@ -59,4 +59,4 @@ Settings Tab * **Form go live date/time**: The optional date/time the form will start appearing on the page. * **Form expiry date/time**: The optional date/time the form will stop appearing on the page. -* **Spam Protection**: When toggled on, this will engage spam protection techniques to attempt to reduce spam form submissions. \ No newline at end of file +* **Spam Protection**: When toggled on, this will engage spam protection techniques to attempt to reduce spam form submissions and add a captcha to the form. \ No newline at end of file From 5f7531c2281c5b089865b2bbc596e24002fb7c2f Mon Sep 17 00:00:00 2001 From: pppls Date: Sat, 2 Oct 2021 11:55:35 +0200 Subject: [PATCH 4/5] clearly demarcate outside code from other open-source projects --- coderedcms/forms.py | 4 ++++ coderedcms/models/page_models.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/coderedcms/forms.py b/coderedcms/forms.py index 30908cfa..ce184276 100755 --- a/coderedcms/forms.py +++ b/coderedcms/forms.py @@ -113,6 +113,8 @@ class CoderedFormBuilder(FormBuilder): Enhance wagtail FormBuilder with additional custom fields. """ + # The following function is sourced from https://github.com/acarasimon96/wagtail-django-simple-captcha + # with small tweeks to integrate with the CodeRedCMS codebase (under the MIT license) @property def formfields(self): # Add wagtailcaptcha to formfields property @@ -133,6 +135,8 @@ def create_datetime_field(self, field, options): def create_time_field(self, field, options): return CoderedTimeField(**options) + # The following function is sourced from https://github.com/acarasimon96/wagtail-django-simple-captcha + # with small tweeks to integrate with the CodeRedCMS codebase (under the MIT license) @staticmethod def remove_captcha_field(form): form.fields.pop(CoderedFormBuilder.CAPTCHA_FIELD_NAME, None) diff --git a/coderedcms/models/page_models.py b/coderedcms/models/page_models.py index 78f58aa1..dc50b239 100755 --- a/coderedcms/models/page_models.py +++ b/coderedcms/models/page_models.py @@ -1489,6 +1489,8 @@ def __init__(self, *args, **kwargs): name, ext = os.path.splitext(self.template) self.landing_page_template = name + '_landing' + ext + # The following function is sourced from https://github.com/acarasimon96/wagtail-django-simple-captcha + # with small tweeks to integrate with the CodeRedCMS codebase (under the MIT License) def process_form_submission(self, request, form, form_submission, processed_data): """ Change process_form_submission function such that From 7a5288cc160de25408df88b625f8da706c1aa983 Mon Sep 17 00:00:00 2001 From: pppls Date: Sat, 2 Oct 2021 13:14:50 +0200 Subject: [PATCH 5/5] Make it so the captcha is not available when spam_protection is disabled --- coderedcms/templates/coderedcms/pages/form_page.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coderedcms/templates/coderedcms/pages/form_page.html b/coderedcms/templates/coderedcms/pages/form_page.html index 2d02e350..87bc081a 100755 --- a/coderedcms/templates/coderedcms/pages/form_page.html +++ b/coderedcms/templates/coderedcms/pages/form_page.html @@ -11,11 +11,12 @@
{% csrf_token %} - {% bootstrap_form form layout='horizontal' %} + {% bootstrap_form form layout='horizontal' exclude='wagtailcaptcha'%} {% block captcha %} {% if page.spam_protection %} {% include 'coderedcms/includes/form_honeypot.html' %} + {% bootstrap_field form.wagtailcaptcha layout='horizontal' %} {% endif %} {% endblock %}