Skip to content

Commit

Permalink
WIP: Works on validators (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
staverne committed Nov 25, 2016
1 parent 36728e2 commit 85403a0
Show file tree
Hide file tree
Showing 13 changed files with 620 additions and 10 deletions.
11 changes: 11 additions & 0 deletions itools/database/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
# Import from itools
from itools.core import is_prototype, prototype
from itools.gettext import MSG
from itools.validators import validator


class Field(prototype):
Expand All @@ -31,6 +32,8 @@ class Field(prototype):
'invalid': MSG(u'Invalid value.'),
'required': MSG(u'This field is required.'),
}
validators = []


def get_datatype(self):
return self.datatype
Expand All @@ -41,6 +44,14 @@ def access(self, mode, resource):
return True


def get_validators(self):
validators = []
for v in self.validators:
if type(v) is str:
v = validator(v)()
validators.append(v)
return validators


def get_field_and_datatype(elt):
""" Now schema can be Datatype or Field.
Expand Down
28 changes: 28 additions & 0 deletions itools/validators/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: UTF-8 -*-
# Copyright (C) 2016 Sylvain Taverne <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# Import from itools
from base import BaseValidator
from exceptions import ValidationError
from registry import register_validator, validator
import files
import database

__all__ = [
'BaseValidator',
'ValidationError',
'register_validator',
'validator']
205 changes: 205 additions & 0 deletions itools/validators/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
# -*- coding: UTF-8 -*-
# Copyright (C) 2016 Sylvain Taverne <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# Import from standard library
import re

# Import from itools
from itools.core import prototype, prototype_type
from itools.gettext import MSG

# Import from here
from exceptions import ValidationError
from registry import register_validator


class BaseValidatorMetaclass(prototype_type):

def __new__(mcs, name, bases, dict):
cls = prototype_type.__new__(mcs, name, bases, dict)
if 'validator_id' in dict:
register_validator(cls)
return cls


class validator_prototype(prototype):

__metaclass__ = BaseValidatorMetaclass


class BaseValidator(validator_prototype):

validator_id = None
errors = {'invalid': MSG(u'Enter a valid value')}

def is_valid(self, value):
try:
self.check(value)
except ValidationError:
return False
return True


def check(self, value):
raise NotImplementedError('Validator is not configured')


def get_error_msg(self):
return self.msg


def raise_default_error(self, kw=None):
code, msg = self.errors.items()[0]
raise ValidationError(msg, code, kw)


def __call__(self, value):
return self.check(value)



class EqualsValidator(BaseValidator):

validator_id = 'equals-to'
base_value = None
errors = {'not-equals': MSG(u'The value should be equals to {base_value}')}

def check(self, value):
if value != self.base_value:
kw = {'base_value': self.base_value}
self.raise_default_error(kw)



class RegexValidator(BaseValidator):

regex = None
inverse_match = False

def check(self, value):
value = str(value)
r = re.compile(self.regex, 0)
if bool(r.search(value)) != (not self.inverse_match):
self.raise_default_error()



class IntegerValidator(RegexValidator):

validator_id = 'integer'
regex = '^-?\d+\Z'
errors = {'valid-integer': MSG(u'Enter a valid integer.')}



class PositiveIntegerValidator(BaseValidator):

validator_id = 'integer-positive'
errors = {'integer-positive': MSG(u'Positiver XXX')}

def check(self, value):
if value < 0:
kw = {'value': value}
self.raise_default_error(kw)



class PositiveIntegerNotNullValidator(BaseValidator):

validator_id = 'integer-positive-not-null'
errors = {'integer-positive-not-null': MSG(u'XXX')}

def check(self, value):
if value <= 0:
kw = {'value': value}
self.raise_default_error(kw)



class MaxValueValidator(BaseValidator):

validator_id = 'max-value'
errors = {'max-value': MSG(u'Ensure this value is less than or equal to {max_value}')}
max_value = None

def check(self, value):
if value > self.max_value:
kw = {'max_value': self.max_value}
self.raise_default_error(kw)



class MinValueValidator(BaseValidator):

validator_id = 'min-value'
errors = {'min-value': MSG(u'Ensure this value is greater than or equal to {min_value}.')}
min_value = None

def check(self, value):
if value < self.min_value:
kw = {'min_value': self.min_value}
self.raise_default_error(kw)



class MinMaxValueValidator(BaseValidator):

validator_id = 'min-max-value'
errors = {'min_max_value': MSG(
u'Ensure this value is greater than or equal to {min_value}.'
u'and value is less than or equal to {max_value}.')}
min_value = None
max_value = None

def check(self, value):
if value < self.min_value or value > self.max_value:
kw = {'max_value': self.max_value}
self.raise_default_error(kw)




class MinLengthValidator(BaseValidator):

validator_id = 'min-length'
min_length = 0
errors = {'min_length': MSG(u'Error')}

def check(self, value):
if len(value) < self.min_length:
kw = {'value': value, 'min_length': self.min_length}
self.raise_default_error(kw)



class MaxLengthValidator(BaseValidator):

validator_id = 'max-length'
max_length = 0
errors = {'max_length': MSG(u'Error')}

def check(self, value):
if len(value) > self.max_length:
kw = {'value': value, 'max_length': self.max_length}
self.raise_default_error(kw)



class HexadecimalValidator(RegexValidator):

validator_id = 'hexadecimal'
regex = '^#[A-Fa-f0-9]+$'
errors = {'invalid': MSG(u'Hexa invalide')}
39 changes: 39 additions & 0 deletions itools/validators/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- coding: UTF-8 -*-
# Copyright (C) 2016 Sylvain Taverne <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# Import from itools
from itools.gettext import MSG

# Import from here
from base import BaseValidator


class UniqueValidator(BaseValidator):

validator_id = 'unique'
errors = {'unique': MSG(u'The field {nb_results} should be unique')}

def check(self, value):
from itools.database import AndQuery, NotQuery
from itools.database import PhraseQuery
query = AndQuery(
NotQuery(PhraseQuery('abspath', str(self.resource.abspath))),
PhraseQuery(self.field_name, value))
search = self.context.database.search(query)
nb_results = len(search)
if nb_results > 0:
kw = {'nb_results': nb_results}
self.raise_default_error(kw)
44 changes: 44 additions & 0 deletions itools/validators/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# -*- coding: UTF-8 -*-
# Copyright (C) 2016 Sylvain Taverne <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.


class ValidationError(Exception):

errors = []

def __init__(self, msg=None, code=None, msg_params=None):
errors = []
if type(msg) is list:
errors.extend(msg)
else:
errors.append((msg, code, msg_params))
self.errors = errors


def get_messages(self):
l = []
for msg, code, msg_params in self.errors:
l.append(msg.gettext(**msg_params))
return l


def get_message(self):
messages = self.get_messages()
return '\n'.join(messages)


def __str__(self):
return self.get_message()
Loading

0 comments on commit 85403a0

Please sign in to comment.