Files
kasu/utils/html5/forms.py
2014-12-10 00:23:36 +01:00

270 lines
8.4 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