251 lines
7.7 KiB
Python
251 lines
7.7 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 utils, Form, ModelForm, ValidationError
|
|
import sys
|
|
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 hasattr(self, 'placeholder'):
|
|
attrs['placeholder'] = self.placeholder
|
|
|
|
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):
|
|
placeholder = _('yyyy-mm-dd')
|
|
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 get_remote_ip(self):
|
|
f = sys._getframe()
|
|
while f:
|
|
if 'request' in f.f_locals:
|
|
request = f.f_locals['request']
|
|
if request:
|
|
remote_ip = request.META.get('REMOTE_ADDR', None)
|
|
forwarded_ip = request.META.get('HTTP_X_FORWARDED_FOR', None)
|
|
return forwarded_ip or remote_ip
|
|
f = f.f_back
|
|
|
|
def clean(self, values):
|
|
""" test the google recaptcha"""
|
|
import json, urllib, urllib2
|
|
|
|
url = "https://www.google.com/recaptcha/api/siteverify"
|
|
challenge_value = values[0]
|
|
data = urllib.urlencode({
|
|
'secret': settings.RECAPTCHA_PRIVATE_KEY,
|
|
'response': values[1],
|
|
'remoteip': self.get_remote_ip()
|
|
})
|
|
req = urllib2.Request(url, data)
|
|
response = urllib2.urlopen(req)
|
|
result = json.loads(response.read())
|
|
|
|
# result["success"] will be True on a success
|
|
if not result["success"]:
|
|
raise ValidationError(
|
|
_(u'Only humans are allowed to submit this form.'))
|
|
|
|
|
|
class RegexField(Html5Mixin, django.forms.RegexField):
|
|
pass
|
|
|
|
|
|
class SlugField(Html5Mixin, django.forms.SlugField):
|
|
pass
|
|
|
|
|
|
class URLField(Html5Mixin, django.forms.fields.URLField):
|
|
widget = widgets.URLInput
|