Django

Code

Ticket #811: ipv6-standalone.diff

File ipv6-standalone.diff, 16.5 kB (added by Johann Queuniet <johann.queuniet@gmail.com>, 2 months ago)

Same as the 02/02/08 patch, without IPy

  • django/oldforms/__init__.py

    old new  
    933933 
    934934    def isValidIPAddress(self, field_data, all_data): 
    935935        try: 
    936             validators.isValidIPAddress4(field_data, all_data) 
     936            validators.isValidIP4Address(field_data, all_data) 
    937937        except validators.ValidationError, e: 
    938938            raise validators.CriticalValidationError, e.messages 
    939939 
     
    941941        return data or None 
    942942    html2python = staticmethod(html2python) 
    943943 
     944class IP6AddressField(IPAddressField): 
     945    def __init__(self, field_name, length=39, max_length=39, is_required=False, validator_list=None): 
     946        if validator_list is None: validator_list = [] 
     947        validator_list = [self.isValidIPAddress] + validator_list 
     948        TextField.__init__(self, field_name, length=length, max_length=max_length, 
     949            is_required=is_required, validator_list=validator_list) 
     950 
     951    def isValidIPAddress(self, field_data, all_data): 
     952        try: 
     953            validators.isValidIPAddress(field_data, all_data) 
     954        except validators.ValidationError, e: 
     955            raise validators.CriticalValidationError, e.messages 
     956 
     957    def html2python(data): 
     958        return data or None 
     959    html2python = staticmethod(html2python) 
     960 
    944961#################### 
    945962# MISCELLANEOUS    # 
    946963#################### 
  • django/db/models/fields/__init__.py

    old new  
    943943        defaults.update(kwargs) 
    944944        return super(IPAddressField, self).formfield(**defaults) 
    945945 
     946class IP6AddressField(Field): 
     947    empty_strings_allowed = False 
     948    def __init__(self, *args, **kwargs): 
     949        kwargs['max_length'] = 39 
     950        Field.__init__(self, *args, **kwargs) 
     951 
     952    def get_manipulator_field_objs(self): 
     953        return [oldforms.IP6AddressField] 
     954 
     955    def validate(self, field_data, all_data): 
     956        validators.isValidIPAddress(field_data, None) 
     957 
     958    def formfield(self, **kwargs): 
     959        defaults = {'form_class': forms.IP6AddressField} 
     960        defaults.update(kwargs) 
     961        return super(IP6AddressField, self).formfield(**defaults) 
     962 
     963 
    946964class NullBooleanField(Field): 
    947965    empty_strings_allowed = False 
    948966    def __init__(self, *args, **kwargs): 
  • django/db/backends/postgresql/introspection.py

    old new  
    7575    23: 'IntegerField', 
    7676    25: 'TextField', 
    7777    701: 'FloatField', 
    78     869: 'IPAddressField', 
     78    869: 'IP6AddressField', 
    7979    1043: 'CharField', 
    8080    1082: 'DateField', 
    8181    1083: 'TimeField', 
  • django/db/backends/postgresql/creation.py

    old new  
    1616    'ImageField':        'varchar(%(max_length)s)', 
    1717    'IntegerField':      'integer', 
    1818    'IPAddressField':    'inet', 
     19    'IP6AddressField':   'inet', 
    1920    'NullBooleanField':  'boolean', 
    2021    'OneToOneField':     'integer', 
    2122    'PhoneNumberField':  'varchar(20)', 
  • django/db/backends/mysql_old/creation.py

    old new  
    1616    'ImageField':        'varchar(%(max_length)s)', 
    1717    'IntegerField':      'integer', 
    1818    'IPAddressField':    'char(15)', 
     19    'IP6AddressField':   'char(39)', 
    1920    'NullBooleanField':  'bool', 
    2021    'OneToOneField':     'integer', 
    2122    'PhoneNumberField':  'varchar(20)', 
  • django/db/backends/sqlite3/creation.py

    old new  
    1515    'ImageField':                   'varchar(%(max_length)s)', 
    1616    'IntegerField':                 'integer', 
    1717    'IPAddressField':               'char(15)', 
     18    'IP6AddressField':              'char(39)', 
    1819    'NullBooleanField':             'bool', 
    1920    'OneToOneField':                'integer', 
    2021    'PhoneNumberField':             'varchar(20)', 
  • django/db/backends/mysql/creation.py

    old new  
    1616    'ImageField':        'varchar(%(max_length)s)', 
    1717    'IntegerField':      'integer', 
    1818    'IPAddressField':    'char(15)', 
     19    'IPAddressField':    'char(39)', 
    1920    'NullBooleanField':  'bool', 
    2021    'OneToOneField':     'integer', 
    2122    'PhoneNumberField':  'varchar(20)', 
  • django/db/backends/oracle/creation.py

    old new  
    1919    'ImageField':                   'NVARCHAR2(%(max_length)s)', 
    2020    'IntegerField':                 'NUMBER(11)', 
    2121    'IPAddressField':               'VARCHAR2(15)', 
     22    'IP6AddressField':              'VARCHAR2(39)', 
    2223    'NullBooleanField':             'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))', 
    2324    'OneToOneField':                'NUMBER(11)', 
    2425    'PhoneNumberField':             'VARCHAR2(20)', 
  • django/db/backends/postgresql_psycopg2/introspection.py

    old new  
    7272    23: 'IntegerField', 
    7373    25: 'TextField', 
    7474    701: 'FloatField', 
    75     869: 'IPAddressField', 
     75    869: 'IP6AddressField', 
    7676    1043: 'CharField', 
    7777    1082: 'DateField', 
    7878    1083: 'TimeField', 
  • django/core/validators.py

    old new  
    1919from django.utils.translation import ugettext as _, ugettext_lazy, ungettext 
    2020from django.utils.functional import Promise, lazy 
    2121from django.utils.encoding import force_unicode, smart_str 
     22from django.utils.http import ip6_normalize 
    2223 
    2324_datere = r'\d{4}-\d{1,2}-\d{1,2}' 
    2425_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?' 
     
    3334    r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE)  # domain 
    3435integer_re = re.compile(r'^-?\d+$') 
    3536ip4_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}$') 
     37ip6_re = re.compile(r'^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$') 
    3638phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE) 
    3739slug_re = re.compile(r'^[-\w]+$') 
    3840url_re = re.compile(r'^https?://\S+$') 
     
    106108        except ValidationError: 
    107109            raise ValidationError, _("Enter valid e-mail addresses separated by commas.") 
    108110 
    109 def isValidIPAddress4(field_data, all_data): 
     111def isValidIP4Address(field_data, all_data): 
    110112    if not ip4_re.search(field_data): 
    111         raise ValidationError, _("Please enter a valid IP address.") 
     113        raise ValidationError, _("Please enter a valid IPv4 address.") 
    112114 
     115def isValidIPAddress(field_data, all_data): 
     116    if not ip4_re.search(field_data): 
     117        try: 
     118            ip = ip6_normalize(field_data) 
     119            if not ip6_re.search(ip): 
     120                raise ValidationError, _("Please enter a valid IP address.") 
     121        except ValueError: 
     122            raise ValidationError, _("Please enter a valid IP address.") 
     123 
    113124def isNotEmpty(field_data, all_data): 
    114125    if field_data.strip() == '': 
    115126        raise ValidationError, _("Empty values are not allowed here.") 
  • django/newforms/fields.py

    old new  
    1919 
    2020from django.utils.translation import ugettext_lazy as _ 
    2121from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str 
     22from django.utils.http import ip6_normalize 
    2223 
    2324from util import ErrorList, ValidationError 
    2425from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput 
     
    3233    'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', 
    3334    'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField', 
    3435    'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', 
    35     'SplitDateTimeField', 'IPAddressField', 'FilePathField', 
     36    'SplitDateTimeField', 'IPAddressField', 'FilePathField', 'IP6AddressField', 
    3637) 
    3738 
    3839# These values, if given to to_python(), will trigger the self.required check. 
     
    782783 
    783784    def __init__(self, *args, **kwargs): 
    784785        super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs) 
     786 
     787ipv6_re = re.compile(r'^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$') 
     788 
     789class IP6AddressField(CharField): 
     790    def __init__(self, *args, **kwargs): 
     791        super(IP6AddressField, self).__init__(39, 3, *args, **kwargs) 
     792 
     793    def clean(self, value): 
     794        value = super(IP6AddressField, self).clean(value) 
     795        if value == u'': 
     796            return value 
     797        if not ipv4_re.search(value): 
     798            try: 
     799                ip = ip6_normalize(value) 
     800                if not ipv6_re.search(ip): 
     801                    raise ValidationError(_(u'Enter a valid IP address.')) 
     802            except ValueError: 
     803                raise ValidationError(_(u'Enter a valid IP address.')) 
     804        return value 
  • django/utils/http.py

    old new  
    6565    """ 
    6666    rfcdate = formatdate(epoch_seconds) 
    6767    return '%s GMT' % rfcdate[:25] 
     68 
     69def ip6_normalize(addr): 
     70    """ 
     71    Normalize an IPv6 address to allow easy regexp validation 
     72    mostly checks the length, and gets ride of tricky things 
     73    like IPv4 mapped addresses and :: shortcuts 
     74     
     75    Outputs a string 
     76    """ 
     77    # Some basic error checking 
     78    if addr.count('::') > 2 or ':::' in addr: 
     79        raise ValueError 
     80 
     81    ip = addr.split(':') 
     82    nbfull = len([elem for elem in ip if elem != '']) 
     83    nb = len(ip) 
     84 
     85    if nbfull >= 1 and '.' in ip[-1]: 
     86        # Convert IPv4 mapped addresses to full hexa 
     87        ipv4 = ip[-1].split('.') 
     88        hex1 = (int(ipv4[0]) << 8) + int(ipv4[1]) 
     89        hex2 = (int(ipv4[2]) << 8) + int(ipv4[3]) 
     90        ip[-1:] = [hex(hex1)[2:], hex(hex2)[2:]] 
     91        nbfull = nbfull + 1 
     92        nb = nb + 1 
     93 
     94    if nbfull == 8 or nbfull == nb: 
     95        # No need to bother 
     96        return addr 
     97    elif nbfull > 8: 
     98        # Has to be invalid anyway 
     99        raise ValueError 
     100 
     101    # Begin normalization 
     102    start, end, index = (None, None, 0) 
     103    for elem in ip: 
     104        if elem == '': 
     105            if start is None: 
     106                start = index 
     107                end = index 
     108            else: 
     109                end = index 
     110        index += 1 
     111    pad = 8 - nbfull 
     112    if end != start: 
     113        ip[start:end-start+1] = ['0'] * pad 
     114    else: 
     115        ip[start] = '0' 
     116        if pad > 1: 
     117            ip[start:1] = ['0'] * (pad - 1) 
     118    return ':'.join([item for item in ip if len(item) > 0]) 
  • tests/regressiontests/forms/extra.py

    old new  
    377377... 
    378378ValidationError: [u'Enter a valid IPv4 address.'] 
    379379 
     380# IP6AddressField ################################################################## 
     381 
     382>>> f = IP6AddressField() 
     383>>> f.clean('') 
     384Traceback (most recent call last): 
     385... 
     386ValidationError: [u'This field is required.'] 
     387>>> f.clean(None) 
     388Traceback (most recent call last): 
     389... 
     390ValidationError: [u'This field is required.'] 
     391>>> f.clean('127.0.0.1') 
     392u'127.0.0.1' 
     393>>> f.clean('2a01:05d8:25ae:9451:020d:39bc:21e6:8cab') 
     394u'2a01:05d8:25ae:9451:020d:39bc:21e6:8cab' 
     395>>> f.clean('2a01:5d8:25ae:9451:20d:39bc:21e6:8cab') 
     396u'2a01:5d8:25ae:9451:20d:39bc:21e6:8cab' 
     397>>> f.clean('::1') 
     398u'::1' 
     399>>> f.clean('::ffff:88.191.32.1') 
     400u'::ffff:88.191.32.1' 
     401>>> f.clean('foo') 
     402Traceback (most recent call last): 
     403... 
     404ValidationError: [u'Enter a valid IP address.'] 
     405>>> f.clean('127.0.0.') 
     406Traceback (most recent call last): 
     407... 
     408ValidationError: [u'Enter a valid IP address.'] 
     409>>> f.clean('::1:') 
     410Traceback (most recent call last): 
     411... 
     412ValidationError: [u'Enter a valid IP address.'] 
     413>>> f.clean('1.2.3.4.5') 
     414Traceback (most recent call last): 
     415... 
     416ValidationError: [u'Enter a valid IP address.'] 
     417>>> f.clean('2a01:5d8:25ae:9451:20d:39bc:21e6:8cab:fb2c') 
     418Traceback (most recent call last): 
     419... 
     420ValidationError: [u'Ensure this value has at most 39 characters (it has 42).'] 
     421>>> f.clean('2a01:5d8:25ae:9451:20d:39bc:1e6:cab:b2c') 
     422Traceback (most recent call last): 
     423... 
     424ValidationError: [u'Enter a valid IP address.'] 
     425>>> f.clean('256.125.1.5') 
     426Traceback (most recent call last): 
     427... 
     428ValidationError: [u'Enter a valid IP address.'] 
     429>>> f.clean('::12345') 
     430Traceback (most recent call last): 
     431... 
     432ValidationError: [u'Enter a valid IP address.'] 
     433 
     434>>> f = IP6AddressField(required=False) 
     435>>> f.clean('') 
     436u'' 
     437>>> f.clean(None) 
     438u'' 
     439>>> f.clean('127.0.0.1') 
     440u'127.0.0.1' 
     441>>> f.clean('foo') 
     442Traceback (most recent call last): 
     443... 
     444ValidationError: [u'Enter a valid IP address.'] 
     445>>> f.clean('127.0.0.') 
     446Traceback (most recent call last): 
     447... 
     448ValidationError: [u'Enter a valid IP address.'] 
     449>>> f.clean('1.2.3.4.5') 
     450Traceback (most recent call last): 
     451... 
     452ValidationError: [u'Enter a valid IP address.'] 
     453>>> f.clean('256.125.1.5') 
     454Traceback (most recent call last): 
     455... 
     456ValidationError: [u'Enter a valid IP address.'] 
     457 
     458 
    380459################################# 
    381460# Tests of underlying functions # 
    382461################################# 
  • docs/modelforms.txt

    old new  
    5858    ``ImageField``                   ``ImageField`` 
    5959    ``IntegerField``                 ``IntegerField`` 
    6060    ``IPAddressField``               ``IPAddressField`` 
     61    ``IP6AddressField``               ``IP6AddressField`` 
    6162    ``ManyToManyField``              ``ModelMultipleChoiceField`` (see 
    6263                                     below) 
    6364    ``NullBooleanField``             ``CharField`` 
  • docs/model-api.txt

    old new  
    388388 
    389389The admin represents this as an ``<input type="text">`` (a single-line input). 
    390390 
     391``IP6AddressField`` 
     392~~~~~~~~~~~~~~~~~~ 
     393 
     394An IPv6 or IPv4 address, in string format (i.e. "24.124.1.30", 
     395"2002:58bf:278c::1", "::ffff:88.191.52.1"). 
     396 
     397The admin represents this as an ``<input type="text">`` (a single-line input). 
     398 
    391399``NullBooleanField`` 
    392400~~~~~~~~~~~~~~~~~~~~ 
    393401 
  • docs/newforms.txt

    old new  
    14271427      expression. 
    14281428    * Error message keys: ``required``, ``invalid`` 
    14291429 
     1430``IP6AddressField`` 
     1431~~~~~~~~~~~~~~~~~~ 
     1432 
     1433    * Default widget: ``TextInput`` 
     1434    * Empty value: ``''`` (an empty string) 
     1435    * Normalizes to: A Unicode object. 
     1436    * Validates that the given value is a valid IPv4 or IPv6 address 
     1437    * Error message keys: ``required``, ``invalid`` 
     1438 
    14301439``MultipleChoiceField`` 
    14311440~~~~~~~~~~~~~~~~~~~~~~~ 
    14321441 
  • docs/form_for_model.txt

    old new  
    6565    ``ImageField``                   ``ImageField`` 
    6666    ``IntegerField``                 ``IntegerField`` 
    6767    ``IPAddressField``               ``IPAddressField`` 
     68    ``IP6AddressField``               ``IP6AddressField`` 
    6869    ``ManyToManyField``              ``ModelMultipleChoiceField`` (see 
    6970                                     below) 
    7071    ``NullBooleanField``             ``CharField``