*Code wurde PEP-8 gerecht formatiert * Kleine Fehler die der PyCharm Inspector beanstandet wurden korrigiert
270 lines
8.6 KiB
Python
270 lines
8.6 KiB
Python
"""
|
|
Created on 08.05.2011
|
|
|
|
@author: christian
|
|
"""
|
|
import re
|
|
|
|
from django.conf import settings
|
|
from django.core import validators
|
|
from django.core.validators import EMPTY_VALUES
|
|
from django.forms import util, Form, ModelForm, ValidationError # @UnusedImport
|
|
import django.forms.fields
|
|
from django.utils.translation import gettext as _
|
|
|
|
from . import widgets
|
|
|
|
|
|
class Html5Mixin(object):
|
|
def widget_attrs(self, widget):
|
|
"""
|
|
Overwrites the standard Widget Attributes to add some HTML5 Stuff
|
|
:param widget: A Widget Object
|
|
"""
|
|
attrs = super(Html5Mixin, self).widget_attrs(widget)
|
|
if self.required and not isinstance(widget, widgets.CheckboxInput):
|
|
attrs['required'] = 'required'
|
|
if self.help_text:
|
|
attrs['title'] = self.help_text
|
|
attrs['placeholder'] = self.help_text
|
|
if self.accesskey:
|
|
attrs['accesskey'] = self.accesskey
|
|
return attrs
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.accesskey = kwargs.pop('accesskey', None)
|
|
super(Html5Mixin, self).__init__(*args, **kwargs)
|
|
|
|
|
|
class AutoCompleteSelectField(Html5Mixin, django.forms.Field):
|
|
widget = widgets.AutoCompleteSelectWidget
|
|
default_error_messages = {
|
|
'invalid_choice': _(u'Select a valid choice. That choice is not one \
|
|
of the available choices.'),
|
|
}
|
|
|
|
def __init__(self, lookup_class, *args, **kwargs):
|
|
self.lookup_class = lookup_class
|
|
self.allow_new = kwargs.pop('allow_new', False)
|
|
if not kwargs['widget']:
|
|
kwargs['widget'] = self.widget(lookup_class,
|
|
allow_new=self.allow_new)
|
|
super(AutoCompleteSelectField, self).__init__(*args, **kwargs)
|
|
|
|
def to_python(self, value):
|
|
if value in EMPTY_VALUES:
|
|
return None
|
|
if isinstance(value, list):
|
|
# Input comes from an AutoComplete widget. It's two
|
|
# components: text and id
|
|
if len(value) != 2:
|
|
raise django.forms.ValidationError(
|
|
self.error_messages['invalid_choice'])
|
|
lookup = self.lookup_class()
|
|
if value[1] in EMPTY_VALUES:
|
|
if not self.allow_new:
|
|
if value[0]:
|
|
raise django.forms.ValidationError(
|
|
self.error_messages['invalid_choice'])
|
|
else:
|
|
return None
|
|
value = lookup.create_item(value[0])
|
|
else:
|
|
value = lookup.get_item(value[1])
|
|
if value is None:
|
|
raise django.forms.ValidationError(
|
|
self.error_messages['invalid_choice'])
|
|
return value
|
|
|
|
|
|
class AutoComboboxSelectField(AutoCompleteSelectField):
|
|
widget = widgets.AutoComboboxSelectWidget
|
|
|
|
|
|
class AutoCompleteSelectMultipleField(Html5Mixin, django.forms.Field):
|
|
widget = widgets.AutoCompleteSelectMultipleWidget
|
|
|
|
default_error_messages = {
|
|
'invalid_choice': _(u'Select a valid choice. \
|
|
That choice is not one of the available choices.'),
|
|
}
|
|
|
|
def __init__(self, lookup_class, *args, **kwargs):
|
|
self.lookup_class = lookup_class
|
|
kwargs['widget'] = self.widget(lookup_class)
|
|
self.attrs['autofocus'] = 'autofocus'
|
|
super(AutoCompleteSelectMultipleField, self).__init__(*args, **kwargs)
|
|
|
|
def to_python(self, value):
|
|
if value in EMPTY_VALUES:
|
|
return None
|
|
lookup = self.lookup_class()
|
|
items = []
|
|
for v in value:
|
|
if v not in EMPTY_VALUES:
|
|
item = lookup.get_item(v)
|
|
if item is None:
|
|
raise django.forms.ValidationError(
|
|
self.error_messages['invalid_choice'])
|
|
items.append(item)
|
|
return items
|
|
|
|
|
|
class AutoComboboxSelectMultipleField(AutoCompleteSelectMultipleField):
|
|
widget = widgets.AutoComboboxSelectMultipleWidget
|
|
|
|
|
|
class BooleanField(Html5Mixin, django.forms.BooleanField):
|
|
widget = widgets.CheckboxInput
|
|
|
|
|
|
class CharField(Html5Mixin, django.forms.CharField):
|
|
pass
|
|
|
|
|
|
class DateField(Html5Mixin, django.forms.fields.DateField):
|
|
widget = widgets.DateInput
|
|
|
|
|
|
class DateTimeField(Html5Mixin, django.forms.fields.DateTimeField):
|
|
widget = widgets.DateTimeInput
|
|
|
|
|
|
class EmailField(Html5Mixin, django.forms.fields.EmailField):
|
|
widget = widgets.EmailInput
|
|
|
|
|
|
class FileField(Html5Mixin, django.forms.fields.FileField):
|
|
widget = widgets.NumberInput
|
|
pass
|
|
|
|
|
|
class FloatField(Html5Mixin, django.forms.fields.FloatField):
|
|
pass
|
|
|
|
|
|
class HiddenInput(Html5Mixin, django.forms.HiddenInput):
|
|
pass
|
|
|
|
|
|
class IntegerField(Html5Mixin, django.forms.fields.IntegerField):
|
|
widget = widgets.NumberInput
|
|
|
|
def widget_attrs(self, widget):
|
|
attrs = super(IntegerField, self).widget_attrs(widget)
|
|
if isinstance(widget, widgets.NumberInput):
|
|
if self.min_value is not None:
|
|
attrs['min'] = self.min_value
|
|
if self.max_value is not None:
|
|
attrs['max'] = self.max_value
|
|
return attrs
|
|
|
|
|
|
class ModelChoiceField(Html5Mixin, django.forms.ModelChoiceField):
|
|
pass
|
|
|
|
|
|
class PasswordInput(Html5Mixin, django.forms.PasswordInput):
|
|
pass
|
|
|
|
|
|
class PhoneField(Html5Mixin, django.forms.CharField):
|
|
widget = widgets.PhoneInput
|
|
|
|
def __init__(self, regex=None, max_length=None, min_length=None,
|
|
error_message=None, *args, **kwargs):
|
|
super(PhoneField, self).__init__(max_length, min_length,
|
|
*args, **kwargs)
|
|
self._set_regex(u'^[0-9+-/ ]+$')
|
|
|
|
def _get_regex(self):
|
|
return self._regex
|
|
|
|
def _set_regex(self, regex=u'^[0-9+-/ ]+$'):
|
|
regex = re.compile(regex, re.UNICODE)
|
|
self._regex = regex
|
|
if hasattr(self, '_regex_validator') \
|
|
and self._regex_validator in self.validators:
|
|
self.validators.remove(self._regex_validator)
|
|
self._regex_validator = validators.RegexValidator(regex=regex)
|
|
self.validators.append(self._regex_validator)
|
|
|
|
regex = property(_get_regex, _set_regex)
|
|
|
|
|
|
class ReCaptchaField(django.forms.fields.CharField):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.widget = widgets.ReCaptchaInput
|
|
self.required = True
|
|
super(ReCaptchaField, self).__init__(*args, **kwargs)
|
|
|
|
def _check_recaptcha(self, challenge_value, response_value, remote_ip):
|
|
"""
|
|
Submits a reCAPTCHA request for verification.
|
|
Returns RecaptchaResponse for the request
|
|
|
|
@param challenge_value: value of recaptcha_challenge_field
|
|
@param response_value: value of recaptcha_response_field
|
|
@param remoteip -- the user's ip address
|
|
|
|
"""
|
|
import urllib
|
|
import urllib2
|
|
private_key = settings.RECAPTCHA_PRIVATE_KEY
|
|
challenge_value = challenge_value.encode('utf-8')
|
|
response_value = response_value.encode('utf-8')
|
|
params = urllib.urlencode({
|
|
'privatekey': private_key,
|
|
'remoteip': remote_ip,
|
|
'challenge': challenge_value,
|
|
'response': response_value,
|
|
})
|
|
|
|
request = urllib2.Request(
|
|
url="http://www.google.com/recaptcha/api/verify",
|
|
data=params,
|
|
headers={
|
|
"Content-type": "application/x-www-form-urlencoded",
|
|
"User-agent": "reCAPTCHA Python"
|
|
}
|
|
)
|
|
httpresp = urllib2.urlopen(request)
|
|
|
|
return_values = httpresp.read().splitlines()
|
|
httpresp.close()
|
|
|
|
return_code = return_values[0]
|
|
if (return_code == "true"):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def clean(self, values):
|
|
challenge_value = values[0]
|
|
response_value = values[1]
|
|
super(ReCaptchaField, self).clean(response_value)
|
|
if not challenge_value:
|
|
raise util.ValidationError(
|
|
_(u'The CAPTCHA challenge is missing.'))
|
|
elif not response_value:
|
|
raise util.ValidationError(
|
|
_(u'The CAPTCHA solution is missing.'))
|
|
elif self._check_recaptcha(challenge_value, response_value):
|
|
return challenge_value
|
|
else:
|
|
raise util.ValidationError(
|
|
_(u'The CAPTCHA solution was incorrect.'))
|
|
|
|
|
|
class RegexField(Html5Mixin, django.forms.RegexField):
|
|
pass
|
|
|
|
|
|
class SlugField(Html5Mixin, django.forms.SlugField):
|
|
pass
|
|
|
|
|
|
class URLField(Html5Mixin, django.forms.fields.URLField):
|
|
widget = widgets.URLInput
|