__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3"
import json
import requests
from django import forms
from django.core.exceptions import ValidationError
from django.conf import settings
from django.contrib.postgres.fields import ArrayField
from django.utils.encoding import force_text
from .widgets import ReCaptcha
[docs]class ChoiceArrayField(ArrayField):
"""
A field that allows us to store an array of choices.
Uses Django 1.9's postgres ArrayField
and a MultipleChoiceField for its formfield.
"""
[docs]class ReCaptchaField(forms.CharField):
default_error_messages = {
'captcha_invalid': 'Incorrect, please try again.',
'captcha_error': 'Error verifying input, please try again.',
}
def __init__(self, use_ssl=None, attrs=None, *args, **kwargs):
"""
ReCaptchaField can accepts attributes which is a dictionary of
attributes to be passed to the ReCaptcha widget class. The widget will
loop over any options added and create the RecaptchaOptions
JavaScript variables as specified in
https://developers.google.com/recaptcha/docs/display#render_param
"""
if attrs is None:
attrs = {}
public_key = settings.RECAPTCHA_PUBLIC_KEY
self.use_ssl = getattr(settings, 'RECAPTCHA_USE_SSL', True)
self.widget = ReCaptcha(public_key=public_key, attrs=attrs)
self.required = True
self.verify_url = 'https://www.recaptcha.net/recaptcha/api/siteverify'
super().__init__(*args, **kwargs)
[docs] def clean(self, values):
super().clean(values[0])
recaptcha_response = force_text(values[0])
if not self.required:
return
data = {
'secret': settings.RECAPTCHA_PRIVATE_KEY,
'response': recaptcha_response
}
r = requests.post(
self.verify_url,
data=data,
headers={
'Content-type': 'application/x-www-form-urlencoded',
'User-agent': 'reCAPTCHA Python'
})
try:
r.raise_for_status()
response = r.json()
catpcha_success = response.get('success', False)
except (requests.exceptions.HTTPError, requests.exceptions.Timeout):
raise ValidationError(
self.error_messages['captcha_error']
)
if not catpcha_success:
raise ValidationError(
self.error_messages['captcha_invalid']
)
return values[0]
[docs]class UserModelChoiceField(forms.ModelChoiceField):
[docs] def label_from_instance(self, obj):
return '{}, {} ({})'.format(obj.last_name, obj.first_name, obj.email)