import logging import re from ipaddress import ip_address import phonenumbers from django.core import validators from django.core.exceptions import ValidationError from django.utils.deconstruct import deconstructible from django.utils.translation import gettext_lazy as _ from ..utils.python import import_class logger = logging.getLogger(__name__) def all_valid(*args): """ helper function to merge multiple validators at once """ if len(args) == 1: # Dict errors = {} kwargs = args[0] for field, validator in kwargs.items(): try: validator[0](*validator[1:]) except ValidationError as error: errors[field] = error else: # List errors = [] value, validators = args for validator in validators: try: validator(value) except ValidationError as error: errors.append(error) if errors: raise ValidationError(errors) @deconstructible class OrValidator(object): """ Run validators with an OR logic """ def __init__(self, *validators): self.validators = validators def __call__(self, value): msg = [] for validator in self.validators: try: validator(value) except ValidationError as err: msg.append(str(err)) else: return raise ValidationError(' OR '.join(msg)) def validate_ipv4_address(value): msg = _("Not a valid IPv4 address") try: ip = ip_address(value) except ValueError: raise ValidationError(msg) if ip.version != 4: raise ValidationError(msg) def validate_ipv6_address(value): msg = _("Not a valid IPv6 address") try: ip = ip_address(value) except ValueError: raise ValidationError(msg) if ip.version != 6: raise ValidationError(msg) def validate_ip_address(value): msg = _("Not a valid IP address") try: ip_address(value) except ValueError: raise ValidationError(msg) def validate_name(value): """ A single non-empty line of free-form text with no whitespace. """ validators.RegexValidator('^[\.\_\-0-9a-z]+$', _("Enter a valid name (spaceless lowercase text including _.-)."), 'invalid')(value) def validate_ascii(value): try: value.encode('ascii') except UnicodeEncodeError: raise ValidationError('This is not an ASCII string.') def validate_hostname(hostname): """ Ensures that each segment * contains at least one character and a maximum of 63 characters * consists only of allowed characters * doesn't begin or end with a hyphen. http://stackoverflow.com/a/2532344 """ if len(hostname) > 255: raise ValidationError(_("Too long for a hostname.")) hostname = hostname.rstrip('.') allowed = re.compile('(?!-)[A-Z\d-]{1,63}(?