Restored MarkDown conversion using 'validator': 'markdown'

This commit is contained in:
2018-07-13 17:02:38 +02:00
parent 8dc3296bd5
commit 0fdcbc3947
2 changed files with 76 additions and 25 deletions

View File

@@ -1,8 +1,7 @@
from datetime import datetime
import logging import logging
from bson import ObjectId, tz_util from bson import ObjectId, tz_util
from datetime import datetime
import cerberus.errors
from eve.io.mongo import Validator from eve.io.mongo import Validator
from flask import current_app from flask import current_app
@@ -12,6 +11,24 @@ log = logging.getLogger(__name__)
class ValidateCustomFields(Validator): class ValidateCustomFields(Validator):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Will be reference to the actual document being validated, so that we can
# modify it during validation.
self.__real_document = None
def validate(self, document, *args, **kwargs):
# Keep a reference to the actual document, because Cerberus validates copies.
self.__real_document = document
return super().validate(document, *args, **kwargs)
def _get_child_validator(self, *args, **kwargs):
child = super()._get_child_validator(*args, **kwargs)
# Pass along our reference to the actual document.
child.__real_document = self.__real_document
return child
# TODO: split this into a convert_property(property, schema) and call that from this function. # TODO: split this into a convert_property(property, schema) and call that from this function.
def convert_properties(self, properties, node_schema): def convert_properties(self, properties, node_schema):
"""Converts datetime strings and ObjectId strings to actual Python objects.""" """Converts datetime strings and ObjectId strings to actual Python objects."""
@@ -160,26 +177,25 @@ class ValidateCustomFields(Validator):
if ip.prefixlen() == 0: if ip.prefixlen() == 0:
self._error(field_name, 'Zero-length prefix is not allowed') self._error(field_name, 'Zero-length prefix is not allowed')
# def _validate_coerce(self, coerce, field: str, value):
# """Override Cerberus' _validate_coerce method for richer features.
#
# This now supports named coercion functions (available in Cerberus 1.0+)
# and passes the field name to coercion functions as well.
# """
# if isinstance(coerce, str):
# coerce = getattr(self, f'_normalize_coerce_{coerce}')
#
# try:
# return coerce(field, value)
# except (TypeError, ValueError):
# self._error(field, cerberus.errors.ERROR_COERCION_FAILED.format(field))
def _validator_markdown(self, field, value): def _validator_markdown(self, field, value):
"""This is a placeholder. """Convert MarkDown.
Markdown is actually processed in a hook
""" """
return value # Find this field inside the original document
my_subdoc = self._subdoc_in_real_document()
save_to = pillar.markdown.cache_field_name(field)
html = pillar.markdown.markdown(value)
my_subdoc[save_to] = html
def _subdoc_in_real_document(self):
"""Return a reference to the current sub-document inside the real document.
This allows modification of the document being validated.
"""
my_subdoc = self.__real_document
for item in self.document_path:
my_subdoc = my_subdoc[item]
return my_subdoc
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -36,7 +36,7 @@ class CerberusCanaryTest(unittest.TestCase):
self._canary_test(validator) self._canary_test(validator)
class ValidationTest(AbstractPillarTest): class AbstractValidationTest(AbstractPillarTest):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
@@ -57,7 +57,7 @@ class ValidationTest(AbstractPillarTest):
self.assertFalse(is_valid) self.assertFalse(is_valid)
class ProjectValidationTest(ValidationTest): class ProjectValidationTest(AbstractValidationTest):
def test_empty(self): def test_empty(self):
from pillar.api.eve_settings import projects_schema from pillar.api.eve_settings import projects_schema
@@ -93,7 +93,7 @@ class ProjectValidationTest(ValidationTest):
self.assertValid(project, projects_schema) self.assertValid(project, projects_schema)
class NodeValidationTest(ValidationTest): class NodeValidationTest(AbstractValidationTest):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.pid, self.project = self.ensure_project_exists() self.pid, self.project = self.ensure_project_exists()
@@ -172,8 +172,8 @@ class NodeValidationTest(ValidationTest):
self.assertValid(comment, nodes_schema) self.assertValid(comment, nodes_schema)
class IPRangeValidatorTest(ValidationTest): class AbstractSchemaValidationTest(AbstractValidationTest):
schema = {'iprange': {'type': 'string', 'required': True, 'validator': 'iprange'}} schema = {}
def assertValid(self, document, schema=None): def assertValid(self, document, schema=None):
return super().assertValid(document, schema or self.schema) return super().assertValid(document, schema or self.schema)
@@ -181,6 +181,10 @@ class IPRangeValidatorTest(ValidationTest):
def assertInvalid(self, document, schema=None): def assertInvalid(self, document, schema=None):
return super().assertInvalid(document, schema or self.schema) return super().assertInvalid(document, schema or self.schema)
class IPRangeValidatorTest(AbstractSchemaValidationTest):
schema = {'iprange': {'type': 'string', 'required': True, 'validator': 'iprange'}}
def test_ipv6(self): def test_ipv6(self):
self.assertValid({'iprange': '2a03:b0c0:0:1010::8fe:6ef1'}) self.assertValid({'iprange': '2a03:b0c0:0:1010::8fe:6ef1'})
self.assertValid({'iprange': '0:0:0:0:0:ffff:102:304'}) self.assertValid({'iprange': '0:0:0:0:0:ffff:102:304'})
@@ -207,3 +211,34 @@ class IPRangeValidatorTest(ValidationTest):
err = self.validator._errors[0] err = self.validator._errors[0]
self.assertEquals(('iprange', ), err.document_path) self.assertEquals(('iprange', ), err.document_path)
self.assertEquals(('Zero-length prefix is not allowed',), err.info) self.assertEquals(('Zero-length prefix is not allowed',), err.info)
class MarkdownValidatorTest(AbstractSchemaValidationTest):
schema = {'subdoc': {
'type': 'list',
'schema': {
'type': 'dict',
'schema': {
'content': {'type': 'string', 'required': True, 'validator': 'markdown'},
'_content_html': {'type': 'string'},
'descr': {'type': 'string', 'required': True, 'validator': 'markdown'},
'_descr_html': {'type': 'string'},
}
},
}}
def test_in_subdoc(self):
doc = {'subdoc': [{
'content': '# Header\n\nSome text',
'descr': 'je moeder'
}]}
self.validator.validate(doc, self.schema, normalize=True)
expect = {'subdoc': [{
'content': '# Header\n\nSome text',
'_content_html': '<h1>Header</h1>\n<p>Some text</p>\n',
'descr': 'je moeder',
'_descr_html': '<p>je moeder</p>\n',
}]}
self.assertEqual(expect, doc)