""" 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 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=None): """ 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 ValidationError( _(u'The CAPTCHA challenge is missing.')) elif not response_value: raise ValidationError( _(u'The CAPTCHA solution is missing.')) elif self._check_recaptcha(challenge_value, response_value): return challenge_value else: raise 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