fields.py 8.25 KB
Newer Older
1 2 3 4 5 6
from django.core.exceptions import ValidationError
from django.forms import fields
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.ipv6 import is_valid_ipv6_address
from south.modelsinspector import add_introspection_rules
7
from django import forms
8
from netaddr import IPAddress, IPNetwork, AddrFormatError, ZEROFILL
9 10
import re

11 12

mac_re = re.compile(r'^([0-9a-fA-F]{2}(:|$)){6}$')
13 14 15 16 17
alfanum_re = re.compile(r'^[A-Za-z0-9_-]+$')
domain_re = re.compile(r'^([A-Za-z0-9_-]\.?)+$')
ipv4_re = re.compile('^[0-9]+\.([0-9]+)\.([0-9]+)\.([0-9]+)$')
reverse_domain_re = re.compile(r'^(%\([abcd]\)d|[a-z0-9.-])+$')

18

19 20 21 22 23 24 25 26
class MACAddressFormField(fields.RegexField):
    default_error_messages = {
        'invalid': _(u'Enter a valid MAC address.'),
    }

    def __init__(self, *args, **kwargs):
        super(MACAddressFormField, self).__init__(mac_re, *args, **kwargs)

27

28 29
class MACAddressField(models.Field):
    empty_strings_allowed = False
30

31 32 33 34 35 36 37
    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 17
        super(MACAddressField, self).__init__(*args, **kwargs)

    def get_internal_type(self):
        return 'CharField'

38 39 40 41 42 43
    def to_python(self, value):
        if not mac_re.search(str(value)):
            raise ValidationError(
                MACAddressFormField.default_error_messages['invalid'])
        return str(value)

44 45 46 47 48 49
    def formfield(self, **kwargs):
        defaults = {'form_class': MACAddressFormField}
        defaults.update(kwargs)
        return super(MACAddressField, self).formfield(**defaults)
add_introspection_rules([], ["firewall\.fields\.MACAddressField"])

50

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
class IPAddressFormField(forms.Field):
    default_error_messages = {
        'invalid': _(u'Enter a valid IP address. %s'),
    }

    def validate(self, value):
        try:
            return IPAddressField.from_str(value, version=self.version)
        except (AddrFormatError, TypeError), e:
            raise ValidationError(self.default_error_messages['invalid']
                                  % unicode(e))

    def __init__(self, *args, **kwargs):
        self.version = kwargs['version']
        del kwargs['version']
        super(IPAddressFormField, self).__init__(*args, **kwargs)


class IPAddressField(models.Field):
    description = _('IP Network object')
    __metaclass__ = models.SubfieldBase

    def __init__(self, version=4, serialize=True, *args, **kwargs):
        kwargs['max_length'] = 100
        self.version = version
        super(IPAddressField, self).__init__(*args, **kwargs)

    @staticmethod
    def from_str(value, version):
        if not value or value == "":
            return None

        if isinstance(value, IPAddress):
            return value

86 87
        return IPAddress(value.split('/')[0], version=version,
                         flags=ZEROFILL)
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

    def get_internal_type(self):
        return "CharField"

    def to_python(self, value):
        return IPAddressField.from_str(value, self.version)

    def get_db_prep_value(self, value, connection, prepared=False):
        if not value or value == "":
            return None

        if isinstance(value, IPAddress):
            if self.version == 4:
                return ('.'.join(["%03d" % x for x in value.words]))
            else:
                return (':'.join(["%04X" % x for x in value.words]))
        return value

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return str(self.get_prep_value(value))

    def clean(self, value, model_instance):
        value = super(IPAddressField, self).clean(value, model_instance)
        return self.get_prep_value(value)

    def formfield(self, **kwargs):
        defaults = {'form_class': IPAddressFormField}
        defaults['version'] = self.version
        defaults.update(kwargs)
        return super(IPAddressField, self).formfield(**defaults)


121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
class IPNetworkFormField(forms.Field):
    default_error_messages = {
        'invalid': _(u'Enter a valid IP network. %s'),
    }

    def validate(self, value):
        try:
            return IPNetworkField.from_str(value, version=self.version)
        except (AddrFormatError, TypeError), e:
            raise ValidationError(self.default_error_messages['invalid']
                                  % unicode(e))

    def __init__(self, *args, **kwargs):
        self.version = kwargs['version']
        del kwargs['version']
        super(IPNetworkFormField, self).__init__(*args, **kwargs)


class IPNetworkField(models.Field):
    description = _('IP Network object')
    __metaclass__ = models.SubfieldBase

143
    def __init__(self, version=4, serialize=True, *args, **kwargs):
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
        kwargs['max_length'] = 100
        self.version = version
        super(IPNetworkField, self).__init__(*args, **kwargs)

    @staticmethod
    def from_str(value, version):
        if not value or value == "":
            return None

        if isinstance(value, IPNetwork):
            return value

        return IPNetwork(value, version=version)

    def get_internal_type(self):
        return "CharField"

    def to_python(self, value):
        return IPNetworkField.from_str(value, self.version)

    def get_db_prep_value(self, value, connection, prepared=False):
        if not value or value == "":
            return None

        if isinstance(value, IPNetwork):
            if self.version == 4:
170 171
                return ('.'.join(["%03d" % x for x in value.ip.words])
                        + '/%02d' % value.prefixlen)
172
            else:
173 174
                return (':'.join(["%04X" % x for x in value.ip.words])
                        + '/%03d' % value.prefixlen)
175 176 177 178
        return value

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
179
        return str(self.get_prep_value(value))
180 181 182 183 184 185 186 187 188 189 190

    def clean(self, value, model_instance):
        value = super(IPNetworkField, self).clean(value, model_instance)
        return self.get_prep_value(value)

    def formfield(self, **kwargs):
        defaults = {'form_class': IPNetworkFormField}
        defaults['version'] = self.version
        defaults.update(kwargs)
        return super(IPNetworkField, self).formfield(**defaults)

191
add_introspection_rules([], ["^firewall\.fields\.IP(Address|Network)Field"])
192 193


194 195 196 197
def val_alfanum(value):
    """Validate whether the parameter is a valid alphanumeric value."""
    if not alfanum_re.match(value):
        raise ValidationError(_(u'%s - only letters, numbers, underscores '
198 199
                                'and hyphens are allowed!') % value)

200 201 202 203 204

def is_valid_domain(value):
    """Check whether the parameter is a valid domain name."""
    return domain_re.match(value) is not None

205

206 207 208 209 210
def val_domain(value):
    """Validate whether the parameter is a valid domin name."""
    if not is_valid_domain(value):
        raise ValidationError(_(u'%s - invalid domain name') % value)

211

212 213 214 215
def is_valid_reverse_domain(value):
    """Check whether the parameter is a valid reverse domain name."""
    return reverse_domain_re.match(value) is not None

216

217 218 219 220 221
def val_reverse_domain(value):
    """Validate whether the parameter is a valid reverse domain name."""
    if not is_valid_reverse_domain(value):
        raise ValidationError(u'%s - invalid reverse domain name' % value)

222

223 224 225 226
def is_valid_ipv4_address(value):
    """Check whether the parameter is a valid IPv4 address."""
    return ipv4_re.match(value) is not None

227

228 229 230 231 232
def val_ipv4(value):
    """Validate whether the parameter is a valid IPv4 address."""
    if not is_valid_ipv4_address(value):
        raise ValidationError(_(u'%s - not an IPv4 address') % value)

233

234 235 236 237 238
def val_ipv6(value):
    """Validate whether the parameter is a valid IPv6 address."""
    if not is_valid_ipv6_address(value):
        raise ValidationError(_(u'%s - not an IPv6 address') % value)

239 240 241 242 243 244 245 246 247 248 249 250 251

def val_mx(value):
    """Validate whether the parameter is a valid MX address definition.

    Expected form is <priority>:<hostname>.
    """
    mx = value.split(':', 1)
    if not (len(mx) == 2 and mx[0].isdigit() and
            domain_re.match(mx[1])):
        raise ValidationError(_("Bad MX address format. "
                                "Should be: <priority>:<hostname>"))


252 253 254 255 256
def ipv4_2_ipv6(ipv4):
    """Convert IPv4 address string to IPv6 address string."""
    val_ipv4(ipv4)
    m = ipv4_re.match(ipv4)
    return ("2001:738:2001:4031:%s:%s:%s:0" %
257
            (m.group(1), m.group(2), m.group(3)))