Code comments are potentially mine.
1. def register in apps/users/views.py
@anonymous_csrf def register(request): if request.user.is_authenticated(): messages.info(request, _("You are already logged in to an account.")) form = None elif request.method == 'POST': form = forms.UserRegisterForm(request.POST) # Always have recaptcha if form.is_valid(): # is_valid() does all the form clean() ... [save form stuff] ... else: form = forms.UserRegisterForm() return jingo.render(request, 'users/register.html', {'form': form, })
2. UserRegisterForm has ReCaptchaField. File: apps/users/forms.py
import captcha.fields class UserRegisterForm(happyforms.ModelForm, PasswordMixin): passwords ... recaptcha = captcha.fields.ReCaptchaField() ... irrelevent stuff ...
3. captcha.fields.ReCaptchaField() in zamboni/vendors (not shown on zamboni github), but it's on Mozilla's django-recaptcha
from django.conf import settings from django import forms from django.utils.encoding import smart_unicode from django.utils.translation import ugettext_lazy as _ from recaptcha.client import captcha from captcha.widgets import ReCaptcha class ReCaptchaField(forms.CharField): default_error_messages = { 'captcha_invalid': _(u'Invalid captcha') } def __init__(self, *args, **kwargs): self.widget = ReCaptcha self.required = True super(ReCaptchaField, self).__init__(*args, **kwargs) def clean(self, values): super(ReCaptchaField, self).clean(values[1]) recaptcha_challenge_value = smart_unicode(values[0]) recaptcha_response_value = smart_unicode(values[1]) check_captcha = captcha.submit(recaptcha_challenge_value, recaptcha_response_value, settings.RECAPTCHA_PRIVATE_KEY, {}) if not check_captcha.is_valid: raise forms.util.ValidationError( self.error_messages['captcha_invalid']) return values[0]
Which, btw is exactly what I have for my ReCaptchaField. The ReCaptcha widget will ultimately introduce an in-body javascript.
Click to read more about ReCaptcha and In-Line Javascript / CSP
So the only difference in reCaptcha is how it's displayed on the html page. Let's investigate.
4. Register page template: apps/users/templates/users/register.html, taken from step 1 views.py
{% block js %}{% include("amo/recaptcha_js.html") %}{% endblock %} ... {% if settings.RECAPTCHA_PRIVATE_KEY %} {{ recaptcha(form) }} {% else %} <p> Welcome Robots, ReCaptcha has been disabled for your convenience. Spam at Wil. </p> {% endif %}The apps/amo/templates/amo/recaptcha_js.html has:
{% if request.user.is_anonymous() %} <script type="text/javascript" src="{{ settings.RECAPTCHA_URL }}"></script> {% endif %}where
# in settings.py RECAPTCHA_PUBLIC_KEY = "blah" RECAPTCHA_PRIVATE_KEY = "blah" RECAPTCHA_URL = ('https://www.google.com/recaptcha/api/challenge?k=%s' % RECAPTCHA_PUBLIC_KEY)
Unless you have the private key (which bots don't), you can see the recaptcha form.
5. def recaptcha() in apps/amo/helpers.py
Read about the inclusion_tag
@register.inclusion_tag('amo/recaptcha.html') @jinja2.contextfunction def recaptcha(context, form): d = dict(context.items()) d.update(form=form) return d
6. recaptcha.html lives in apps/amo/templates/amo/recaptcha.hhtml"
{% from 'includes/forms.html' import required %} <label for="recaptcha_response_field"> {{ _('Are you human?') }} {{ required() }} </label> {% trans %} <p> Please enter <strong>both words</strong> below, <strong>separated by a space</strong>. </p> <p> If this is hard to read, you can <a href="#" id="recaptcha_different">try different words</a> or <a href="#" id="recaptcha_audio">listen to something</a> instead. </p> {% endtrans %} <div id="recaptcha_image"></div> <p> <input type="text" name="recaptcha_response_field" id="recaptcha_response_field" size="30" /> </p> <p><a href="#" id="recaptcha_help">{{ _("What's this?") }}</a></p> {{ form.recaptcha.errors }}
7. div ids link to function in javascript here: media/js/zamboni/users.js
// Recaptcha var RecaptchaOptions = { theme : 'custom' }; $('#recaptcha_different').click(function(e) { e.preventDefault(); Recaptcha.reload(); }); $('#recaptcha_audio').click(function(e) { e.preventDefault(); Recaptcha.switch_type('audio'); }); $('#recaptcha_help').click(function(e) { e.preventDefault(); Recaptcha.showhelp(); });These Recaptcha's functions are defined in Google's recaptcha.
No comments:
Post a Comment