django-orchestra/orchestra/core/validators.py

187 lines
5.0 KiB
Python
Raw Permalink Normal View History

2015-05-04 14:19:58 +00:00
import logging
2014-05-08 16:59:35 +00:00
import re
from ipaddress import ip_address
2014-05-08 16:59:35 +00:00
2014-10-30 16:34:02 +00:00
import phonenumbers
2014-05-08 16:59:35 +00:00
from django.core import validators
from django.core.exceptions import ValidationError
2016-02-19 10:11:28 +00:00
from django.utils.deconstruct import deconstructible
from django.utils.translation import gettext_lazy as _
2014-05-08 16:59:35 +00:00
2014-10-30 16:34:02 +00:00
from ..utils.python import import_class
2014-05-08 16:59:35 +00:00
2015-05-04 14:19:58 +00:00
logger = logging.getLogger(__name__)
2015-04-26 15:52:40 +00:00
def all_valid(*args):
2014-11-05 20:22:01 +00:00
""" helper function to merge multiple validators at once """
2015-04-26 15:52:40 +00:00
if len(args) == 1:
# Dict
errors = {}
kwargs = args[0]
2015-04-26 15:52:40 +00:00
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)
2014-11-05 20:22:01 +00:00
if errors:
raise ValidationError(errors)
2016-02-19 10:11:28 +00:00
@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))
2014-05-08 16:59:35 +00:00
def validate_ipv4_address(value):
msg = _("Not a valid IPv4 address")
2014-05-08 16:59:35 +00:00
try:
ip = ip_address(value)
except ValueError:
2014-05-08 16:59:35 +00:00
raise ValidationError(msg)
if ip.version != 4:
2014-05-08 16:59:35 +00:00
raise ValidationError(msg)
def validate_ipv6_address(value):
msg = _("Not a valid IPv6 address")
2014-05-08 16:59:35 +00:00
try:
ip = ip_address(value)
except ValueError:
2014-05-08 16:59:35 +00:00
raise ValidationError(msg)
if ip.version != 6:
2014-05-08 16:59:35 +00:00
raise ValidationError(msg)
def validate_ip_address(value):
msg = _("Not a valid IP address")
try:
ip_address(value)
except ValueError:
raise ValidationError(msg)
2014-05-08 16:59:35 +00:00
def validate_name(value):
"""
A single non-empty line of free-form text with no whitespace.
2014-05-08 16:59:35 +00:00
"""
2014-11-02 14:33:55 +00:00
validators.RegexValidator('^[\.\_\-0-9a-z]+$',
_("Enter a valid name (spaceless lowercase text including _.-)."), 'invalid')(value)
2014-05-08 16:59:35 +00:00
def validate_ascii(value):
try:
2015-04-05 18:02:36 +00:00
value.encode('ascii')
2017-03-29 20:04:42 +00:00
except UnicodeEncodeError:
2014-05-08 16:59:35 +00:00
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:
2014-10-30 16:34:02 +00:00
raise ValidationError(_("Too long for a hostname."))
hostname = hostname.rstrip('.')
allowed = re.compile('(?!-)[A-Z\d-]{1,63}(?<!-)$', re.IGNORECASE)
for name in hostname.split('.'):
if not allowed.match(name):
raise ValidationError(_("Not a valid hostname (%s).") % name)
2014-05-08 16:59:35 +00:00
2014-11-20 15:34:59 +00:00
def validate_username(value):
validators.RegexValidator(r'^[\w.-]+$', _("Enter a valid username."))(value)
2014-05-08 16:59:35 +00:00
def validate_password(value):
2015-05-04 14:19:58 +00:00
try:
import crack
except:
try:
import cracklib as crack
except:
logger.error("Can not validate password. Cracklib bindings are not installed.")
return
2014-05-08 16:59:35 +00:00
try:
crack.VeryFascistCheck(value)
2015-04-01 15:49:21 +00:00
except ValueError as message:
2014-05-08 16:59:35 +00:00
raise ValidationError("Password %s." % str(message)[3:])
def validate_url_path(value):
2014-10-23 21:25:44 +00:00
if not re.match(r'^\/[/.a-zA-Z0-9-_]*$', value):
2015-09-28 10:51:03 +00:00
raise ValidationError(_('"%s" is not a valid URL-path.') % value)
2014-10-30 16:34:02 +00:00
def validate_vat(vat, country):
field = 'localflavor.{lower}.forms.{upper}IdentityCardNumberField'.format(
lower=country.lower(),
upper=country.upper()
)
try:
field = import_class(field)
except (ImportError, AttributeError, ValueError):
pass
else:
field().clean(vat)
def validate_zipcode(zipcode, country):
field = 'localflavor.{lower}.forms.{upper}PostalCodeField'.format(
lower=country.lower(),
upper=country.upper()
)
try:
field = import_class(field)
except (ImportError, AttributeError, ValueError):
pass
else:
field().clean(zipcode)
def validate_phone(value, country):
""" local phone number or international """
msg = _("Not a valid %s nor international phone number.") % country
try:
number = phonenumbers.parse(value, country)
except phonenumbers.phonenumberutil.NumberParseException:
raise ValidationError(msg)
if not phonenumbers.is_valid_number(number):
raise ValidationError(msg)
def validate_string_dir(value):
"""
A single non-empty line of free-form text with no whitespace.
"""
validators.RegexValidator('^[\_\-0-9a-z]+$',
_("Enter a valid name dir (spaceless lowercase text, number and _- )"), 'invalid')(value)