# HG changeset patch
# User Brian Neal
# Date 1523731985 18000
# Node ID b957e4829a03f9a4e722c925d2c17a1b7cbeca5a
# Parent b213e4b333bb1feece054832c4066dfafa3fca1a
Add reCAPTCHA to contact form
diff -r b213e4b333bb -r b957e4829a03 contact/forms.py
--- a/contact/forms.py Mon Jan 01 10:39:48 2018 -0600
+++ b/contact/forms.py Sat Apr 14 13:53:05 2018 -0500
@@ -1,12 +1,20 @@
"""forms for the contact application"""
+import logging
+
from django import forms
from django.conf import settings
from django.template.loader import render_to_string
from django.contrib.sites.models import Site
+import requests
+
+from core.functions import get_ip
from core.functions import send_mail
+logger = logging.getLogger(__name__)
+
+
class ContactForm(forms.Form):
"""Form used to contact the website admins"""
name=forms.CharField(label="Your Name")
@@ -20,12 +28,34 @@
recipient_list = [mail_tuple[1] for mail_tuple in settings.MANAGERS]
+ def __init__(self, *args, **kwargs):
+ self.request = kwargs.pop('request', None)
+ super(ContactForm, self).__init__(*args, **kwargs)
+
def clean_honeypot(self):
value = self.cleaned_data['honeypot']
if value:
raise forms.ValidationError(self.fields['honeypot'].label)
return value
+ def clean(self):
+ super(ContactForm, self).clean()
+ captcha_response = self.request.POST.get('g-recaptcha-response')
+ if not captcha_response:
+ raise forms.ValidationError('Missing reCAPTCHA response')
+ r = requests.post(settings.RECAPTCHA_URL, data={
+ 'secret': settings.RECAPTCHA_SECRET_KEY,
+ 'response': captcha_response,
+ 'remoteip': get_ip(self.request),
+ })
+ result = r.json()
+ logger.info("Contact Form captcha response: %s %s",
+ result.get('success', ''),
+ result.get('error-codes', ''))
+ success = result.get('success', False)
+ if not success:
+ raise forms.ValidationError('reCAPTCHA failure')
+
def save(self):
# Send the feedback message email
diff -r b213e4b333bb -r b957e4829a03 contact/tests/test_views.py
--- a/contact/tests/test_views.py Mon Jan 01 10:39:48 2018 -0600
+++ b/contact/tests/test_views.py Sat Apr 14 13:53:05 2018 -0500
@@ -2,7 +2,9 @@
Unit tests for the contact application views.
"""
+from mock import patch, Mock
from django.test import TestCase
+from django.conf import settings
from django.core.urlresolvers import reverse
from django.core import mail
@@ -10,9 +12,16 @@
class BaseTestCase(TestCase):
"""Simple tests to ensure basic functionality."""
- def test_usage(self):
- url = reverse('contact-form')
- response = self.client.get(url)
+ def setUp(self):
+ self.url = reverse('contact-form')
+
+ @patch('contact.forms.requests.post')
+ def test_usage(self, post_mock):
+ post_response = Mock()
+ post_response.json.return_value = {'success': True}
+ post_mock.return_value = post_response
+
+ response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
post_data = {
@@ -20,8 +29,9 @@
'email': 'jdoe@example.com',
'subject': 'Test message',
'message': 'Testing contact form.',
+ 'g-recaptcha-response': 'crazy-google-string',
}
- response = self.client.post(url, data=post_data, follow=True)
+ response = self.client.post(self.url, data=post_data, follow=True)
self.assertRedirects(response, reverse('contact-thanks'))
self.assertEqual(len(mail.outbox), 1)
@@ -36,8 +46,13 @@
self.assertTrue(post_data['email'] in msg)
self.assertTrue(post_data['message'] in msg)
+ post_mock.assert_called_once_with(settings.RECAPTCHA_URL, data={
+ 'secret': settings.RECAPTCHA_SECRET_KEY,
+ 'response': 'crazy-google-string',
+ 'remoteip': '127.0.0.1',
+ })
+
def test_honeypot(self):
- url = reverse('contact-form')
post_data = {
'name': 'John Doe',
'email': 'jdoe@example.com',
@@ -45,6 +60,34 @@
'message': 'Testing contact form.',
'honeypot': 'some spam',
}
- response = self.client.post(url, data=post_data)
+ response = self.client.post(self.url, data=post_data)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(mail.outbox), 0)
+
+ def test_no_captcha_response(self):
+ post_data = {
+ 'name': 'John Doe',
+ 'email': 'jdoe@example.com',
+ 'subject': 'Test message',
+ 'message': 'Testing contact form.',
+ }
+ response = self.client.post(self.url, data=post_data, follow=True)
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(len(mail.outbox), 0)
+
+ @patch('contact.forms.requests.post')
+ def test_captcha_failure(self, post_mock):
+ post_response = Mock()
+ post_response.json.return_value = {'success': False}
+ post_mock.return_value = post_response
+
+ post_data = {
+ 'name': 'John Doe',
+ 'email': 'jdoe@example.com',
+ 'subject': 'Test message',
+ 'message': 'Testing contact form.',
+ 'g-recaptcha-response': 'crazy-google-string',
+ }
+ response = self.client.post(self.url, data=post_data, follow=True)
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(len(mail.outbox), 0)
diff -r b213e4b333bb -r b957e4829a03 contact/views.py
--- a/contact/views.py Mon Jan 01 10:39:48 2018 -0600
+++ b/contact/views.py Sat Apr 14 13:53:05 2018 -0500
@@ -1,5 +1,6 @@
"""Views for the contact application."""
+from django.conf import settings
from django.shortcuts import redirect, render
from django.views.generic import TemplateView
@@ -9,7 +10,7 @@
def contact_form(request):
if request.method == 'POST':
- form = ContactForm(request.POST)
+ form = ContactForm(request.POST, request=request)
if form.is_valid():
form.save()
return redirect('contact-thanks')
@@ -26,10 +27,11 @@
if subject:
initial_data['subject'] = subject
- form = ContactForm(initial=initial_data)
+ form = ContactForm(initial=initial_data, request=request)
return render(request, 'contact/contact_form.html', {
'form': form,
+ 'RECAPTCHA_SITE_KEY': settings.RECAPTCHA_SITE_KEY,
'V3_DESIGN': True,
})
diff -r b213e4b333bb -r b957e4829a03 sg101/settings/base.py
--- a/sg101/settings/base.py Mon Jan 01 10:39:48 2018 -0600
+++ b/sg101/settings/base.py Sat Apr 14 13:53:05 2018 -0500
@@ -311,6 +311,11 @@
# useful when we are rebuilding the search index.
SEARCH_QUEUE_ENABLED = True
+# Google reCAPTCHA settings
+RECAPTCHA_URL = 'https://www.google.com/recaptcha/api/siteverify'
+RECAPTCHA_SITE_KEY = SECRETS['RECAPTCHA_SITE_KEY']
+RECAPTCHA_SECRET_KEY = SECRETS['RECAPTCHA_SECRET_KEY']
+
#######################################################################
# Asynchronous settings (queues, queued_search, redis, celery, etc)
#######################################################################
diff -r b213e4b333bb -r b957e4829a03 sg101/templates/contact/contact_form.html
--- a/sg101/templates/contact/contact_form.html Mon Jan 01 10:39:48 2018 -0600
+++ b/sg101/templates/contact/contact_form.html Sat Apr 14 13:53:05 2018 -0500
@@ -10,9 +10,6 @@