""" 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