Source code for kerno.colander
"""Convenience to use colander with kerno."""
import colander as c
from kerno.state import MalbonaRezulto
from kerno.typing import DictStr
_ = str # TODO add i18n
[docs]def validate_schema(
schema: c.SchemaType,
adict: DictStr,
mal_title: str = _("Validation error"),
mal_plain: str = _("The data do not pass server validation."),
) -> DictStr:
"""Conveniently validate a colander schema and return the clean dict.
But if colander.Invalid is raised, put it inside a MalbonaRezulto.
"""
try:
return schema.deserialize(adict)
except c.Invalid as e:
malbona = MalbonaRezulto()
malbona.add_toast(title=mal_title, plain=mal_plain)
malbona.invalid = e.asdict()
raise malbona
[docs]class InvalidToMalbona:
"""Context manager that wraps colander's Invalid in a MalbonaRezulto."""
def __init__(
self,
title: str = _("Validation error"),
plain: str = _("The data do not pass server validation."),
html: str = "",
) -> None: # noqa
self.title = title
self.plain = plain
self.html = html
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
if isinstance(exc_val, c.Invalid):
malbona = MalbonaRezulto()
malbona.add_toast(
title=self.title, plain=self.plain, html=self.html
)
malbona.invalid = exc_val.asdict()
raise malbona
[docs]class NumLines:
"""Colander validator that checks the number of lines in text."""
def __init__(
self,
min: int = 0,
max: int = -1,
min_err: str = "Not enough lines (minimum {min})",
max_err: str = "Too many lines (maximum {max})",
) -> None: # noqa
self.min = min
self.max = max
self.min_err = min_err
self.max_err = max_err
def __call__(self, node, value) -> None: # noqa
num_lines = value.count("\n") + 1
if self.min > 0 and num_lines < self.min:
# err = _(self.min_err, mapping={"min": self.min})
raise c.Invalid(node, self.min_err.format(min=self.min))
if self.max > -1 and num_lines > self.max:
# err = _(self.max_err, mapping={"max": self.max})
raise c.Invalid(node, self.max_err.format(max=self.max))
[docs]class IsWeb:
"""Colander validator: ensure starts with "http://" or "https://"."""
def __init__(self, msg: str = 'Must start with "http://" or "https://".'):
self.msg = msg
def __call__(self, node, value) -> None: # noqa
if not (value.startswith("http://") or value.startswith("https://")):
raise c.Invalid(node, self.msg)
[docs]def no_scripts(node, val: str) -> None:
"""Colander validator: forbid script tags in the value."""
if "<script" in val:
raise c.Invalid(node=node, value=val, msg="No scripts are allowed!")