__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)