diff --git a/libcovebods/common_checks.py b/libcovebods/common_checks.py index f04f572..7146507 100644 --- a/libcovebods/common_checks.py +++ b/libcovebods/common_checks.py @@ -1,11 +1,101 @@ +import json +from collections import OrderedDict from libcove.lib.common import common_checks_context from libcovebods.lib.common_checks import get_statistics, RunAdditionalChecks +from django.utils.html import format_html + + +validation_error_template_lookup = { + 'date': 'Date is not in the correct format. The correct format is YYYY-MM-DD.', + 'date-time': 'Date is not in the correct format. The correct format is YYYY-MM-DDThh:mm:ssZ.', + 'uri': 'Invalid uri found', + 'string': '\'{}\' should be a string. Check that the value {} has quotes at the start and end. Escape any quotes in the value with \'\\\'', # noqa + 'integer': '\'{}\' should be an integer. Check that the value {} doesn’t contain decimal points or any characters other than 0-9. Integer values should not be in quotes. ', # noqa + 'number': '\'{}\' should be a number. Check that the value {} doesn’t contain any characters other than 0-9 and dot (\'.\'). Number values should not be in quotes. ', # noqa + 'boolean': '\'{}\' should be a JSON boolean, \'true\' or \'false\'.', # noqa + 'object': '\'{}\' should be a JSON object', + 'array': '\'{}\' should be a JSON array. Check that value(s) appear within square brackets, [...]'} +# These are "safe" html that we trust +# Don't insert any values into these strings without ensuring escaping +# e.g. using django's format_html function. +validation_error_template_lookup_safe = { + 'date': 'Date is not in the correct format. The correct format is YYYY-MM-DD.', + 'date-time': 'Date is not in the correct format. The correct format is YYYY-MM-DDT00:00:00Z.', + 'uri': 'Invalid uri found', + 'string': '{} should be a string. Check that the value {} has quotes at the start and end. Escape any quotes in the value with \', # noqa + 'integer': '{} should be an integer. Check that the value {} doesn’t contain decimal points or any characters other than 0-9. Integer values should not be in quotes. ', # noqa + 'number': '{} should be a number. Check that the value {} doesn’t contain any characters other than 0-9 and dot (.). Number values should not be in quotes. ', # noqa + 'boolean': '{} should be a JSON boolean, true or false.', # noqa + 'object': '{} should be a JSON object', + 'array': '{} should be a JSON array. Check that value(s) appear within square brackets, [...]'} def common_checks_bods(context, upload_dir, json_data, schema_obj): common_checks = common_checks_context(upload_dir, json_data, schema_obj, 'bods-schema.json', context) + # Rewrite validation errors + # We do something similar for OCDS + # https://github.com/open-contracting/lib-cove-ocds/blob/74c459c06136af45db76487f39408664fd2d4854/libcoveocds/common_checks.py#L32 + validation_errors = common_checks['context']['validation_errors'] + new_validation_errors = [] + for (json_key, values) in validation_errors: + error = json.loads(json_key, object_pairs_hook=OrderedDict) + + e_validator = error['validator'] + e_validator_value = error['validator_value'] + validator_type = error['message_type'] + null_clause = error['null_clause'] + header = error['header_extra'] + + message = None + message_safe = None + + if e_validator in ('format', 'type'): + message_template = validation_error_template_lookup.get(validator_type) + message_safe_template = validation_error_template_lookup_safe.get(validator_type) + + if message_template: + message = message_template.format(header, null_clause) + if message_safe_template: + message_safe = format_html(message_safe_template, header, null_clause) + + if e_validator == 'required': + extra_message = ". Check that the field is included and correctly spelled." + error['message'] += extra_message + error['message_safe'] += extra_message + + if e_validator == 'enum': + message = "'{}' contains an unrecognised value. Check the related codelist for allowed code values.".format(header) # noqa + message_safe = format_html("{} contains an unrecognised value. Check the related codelist for allowed code values.", header) # noqa + + if e_validator == 'minItems' and e_validator_value == 1: + message_safe = format_html('{} is too short. You must supply at least one value, or remove the item entirely (unless it’s required).', header) # noqa + + if e_validator == 'minLength': + if e_validator_value == 1: + message_safe = format_html('"{}" is too short. Strings must be at least one character. This error typically indicates a missing value.', header) # noqa + else: + message_safe = format_html('{} is too short. It should be at least {} characters.', header, e_validator_value) # noqa + + if e_validator == 'maxLength': + message_safe = format_html('{} is too long. It should not exceed {} characters.', header, e_validator_value) # noqa + + if e_validator == 'minimum': + message_safe = format_html('{} is too small. The minimum allowed value is {}.', header, e_validator_value) # noqa + + if e_validator == 'maximum': + message_safe = format_html('{} is too large. The maximum allowed value is {}.', header, e_validator_value) # noqa + + if message is not None: + error['message'] = message + if message_safe is not None: + error['message_safe'] = message_safe + + new_validation_errors.append([json.dumps(error), values]) + new_validation_errors.sort() + common_checks['context']['validation_errors'] = new_validation_errors + context.update(common_checks['context']) additional_checks = RunAdditionalChecks(json_data).run() diff --git a/requirements.in b/requirements.in index 1252aa7..c89947c 100644 --- a/requirements.in +++ b/requirements.in @@ -1,3 +1,3 @@ -e git+https://github.com/OpenDataServices/flatten-tool.git@v0.5.0#egg=flattentool --e git+https://github.com/OpenDataServices/lib-cove.git@v0.5.0#egg=libcove +-e git+https://github.com/OpenDataServices/lib-cove.git@35d7c2f28d643f68455816983185eddafa39ec51#egg=libcove -e . diff --git a/requirements.txt b/requirements.txt index df144bb..71b651f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -e git+https://github.com/OpenDataServices/flatten-tool.git@4c13ef0b32a59e810919a3de09bc8f64ce8f9392#egg=flattentool --e git+https://github.com/OpenDataServices/lib-cove.git@v0.5.0#egg=libcove +-e git+https://github.com/OpenDataServices/lib-cove.git@35d7c2f28d643f68455816983185eddafa39ec51#egg=libcove ## The following requirements were added by pip freeze: bleach==3.1.0 cached-property==1.5.1 diff --git a/requirements_dev.txt b/requirements_dev.txt index 876a61b..c7be921 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -20,7 +20,7 @@ jdcal==1.4 json-merge-patch==0.2 jsonref==0.2 jsonschema==2.6.0 --e git+https://github.com/OpenDataServices/lib-cove.git@v0.5.0#egg=libcove +-e git+https://github.com/OpenDataServices/lib-cove.git@0d9937aa7bf9c7711f17824b1c78ecdba6a9219f#egg=libcove lxml==4.3.2 mccabe==0.6.1 more-itertools==6.0.0