示例#1
0
    def __init__(cls, *args, **kwargs):
        def new_validator(validator_name):
            def inner(self, key, val):
                meth = getattr(db_validator, validator_name)
                try:
                    return meth(val)
                except Exception as exc:
                    # add an attribute identifying invalid field
                    setattr(exc, 'invalid_field', key)
                    raise

            return inner

        columns_to_validate = getattr(cls, '_columns_to_validate', None)
        if columns_to_validate:
            for name in columns_to_validate:
                table, col = cls._split_name_to_table_column(name)
                if table:
                    validator_name = db_validator.adjuster_prefix + table + '_' + col
                else:
                    validator_name = db_validator.adjuster_prefix + col
                validates_with_args = validates(col)
                validator_func = new_validator(validator_name)
                setattr(cls, validator_name,
                        validates_with_args(validator_func))
        super(CustomDeclarativeMeta, cls).__init__(*args, **kwargs)
示例#2
0
def receive_class_instrument(cls):
    for field in cls.iter_columns(relationships=False,
                                  synonyms=False,
                                  use_inspection=False):
        if not isinstance(field, Field) or not field.can_validate:
            continue
        method_name = 'validate_%s' % field.name
        if not hasattr(cls, method_name):

            def validator(self, key, value):
                return self.get_column(key).validate(value)

            setattr(cls, method_name, validates(field.name)(validator))
示例#3
0
class Layer3Domain(db.Model, TrackChanges):
    VRF = 'vrf'
    TYPES = {VRF: ('rd', )}

    id = Column(BigInteger, primary_key=True, nullable=False)
    name = Column(String(128), nullable=False, unique=True)
    type = Column(String(20), nullable=False)
    comment = Column(String(255), nullable=True, index=False)
    # Vrf
    rd = Column(BigInteger, nullable=True, unique=True)

    validate_uint32 = validates('rd')(validate_uint32)

    @property
    def display_name(self):
        return self.name

    @property
    def display_rd(self):
        return '%d:%d' % (self.rd >> 16, self.rd & 0xFFFF)

    def set_comment(self, comment):
        self.comment = comment
        self.update_modified()

    def set_rd(self, rd_str):
        if self.type != Layer3Domain.VRF:
            raise InvalidParameterError('Layer3domain %s is not of type vrf' %
                                        self.name)
        rd = Layer3Domain.parse_rd(rd_str)
        if Layer3Domain.query.filter_by(rd=rd).count() > 0:
            raise InvalidParameterError(
                'Layer3domain with type vrf rd %s already exists' % rd_str)
        self.rd = rd

    @staticmethod
    def parse_rd(rd):
        m = re.match(r'(\d{1,5}):(\d{1,5})', rd)
        if m is None:
            raise InvalidParameterError("Invalid rd '%s'" % rd)

        def validate_uint16(s):
            value = int(s)
            if value < 0 or value > 2**16 - 1:
                raise InvalidParameterError("Invalid rd '%s'" % rd)
            return value

        a = validate_uint16(m.group(1))
        b = validate_uint16(m.group(2))
        return (a << 16) + b
def complex_validates(validate_rule):
    """Quickly setup attributes validation by one-time, based on `sqlalchemy.orm.validates`.

    Don't like `sqlalchemy.orm.validates`, you don't need create many model method,
    as long as pass formatted validate rule.
    (Cause of SQLAlchemy's validate mechanism, you need assignment this funciton's return value
    to a model property.)

    For simplicity, complex_validates don't support `include_removes` and `include_backrefs` parameters
    that in `sqlalchemy.orm.validates`.

    And we don't recommend you use this function multiple times in one model.
    Because this will bring many problems, like:
    1. Multiple complex_validates's execute order was decide by it's model property name, and by reversed order.
       eg. predicates in `validator1 = complex_validates(...)`
       will be executed **AFTER** predicates in `validator2 = complex_validates(...)`
    2. If you try to validate the same attribute in two (or more) complex_validates, only one of complex_validates
       will be execute. (May be this is a bug of SQLAlchemy?)
    `complex_validates` was currently based on `sqlalchemy.orm.validates`, so it is difficult to solve these problems.
    May be we can try to use `AttributeEvents` directly in further, to provide more reliable function.

    Rule Format
    -----------

    {
        column_name: predicate                          # basic format
        (column_name2, column_name3): predicate         # you can specify multiple column_names to given predicates
        column_name4: (predicate, predicate2)           # you can specify multiple predicates to given column_names
        column_name5: [(predicate, arg1, ... argN)]     # and you can specify what arguments should pass to predicate
                                                        # when it doing validate
        (column_name6, column_name7): [(predicate, arg1, ... argN), predicate2]   # another example
    }

    Notice: If you want pass arguments to predicate, you must wrap whole command by another list or tuple.
            Otherwise, we will determine the argument as another predicate.
            So, this is wrong: { column_name: (predicate, arg) }
            this is right: { column_name: [(predicate, arg)] }

    Predicate
    ---------

    There's some `predefined_predicates`, you can just reference its name in validate rule.

        {column_name: ['trans_upper']}

    Or you can pass your own predicate function to the rule, like this:

        def custom_predicate(value):
            return value_is_legal       # return True or False for valid or invalid value

        {column_name: [custom_predicate]}

    If you want change the value when doing validate, return an `dict(value=new_value)` instead of boolean

        {column_name: lambda value: dict(value = value * 2)}   # And you see, we can use lambda as a predicate.

    And the predicate can receive extra arguments, that passes in rule:

        def multiple(value, target_multiple):
            return dict(value= value * target_multiple)

        {column_name: (multiple, 10)}

    Complete Example
    ----------------

    class People(db.Model):
        name = Column(String(100))
        age = Column(Integer)
        IQ = Column(Integer)
        has_lover = Column(Boolean)

        validator = complex_validates({
            'name': [('min_length', 1), ('max_length', 100)],
            ('age', 'IQ'): [('min', 0)],
            'has_lover': lambda value: return !value    # hate you!
        })"""

    ref_dict = {
        # column_name: (
        #   (predicate, arg1, ... argN),
        #   ...
        # )
    }

    for column_names, predicate_refs in validate_rule.iteritems():
        for column_name in _to_tuple(column_names):
            ref_dict[column_name] = \
                ref_dict.get(column_name, tuple()) + _normalize_predicate_refs(predicate_refs)

    return validates(*ref_dict.keys())(
        lambda self, name, value: _validate_handler(name, value, ref_dict[name]))
示例#5
0
def json_freezing_mapper(*args, **kwargs):
    m = mapper(*args, **kwargs)
    names = [c.name for c in m.columns if isinstance(c.type, JSONEncoded)]
    m.class_._json_freezer = validates(*names)(
                                lambda self, name, val: freeze(val))
    return m
示例#6
0
class ZoneView(db.Model, TrackChanges):
    __table_constraints__ = (UniqueConstraint('name', 'zone_id'), )
    soa_attrs = ['ttl', 'primary', 'mail', 'serial', 'refresh', 'retry', 'expire', 'minimum']

    id = Column(BigInteger, primary_key=True, nullable=False)
    name = Column(String(255), nullable=False)
    zone_id = Column(BigInteger, ForeignKey('zone.id'), nullable=False)
    # SOA fields
    ttl = Column(Integer, nullable=False)
    primary = Column(String(255), nullable=False)
    mail = Column(String(255), nullable=False)
    serial = Column(BigInteger, nullable=False)
    refresh = Column(Integer, nullable=False)
    retry = Column(Integer, nullable=False)
    expire = Column(Integer, nullable=False)
    minimum = Column(BigInteger, nullable=False)

    zone = relationship(Zone, backref='views')

    @staticmethod
    def create(zone, name, from_profile=None, soa_attributes=None, copy_rrs=True):
        if from_profile:
            assert len(from_profile.views) == 1
            from_view = from_profile.views[0]
            fields = dict(
                ttl=from_view.ttl,
                primary=from_view.primary,
                mail=from_view.mail,
                refresh=from_view.refresh,
                retry=from_view.retry,
                expire=from_view.expire,
                minimum=from_view.minimum)
        else:
            fields = dict(
                primary='localhost.',
                mail='hostmaster.' + (zone.name or 'root') + '.',
                refresh=app.config['DNS_DEFAULT_REFRESH'],
                retry=app.config['DNS_DEFAULT_RETRY'],
                expire=app.config['DNS_DEFAULT_EXPIRE'],
                minimum=app.config['DNS_DEFAULT_MINIMUM'],
                ttl=app.config['DNS_DEFAULT_ZONE_TTL'])
        if soa_attributes:
            fields.update(soa_attributes)
        if not fields.get('serial', None):
            fields['serial'] = int(datetime.date.today().strftime("%Y%m%d01"))
        zoneview = ZoneView(name=name, zone=zone, **fields)
        if from_profile and copy_rrs:
            for rr in RR.query.filter_by(view=from_view):
                db.session.add(RR(name=make_fqdn(RR.record_name(rr.name, rr.view.zone.name), zone.name),
                                  view=zoneview,
                                  type=rr.type,
                                  ttl=rr.ttl,
                                  ipblock=rr.ipblock,
                                  target=rr.target,
                                  value=rr.value))
        db.session.add(zoneview)
        zone.update_modified()
        return zoneview

    validate_fqdn = validates('primary')(validate_fqdn)

    @validates('expire', 'ttl', 'minimum', 'refresh', 'retry')
    def validate_int32(self, key, value):
        value = int(value)
        if value < 0 or value > 2 ** 31 - 1:
            raise InvalidParameterError("Invalid %s: %d" % (key, value))
        return value

    validate_uint32 = validates('serial')(validate_uint32)

    def set_soa_attrs(self, attributes):
        # TODO what happens to outputs if we set the serial here?
        ttl_change = 'ttl' in attributes and int(attributes['ttl']) != self.ttl
        if ttl_change:
            rrs = RR.query.filter_by(view=self, ttl=None).all()
            for rr in rrs:
                OutputUpdate.send_rr_action(rr, OutputUpdate.DELETE_RR)
        for name, value in attributes.iteritems():
            setattr(self, name, value)
        if 'serial' not in attributes:
            self.update_serial()
        OutputUpdate.send_update_soa(self)
        if ttl_change:
            for rr in rrs:
                OutputUpdate.send_rr_action(rr, OutputUpdate.CREATE_RR)

    def update_serial(self):
        '''
        Increment the serial and call update_modified().

        Only update the serial by calling this function, otherwise outputs will
        not be correctly updated.
        '''
        self.serial += 1
        self.update_modified()

    @property
    def nsec3param(self):
        return self.zone.nsec3param

    def soa_value(self):
        return '{primary} {email} {serial} {refresh} {retry} {expire} {minimum}'.format(
            primary=self.primary,
            email=self.mail,
            serial=self.serial,
            refresh=self.refresh,
            retry=self.retry,
            expire=self.expire,
            minimum=self.minimum)

    @staticmethod
    def pdns_soa_value(value):
        primary, email, serial, refresh, retry, expire, minimum = value.split()
        return '{primary} {email} {serial} {refresh} {retry} {expire} {minimum}'.format(
            primary=strip_dot(primary),
            email=strip_dot(email),
            serial=serial,
            refresh=refresh,
            retry=retry,
            expire=expire,
            minimum=minimum)

    @property
    def outputs(self):
        return Output.query.join(Output.groups).join(ZoneGroup.views).filter(ZoneView.id == self.id)

    def __str__(self):
        zone_object = 'zone profile' if self.zone.profile else 'zone'
        if len(self.zone.views) == 1:
            return '{0} {1}'.format(zone_object, self.zone.display_name)
        else:
            return '{0} {1} view {2}'.format(zone_object, self.zone.display_name, self.name)

    @property
    def display_name(self):
        return self.name
def complex_validates(validate_rule):
    """Quickly setup attributes validation by one-time, based on `sqlalchemy.orm.validates`.

    Don't like `sqlalchemy.orm.validates`, you don't need create many model method,
    as long as pass formatted validate rule.
    (Cause of SQLAlchemy's validate mechanism, you need assignment this funciton's return value
    to a model property.)

    For simplicity, complex_validates don't support `include_removes` and `include_backrefs` parameters
    that in `sqlalchemy.orm.validates`.

    And we don't recommend you use this function multiple times in one model.
    Because this will bring many problems, like:
    1. Multiple complex_validates's execute order was decide by it's model property name, and by reversed order.
       eg. predicates in `validator1 = complex_validates(...)`
       will be executed **AFTER** predicates in `validator2 = complex_validates(...)`
    2. If you try to validate the same attribute in two (or more) complex_validates, only one of complex_validates
       will be execute. (May be this is a bug of SQLAlchemy?)
    `complex_validates` was currently based on `sqlalchemy.orm.validates`, so it is difficult to solve these problems.
    May be we can try to use `AttributeEvents` directly in further, to provide more reliable function.

    Rule Format
    -----------

    {
        column_name: predicate                          # basic format
        (column_name2, column_name3): predicate         # you can specify multiple column_names to given predicates
        column_name4: (predicate, predicate2)           # you can specify multiple predicates to given column_names
        column_name5: [(predicate, arg1, ... argN)]     # and you can specify what arguments should pass to predicate
                                                        # when it doing validate
        (column_name6, column_name7): [(predicate, arg1, ... argN), predicate2]   # another example
    }

    Notice: If you want pass arguments to predicate, you must wrap whole command by another list or tuple.
            Otherwise, we will determine the argument as another predicate.
            So, this is wrong: { column_name: (predicate, arg) }
            this is right: { column_name: [(predicate, arg)] }

    Predicate
    ---------

    There's some `predefined_predicates`, you can just reference its name in validate rule.

        {column_name: ['trans_upper']}

    Or you can pass your own predicate function to the rule, like this:

        def custom_predicate(value):
            return value_is_legal       # return True or False for valid or invalid value

        {column_name: [custom_predicate]}

    If you want change the value when doing validate, return an `dict(value=new_value)` instead of boolean

        {column_name: lambda value: dict(value = value * 2)}   # And you see, we can use lambda as a predicate.

    And the predicate can receive extra arguments, that passes in rule:

        def multiple(value, target_multiple):
            return dict(value= value * target_multiple)

        {column_name: (multiple, 10)}

    Complete Example
    ----------------

    class People(db.Model):
        name = Column(String(100))
        age = Column(Integer)
        IQ = Column(Integer)
        has_lover = Column(Boolean)

        validator = complex_validates({
            'name': [('min_length', 1), ('max_length', 100)],
            ('age', 'IQ'): [('min', 0)],
            'has_lover': lambda value: return !value    # hate you!
        })"""

    ref_dict = {
        # column_name: (
        #   (predicate, arg1, ... argN),
        #   ...
        # )
    }

    for column_names, predicate_refs in validate_rule.items():
        for column_name in _to_tuple(column_names):
            ref_dict[column_name] = \
                ref_dict.get(column_name, tuple()) + _normalize_predicate_refs(predicate_refs)

    return validates(*ref_dict.keys())(
        lambda self, name, value: _validate_handler(name, value, ref_dict[name]))
示例#8
0
 class User(fixtures.ComparableEntity):
     sv = validates("name")(SomeValidator())