kansha/validator.py
# -*- coding:utf-8 -*-
#--
# Copyright (c) 2012-2014 Net-ng.
# All rights reserved.
#
# This software is licensed under the BSD License, as described in
# the file LICENSE.txt, which you should have received as part of
# this distribution.
#--
import re
import string
import ntpath
from lxml import html
from nagare import i18n
from nagare import validator
from nagare.i18n import _, _L
from lxml.html.clean import Cleaner
# mail regex extracted from http://www.regular-expressions.info/email.html
MAIL_RE = r"(?i)^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$"
def clean_text(text):
text = text.replace(u'<br>', u'<br>\n')
text = text.replace(u'</p>', u'</p>\n')
text = text.replace(u'</li>', u'</li>\n')
return unicode(html.fromstring(text).text_content())
def clean_html(text):
cleaner = Cleaner(style=False)
return cleaner.clean_html(text)
class BoolValidator(validator.Validator):
"""Conversion and validation of integers
"""
def __init__(self, value, strip=True, *args, **kw):
"""Initialisation
Check that the value is a bool
In:
- ``v`` -- value to validate
"""
try:
if isinstance(value, basestring):
value = value.strip()
if value.lower() in ('yes', 'on', 'true', '1'):
self.value = True
elif value.lower() in ('no', 'off', 'false', '0'):
self.value = False
else:
self.value = False
else:
self.value = bool(value)
except (ValueError, TypeError):
raise ValueError(i18n._(u'Must be a boolean'))
to_bool = validator.Validator.__call__
def validate_identifier(value, start_with_uppercase_letter=False, max_len=256):
"""Validate an identifier: only letters, digits or underscore characters are accepted"""
if not value:
raise ValueError(_("Should not be empty"))
safe_chars = set("_%s%s" % (string.ascii_letters, string.digits))
ok = all(c in safe_chars for c in value)
if not ok:
raise ValueError(_('Should only contain ascii letters, digits or underscore characters'))
if start_with_uppercase_letter:
if value[0] not in string.ascii_uppercase:
raise ValueError(_("Should start with an uppercase ascii letter"))
else:
if value[0] not in string.ascii_letters:
raise ValueError(_("Should start with an ascii letter"))
if len(value) > max_len:
raise ValueError(
_("Identifier too long (max. %d characters)") % max_len)
return value
def validate_file(data, max_size=None, msg=_('Size must be less than %d KB')):
"""Validate a 'file' input data against the max size in KB"""
# check against the first roundtrip with the client
if data is None or isinstance(data, basestring):
return None
if data.done == -1:
raise ValueError(_('Transfer was interrupted'))
# gets the file size (it's a StringIO)
data.file.seek(0, 2) # 0 from EOF
filesize = data.file.tell()
data.file.seek(0)
if max_size is not None and filesize > max_size * 1024:
raise ValueError(msg % max_size)
filedata = data.file.read()
data.file.seek(0)
# some browsers (i.e. Internet Explorer) send the full path of the file
# instead of the filename
# so, we remove the path from the filename
filename = ntpath.basename(unicode(data.filename))
return {'filename': filename,
'data': filedata,
'content_type': unicode(data.type)}
def validate_non_empty_string(value, msg=_L("Required field")):
"""Check that the value is a non-empty string"""
# strip whitespace characters
return validator.StringValidator(value, strip=True).not_empty(_(msg)).to_string()
def validate_email(value, required_msg=_L("Required field"), invalid_msg=_L("Invalid email address")):
"""Check that the value is a valid email address"""
if not value:
raise ValueError(_(required_msg))
# convert to lowercase
value = value.lower()
if len(value) > 7:
if re.match(MAIL_RE, value):
return value
raise ValueError(_(invalid_msg))
def validate_password(value):
value = validate_non_empty_string(value)
# check password complexity
min_len = 6
if len(value) < min_len:
raise ValueError(_("Password too short: should have at least %d characters")
% min_len)
return value