diff --git a/coderedcms/forms.py b/coderedcms/forms.py index e56cf2ed..ce184276 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,21 @@ class CoderedTimeField(forms.TimeField): class CoderedFormBuilder(FormBuilder): + CAPTCHA_FIELD_NAME = 'wagtailcaptcha' """ 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 + 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 +135,12 @@ 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) + 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..dc50b239 100755 --- a/coderedcms/models/page_models.py +++ b/coderedcms/models/page_models.py @@ -1489,6 +1489,16 @@ 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 + 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 +1695,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/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/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 %} 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: 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 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