Exemplo n.º 1
0
def _val_string(value: Any,
                min_len: Optional[int] = None,
                max_len: Optional[int] = None,
                ends_with: Optional[str] = None,
                starts_with: Optional[str] = None,
                strip_html: bool = False) -> Result:
    if value is None:
        return Success(None)
    if not isinstance(value, str):
        return Failure(
            ValErrorEntry(_ERR_STR_NOT_STRING, f'Value not a string'))
    if min_len and len(value) < min_len:
        return Failure(
            ValErrorEntry(_ERR_STR_TOO_SHORT,
                          f'Value is too short. Min length {min_len}'))
    if max_len and len(value) > max_len:
        return Failure(
            ValErrorEntry(_ERR_STR_TOO_LONG,
                          f'Value is too long. Max length {max_len}'))
    if ends_with and not value.endswith(ends_with):
        return Failure(
            ValErrorEntry(_ERR_STR_NOT_ENDS_WITH,
                          f'Incorrect value. Value not ends with {ends_with}'))
    if starts_with and not value.startswith(starts_with):
        return Failure(
            ValErrorEntry(
                _ERR_STR_NOT_STARTS_WITH,
                f'Incorrect value. Value not starts with {starts_with}'))
    if strip_html:
        value = remove_tags(value)
    return Success(value)
Exemplo n.º 2
0
def _val_list_of_items(value: Any,
                       parser: Callable[[str], Optional[Union[float, int]]],
                       min_length: int = None,
                       max_length: int = None) -> Result:
    if value is None:
        return Success(None)

    if not isinstance(value, (list, tuple)):
        return Failure(ValErrorEntry(_ERR_EXPECTED_LIST, 'Expected list'))
    elif min_length and min_length > len(value):
        return Failure(
            ValErrorEntry(
                _ERR_LIST_TOO_SHORT,
                f'List too short. Required at least {min_length} elements'))
    else:
        out = []
        for i, e in enumerate(value):
            e = parser(e, None)
            if e is None:
                return Failure(
                    ValErrorEntry(_ERR_LIST_VALUE_ERROR,
                                  f'Invalid value at position {i}'))
            else:
                out.append(e)
        if max_length and len(out) > max_length:
            return Success(
                ValErrorEntry(
                    _ERR_LIST_TOO_BIG,
                    f'List too long. Expected maximum {max_length} elements'))
        return Success(out)
Exemplo n.º 3
0
def val_gif(contents: bytes) -> Result:
    if not contents.startswith(_GIF_HEADER):
        return Failure(ValErrorEntry(_ERR_IMG_GIF, 'Invalid GIF file'))
    if not contents.endswith(_GIF_TRAILER):
        return Failure(ValErrorEntry(_ERR_IMG_GIF, 'Invalid GIF file'))

    if contents[4] not in (0x37, 0x39) or contents[5] != 0x61:
        return Failure(ValErrorEntry(_ERR_IMG_GIF, 'Invalid GIF file'))
Exemplo n.º 4
0
def val_jpg(contents: bytes) -> Result:
    if not contents.startswith(_JPEG_HEADER):
        return Failure(ValErrorEntry(_ERR_IMG_JPEG, 'Invalid JPEG file'))
    if not contents.endswith(_JPEG_TRAILER):
        return Failure(ValErrorEntry(_ERR_IMG_JPEG, 'Invalid JPEG file'))

    if 0xE0 <= contents[3] <= 0xE8:
        return Success(None)
    else:
        return Failure(ValErrorEntry(_ERR_IMG_JPEG, 'Invalid JPEG file'))
Exemplo n.º 5
0
def _val_email(value: Any, domain: Optional[str] = None) -> Result:
    if value is None:
        return Success(None)

    result = _EMAIL_RE.match(value)
    value = result.string if result else None
    if value:
        if domain and not value.endswith(domain):
            return Failure(ValErrorEntry(_ERR_EMAIL_DOMAIN,
                                         'Not valid domain'))
        return Success(value)
    else:
        return Failure(
            ValErrorEntry(_ERR_EMAIL_NOT_VALID, 'Not valid email address'))
Exemplo n.º 6
0
    def _validate_field(cls, value: Any, validators: Union[List,
                                                           Tuple]) -> Result:
        check_status = True
        errors = []
        for i, v in enumerate(validators):
            if isinstance(v, _FieldValidator):
                result = v.call(value)
            elif callable(v):
                result = v(value)
            else:
                raise ValueError(
                    f'Validator at position {i} of "{v}" is unknown')

            if isinstance(result, Result):
                if not result.ok:
                    check_status = False
                    if isinstance(result.result, ValErrorEntry):
                        errors.append(_val_err_dict(result.result))
                    else:
                        errors.append(result.result)
                else:
                    value = result.result
            else:
                raise ValueError(
                    f'Validator at position {i} of "{v}" has returned unexpected result'
                )
        if check_status:
            return Success(value)
        else:
            return Failure(errors)
Exemplo n.º 7
0
def _val_fn(value: Any, fn: Callable[[str], Optional[Any]]) -> Result:
    if value is None:
        return Success(None)
    v = fn(value)
    if v is None:
        return Failure(ValErrorEntry(_ERR_INVALID_VALUE, 'Incorrect value'))
    else:
        return Success(v)
Exemplo n.º 8
0
def _val_phone(value: Any, country: Optional[str] = None) -> Result:
    if value is None:
        return Success(None)
    if parse_phone_number(value, country == 'POL') is None:
        return Failure(ValErrorEntry(_ERR_PHONE_FORMAT,
                                     'Invalid phone format'))
    else:
        return Success(value)
Exemplo n.º 9
0
def _val_value_in(value: Any,
                  available: Optional[Union[List, Tuple]] = None) -> Result:
    if value is None or available is None:
        return Success(None)
    if value in available:
        return Success(value)
    else:
        s = ', '.join(available)
        return Failure(
            ValErrorEntry(_ERR_VALUE_IN, f'Incorrect value. Expected {s}'))
Exemplo n.º 10
0
def _val_numeric(value: Any,
                 parser: Callable[[str, Optional[Union[float, int]]],
                                  Optional[Union[float, int]]],
                 min_val: Optional[Union[int, float]] = None,
                 max_val: Optional[Union[int, float]] = None) -> Result:
    if value is None:
        return Success(None)
    v = parser(value, None)
    if v is None:
        return Failure(
            ValErrorEntry(_ERR_NUMBER_FORMAT, "Invalid number format"))
    else:
        if min_val is not None and v < min_val:
            return Failure(
                ValErrorEntry(_ERR_NUMBER_TOO_SMALL,
                              f'Cannot be smaller than {min_val}'))
        if max_val is not None and v > max_val:
            return Failure(
                ValErrorEntry(_ERR_NUMBER_TOO_BIG,
                              f'Cannot be bigger than {max_val}'))
        return Success(v)
Exemplo n.º 11
0
def _val_address(value: Any,
                 required: int = ADDR_REQ_CITY & ADDR_REQ_COUNTRY) -> Result:
    if value is None or required == 0:
        return Success(None)

    if not isinstance(value, dict):
        return Failure(ValErrorEntry(_ERR_ADDR_FORMAT, 'Invalid format'))
    err = {}
    if required & ADDR_REQ_CITY and value.get('city') is None:
        err['city'] = {
            'code': _ERR_ADDR_MISSING_CITY,
            'message': 'Missing required value'
        }
    if required & ADDR_REQ_COUNTRY and value.get('country') is None:
        err['country'] = {
            'code': _ERR_ADDR_MISSING_COUNTRY,
            'message': 'Missing required value'
        }
    if value.get('country') and value.get(
            'country') not in countries_by_alpha3:
        err['country'] = {
            'code': _ERR_ADDR_COUNTRY,
            'message': 'Incorrect value'
        }
    if required & ADDR_REQ_STREET and value.get('street') is None:
        err['street'] = {
            'code': _ERR_ADDR_MISSING_STREET,
            'message': 'Missing required value'
        }
    if required & ADDR_REQ_DISTRICT and value.get('district') is None:
        err['district'] = {
            'code': _ERR_ADDR_MISSING_DISTRICT,
            'message': 'Missing required value'
        }

    if any(err):
        return Failure(err)
    else:
        return Success(value)
Exemplo n.º 12
0
    def validate(cls,
                 contents: Union[bytes, str],
                 types: int = PNG + JPEG + GIF) -> Result:
        if not contents:
            return Success(None)
        if isinstance(contents, str):
            contents = bytes(contents, 'ascii')
        header = bytes(memoryview(contents)[0:36])
        if len(header) != 36:
            return Failure(
                ValErrorEntry(_ERR_IMG_CONTENT_TOO_SHORT,
                              'Not valid data contents. Content too short'))
        if not header.startswith(b'data:image/'):
            return Failure(
                ValErrorEntry(_ERR_IMG_MISSING_HEADER,
                              'Not valid data contents. Expected image data'))
        img = header.split(b';', 1)
        if len(img) != 2:
            return Failure(
                ValErrorEntry(_ERR_IMG_MISSING_HEADER,
                              'Not valid data contents. Expected image data'))

        image_type = img[0][11:]
        val = cls._IMG_VAL.get(image_type)
        it = cls._IMG_TYPES.get(image_type)
        if not it or it & types == 0 or not val:
            formats = []
            if types & cls.PNG:
                formats.append('PNG')
            if types & cls.JPEG:
                formats.append('JPEG')
            if types & cls.GIF:
                formats.append('GIF')
            formats = ', '.join(formats)
            return Failure(
                ValErrorEntry(_ERR_IMG_TYPE,
                              f'Unknown image type. Expected {formats}'))

        if not img[1].startswith(b'base64,'):
            return Failure(
                ValErrorEntry(_ERR_IMG_CONTENT,
                              'Unknown image type. Expected base64 contents'))

        content_start = len(img[0]) + 8
        try:
            image_bytes = base64_decode(contents[content_start:])[0]
        except (TypeError, binascii.Error) as ex:
            return Failure(
                ValErrorEntry(_ERR_IMG_CONTENT,
                              f'Invalid image contents. {ex}'))

        result = val(image_bytes)
        if result.ok:
            return Success(
                cls.Image(img_type=image_type.decode('ascii'),
                          img_contents=image_bytes))
        else:
            return result
Exemplo n.º 13
0
def _val_date(value: Any,
              remove_offset: bool = True,
              before_date: Optional[datetime] = None,
              after_date: Optional[datetime] = None) -> Result:
    if value is None:
        return Success(None)
    v = parse_date(value)
    if v is None:
        return Failure(ValErrorEntry(_ERR_DATE_FORMAT,
                                     "Not valid date format"))
    else:
        if remove_offset:
            v = v.replace(tzinfo=None)
        if before_date and before_date < v:
            return Failure(
                ValErrorEntry(_ERR_DATE_BEFORE,
                              f'Date has to be before {before_date}'))
        if after_date and after_date > v:
            return Failure(
                ValErrorEntry(_ERR_DATE_AFTER,
                              f'Date has to be after {after_date}'))

        return Success(v)
Exemplo n.º 14
0
def _is_required(value: Any) -> Result:
    if value in (None, ''):
        return Failure(ValErrorEntry(_ERR_REQUIRED, 'Missing required value'))
    else:
        return Success(value)
Exemplo n.º 15
0
def _just_fail(value: Any) -> Result:
    return Failure(ValErrorEntry(0, "Fail"))
Exemplo n.º 16
0
def val_png(contents: bytes) -> Result:
    if not contents.startswith(_PNG_HEADER):
        return Failure(ValErrorEntry(_ERR_IMG_PNG, 'Invalid PNG file'))
    if not contents.endswith(_PNG_TRAILER):
        return Failure(ValErrorEntry(_ERR_IMG_PNG, 'Invalid PNG file'))
    return Success(None)