~ubuntu-branches/ubuntu/quantal/python-django/quantal-security

« back to all changes in this revision

Viewing changes to django/core/validators.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2010-05-21 07:52:55 UTC
  • mfrom: (1.3.6 upstream)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: james.westby@ubuntu.com-20100521075255-ii78v1dyfmyu3uzx
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import re
 
2
import urlparse
 
3
 
 
4
from django.core.exceptions import ValidationError
 
5
from django.utils.translation import ugettext_lazy as _
 
6
from django.utils.encoding import smart_unicode
 
7
 
 
8
# These values, if given to validate(), will trigger the self.required check.
 
9
EMPTY_VALUES = (None, '', [], (), {})
 
10
 
 
11
try:
 
12
    from django.conf import settings
 
13
    URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
 
14
except ImportError:
 
15
    # It's OK if Django settings aren't configured.
 
16
    URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
 
17
 
 
18
class RegexValidator(object):
 
19
    regex = ''
 
20
    message = _(u'Enter a valid value.')
 
21
    code = 'invalid'
 
22
 
 
23
    def __init__(self, regex=None, message=None, code=None):
 
24
        if regex is not None:
 
25
            self.regex = regex
 
26
        if message is not None:
 
27
            self.message = message
 
28
        if code is not None:
 
29
            self.code = code
 
30
 
 
31
        if isinstance(self.regex, basestring):
 
32
            self.regex = re.compile(regex)
 
33
 
 
34
    def __call__(self, value):
 
35
        """
 
36
        Validates that the input matches the regular expression.
 
37
        """
 
38
        if not self.regex.search(smart_unicode(value)):
 
39
            raise ValidationError(self.message, code=self.code)
 
40
 
 
41
class URLValidator(RegexValidator):
 
42
    regex = re.compile(
 
43
        r'^https?://' # http:// or https://
 
44
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
 
45
        r'localhost|' #localhost...
 
46
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
 
47
        r'(?::\d+)?' # optional port
 
48
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)
 
49
 
 
50
    def __init__(self, verify_exists=False, validator_user_agent=URL_VALIDATOR_USER_AGENT):
 
51
        super(URLValidator, self).__init__()
 
52
        self.verify_exists = verify_exists
 
53
        self.user_agent = validator_user_agent
 
54
 
 
55
    def __call__(self, value):
 
56
        try:
 
57
            super(URLValidator, self).__call__(value)
 
58
        except ValidationError, e:
 
59
            # Trivial case failed. Try for possible IDN domain
 
60
            if value:
 
61
                value = smart_unicode(value)
 
62
                scheme, netloc, path, query, fragment = urlparse.urlsplit(value)
 
63
                try:
 
64
                    netloc = netloc.encode('idna') # IDN -> ACE
 
65
                except UnicodeError: # invalid domain part
 
66
                    raise e
 
67
                url = urlparse.urlunsplit((scheme, netloc, path, query, fragment))
 
68
                super(URLValidator, self).__call__(url)
 
69
            else:
 
70
                raise
 
71
        else:
 
72
            url = value
 
73
 
 
74
        if self.verify_exists:
 
75
            import urllib2
 
76
            headers = {
 
77
                "Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
 
78
                "Accept-Language": "en-us,en;q=0.5",
 
79
                "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
 
80
                "Connection": "close",
 
81
                "User-Agent": self.user_agent,
 
82
            }
 
83
            try:
 
84
                req = urllib2.Request(url, None, headers)
 
85
                u = urllib2.urlopen(req)
 
86
            except ValueError:
 
87
                raise ValidationError(_(u'Enter a valid URL.'), code='invalid')
 
88
            except: # urllib2.URLError, httplib.InvalidURL, etc.
 
89
                raise ValidationError(_(u'This URL appears to be a broken link.'), code='invalid_link')
 
90
 
 
91
 
 
92
def validate_integer(value):
 
93
    try:
 
94
        int(value)
 
95
    except (ValueError, TypeError), e:
 
96
        raise ValidationError('')
 
97
 
 
98
class EmailValidator(RegexValidator):
 
99
 
 
100
    def __call__(self, value):
 
101
        try:
 
102
            super(EmailValidator, self).__call__(value)
 
103
        except ValidationError, e:
 
104
            # Trivial case failed. Try for possible IDN domain-part
 
105
            if value and u'@' in value:
 
106
                parts = value.split(u'@')
 
107
                domain_part = parts[-1]
 
108
                try:
 
109
                    parts[-1] = parts[-1].encode('idna')
 
110
                except UnicodeError:
 
111
                    raise e
 
112
                super(EmailValidator, self).__call__(u'@'.join(parts))
 
113
            else:
 
114
                raise
 
115
 
 
116
email_re = re.compile(
 
117
    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
 
118
    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
 
119
    r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)  # domain
 
120
validate_email = EmailValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid')
 
121
 
 
122
slug_re = re.compile(r'^[-\w]+$')
 
123
validate_slug = RegexValidator(slug_re, _(u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
 
124
 
 
125
ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
 
126
validate_ipv4_address = RegexValidator(ipv4_re, _(u'Enter a valid IPv4 address.'), 'invalid')
 
127
 
 
128
comma_separated_int_list_re = re.compile('^[\d,]+$')
 
129
validate_comma_separated_integer_list = RegexValidator(comma_separated_int_list_re, _(u'Enter only digits separated by commas.'), 'invalid')
 
130
 
 
131
 
 
132
class BaseValidator(object):
 
133
    compare = lambda self, a, b: a is not b
 
134
    clean   = lambda self, x: x
 
135
    message = _(u'Ensure this value is %(limit_value)s (it is %(show_value)s).')
 
136
    code = 'limit_value'
 
137
 
 
138
    def __init__(self, limit_value):
 
139
        self.limit_value = limit_value
 
140
 
 
141
    def __call__(self, value):
 
142
        cleaned = self.clean(value)
 
143
        params = {'limit_value': self.limit_value, 'show_value': cleaned}
 
144
        if self.compare(cleaned, self.limit_value):
 
145
            raise ValidationError(
 
146
                self.message % params,
 
147
                code=self.code,
 
148
                params=params,
 
149
            )
 
150
 
 
151
class MaxValueValidator(BaseValidator):
 
152
    compare = lambda self, a, b: a > b
 
153
    message = _(u'Ensure this value is less than or equal to %(limit_value)s.')
 
154
    code = 'max_value'
 
155
 
 
156
class MinValueValidator(BaseValidator):
 
157
    compare = lambda self, a, b: a < b
 
158
    message = _(u'Ensure this value is greater than or equal to %(limit_value)s.')
 
159
    code = 'min_value'
 
160
 
 
161
class MinLengthValidator(BaseValidator):
 
162
    compare = lambda self, a, b: a < b
 
163
    clean   = lambda self, x: len(x)
 
164
    message = _(u'Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).')
 
165
    code = 'min_length'
 
166
 
 
167
class MaxLengthValidator(BaseValidator):
 
168
    compare = lambda self, a, b: a > b
 
169
    clean   = lambda self, x: len(x)
 
170
    message = _(u'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).')
 
171
    code = 'max_length'
 
172