iro/validate.py
author Sandro Knauß <knauss@netzguerilla.net>
Mon, 30 Jan 2012 21:36:12 +0100
branchdevel
changeset 128 1a3ebdd3bdaf
parent 126 1ac2439a68b5
child 129 d6704178a18f
permissions -rw-r--r--
telnumber test in own file

from twisted.internet import defer

import re
from decorator import decorator
from inspect import getcallargs

from .error import ValidateException, NotATelNumber, InvalidMail
from .telnumber import Telnumber

def vBool(value, field):
    '''Validator for boolean values'''
    t=[True, 1, "true", "True", "TRUE"]
    f=[False, 0, "false", "False", "FALSE"]
    if value in t:
        return True
    elif value in f:
        return False
    else:
        raise ValidateException(field=field, msg='%s is not boolean' % field)


def vHash(value,field,minlength=None,maxlength=None):
    '''Validator for hash values'''
    if not re.match(r'^[a-f0-9]*$', value.lower()):
        raise ValidateException(field=field)
    if minlength and len(value)<minlength:
        raise ValidateException(field=field)
    if maxlength and len(value)>maxlength:
        raise ValidateException(field=field)
    return value

def vTel(value,field):
    '''Validator for Telefonnumbers'''
    ret = []
    for v in value:
        try:
            ret.append(Telnumber(v))
        except NotATelNumber, e:
            e.field=field
            raise e
    return ret

def vEmail(value, field):
    '''validator for emailadresses (see wikipeda for strange mailadresses and RFC3696)
    valid:
    "very.(),:;<>[]\\".VERY.\\"very@\\\ \\"very\\".unusual"@strange.example.com
    ""@example.org
    "very.unusual.@.unusual.com"@example.com'

    not valid:
    Abc.@example.com
    Abc..123@example.com
    thisis."notallowed@example.com
    this\\ still\\"not\\allowed@example.com
    '''
    ret = []
    for v in value:
        parts= re.match(r'^(.*)@(.+?)$',v)
        if not parts:
            raise InvalidMail(v,field)
        local=parts.group(1)
        domain=parts.group(2)
        
        if not re.match(r'^(\[[0-9\.]{7,16}\]|\[[0-9a-f:]{3,}\]|([a-z0-9+\-%_]+\.)+[a-z]{2,6})$',domain.lower()):
            raise InvalidMail(v,field)
       
        if local == "":
            continue
        if local.startswith(".") or local.endswith("."):
            raise InvalidMail(v,field)
        unquote = True
        parts = local.split('"')
        c=0
        i=0
        for part in parts:
            if unquote and part != "":                     #unquoted is not allowd so much
                if not re.match(r'^[^\\,\[\];\(\)@<>: ]+$',part) or ".." in part:
                    raise InvalidMail(v,field)
            if i == 0:
                if unquote and part != "" and len(parts) > 1 and part[-1] != '.': #quoted parts must be seperated by a dot
                    raise InvalidMail(v,field)
                unquote = not unquote
                c+=1
            elif part == ''  or part[-1] != "\\":
                if unquote  and part != "":         #quoted parts must be seperated by a dot
                    if part[0] != ".":
                        raise InvalidMail(v,field)
                    if i < len(parts)-1 and part[-1] != '.':
                        raise InvalidMail(v,field)
                unquote = not unquote
                c += 1
            i += 1
        if c%2 == 0 and c > 1:                        #no single quote allowed
            raise InvalidMail(v,field)
        ret.append(v)
    return ret

def validate(kwd,func, need=True,*args,**kargs):
    '''validate decorator
    use it like this:
        @validate(kwd=userhash, func=vuserhash)
        f(userhash)
    that will validate usrhash with the function vuserhash.
    Every validate function should raise an Exception, if the the value is not valid'''
    @decorator
    def v(f,*a,**k):
        kp=getcallargs(f,*a,**k)
        def dfunc(*x,**y):
            return None
        try:
            if need or kp[kwd] is not None:
                dfunc=func
        except KeyError:
            if need:
                raise ValidateException(field=kwd,msg="%s is nessasary"%kwd)

        def _gotResult(value):
            kp[kwd] = value
            e = defer.maybeDeferred(f,**kp)
            return e
        d = defer.maybeDeferred(dfunc, kp[kwd],kwd,*args,**kargs)
        return d.addCallback(_gotResult)
    return v