Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
validators.py 2.57 KiB
# -*- coding: utf-8 -*-
"""
app.validators
~~~~~~~~~~~~~~

This module defines extra field validators

:copyright: (c) 2017 European Spallation Source ERIC
:license: BSD 2-Clause, see LICENSE for more details.

"""
import ipaddress
import re
import sqlalchemy as sa
from wtforms import ValidationError

ICS_ID_RE = re.compile('[A-Z]{3}[0-9]{3}')
HOST_NAME_RE = re.compile('^[a-z0-9\-]{2,20}$')
VLAN_NAME_RE = re.compile('^[A-Za-z0-9\-]{3,25}$')
MAC_ADDRESS_RE = re.compile('^(?:[0-9a-fA-F]{2}[:-]?){5}[0-9a-fA-F]{2}$')


class IPNetwork:
    """Validates an IP network.

    :param message: the error message to raise in case of a validation error
    """
    def __init__(self, message=None):
        self.message = message

    def __call__(self, form, field):
        try:
            ipaddress.ip_network(field.data, strict=True)
        except (ipaddress.AddressValueError, ipaddress.NetmaskValueError, ValueError):
            if self.message is None:
                self.message = field.gettext('Invalid IP network.')
            raise ValidationError(self.message)


# Inspired by flask-admin Unique validator
# Modified to use flask-sqlalchemy query on Model
class Unique(object):
    """Checks field value unicity against specified table field

    :param model: the model to check unicity against
    :param column: the unique column
    :param message: the error message
    """

    def __init__(self, model, column='name', message=None):
        self.model = model
        self.column = column
        self.message = message

    def __call__(self, form, field):
        # databases allow multiple NULL values for unique columns
        if field.data is None:
            return
        try:
            kwargs = {self.column: field.data}
            obj = self.model.query.filter_by(**kwargs).one()
            if not hasattr(form, '_obj') or not form._obj == obj:
                if self.message is None:
                    self.message = field.gettext('Already exists.')
                raise ValidationError(self.message)
        except sa.orm.exc.NoResultFound:
            pass


class RegexpList:
    """Validates a list of strings against a user provided regexp.

    :param regex: the regular expression to use
    :param message: the error message
    """
    def __init__(self, regex, message=None):
        self.regex = regex
        if message is None:
            message = 'Invalid input.'
        self.message = message

    def __call__(self, form, field):
        for string in field.data.split():
            if self.regex.match(string) is None:
                raise ValidationError(self.message)