From 50f3e8f9ff1f532f61b29f2caaa8657b2ea8f9b0 Mon Sep 17 00:00:00 2001 From: Anna Shamray Date: Wed, 18 Nov 2020 18:18:38 +0100 Subject: [PATCH] :sparkles: add validators to API since it's writable now --- src/objecttypes/api/serializers.py | 8 ++++++- src/objecttypes/api/validators.py | 38 ++++++++++++++++++++++++++++++ src/objecttypes/core/models.py | 11 ++------- src/objecttypes/core/utils.py | 12 ++++++++++ 4 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 src/objecttypes/api/validators.py create mode 100644 src/objecttypes/core/utils.py diff --git a/src/objecttypes/api/serializers.py b/src/objecttypes/api/serializers.py index c33eee42..f88ce5ee 100644 --- a/src/objecttypes/api/serializers.py +++ b/src/objecttypes/api/serializers.py @@ -4,6 +4,8 @@ from objecttypes.core.models import ObjectType, ObjectVersion +from .validators import JsonSchemaValidator, VersionUpdateValidator + class ObjectVersionSerializer(NestedHyperlinkedModelSerializer): parent_lookup_kwargs = {"objecttype_uuid": "object_type__uuid"} @@ -27,9 +29,13 @@ class Meta: "read_only": True, }, "publicationDate": {"source": "publication_date", "read_only": True}, - "jsonSchema": {"source": "json_schema"}, + "jsonSchema": { + "source": "json_schema", + "validators": [JsonSchemaValidator()], + }, "status": {"read_only": True}, } + validators = [VersionUpdateValidator()] def create(self, validated_data): kwargs = self.context["request"].resolver_match.kwargs diff --git a/src/objecttypes/api/validators.py b/src/objecttypes/api/validators.py new file mode 100644 index 00000000..a3883274 --- /dev/null +++ b/src/objecttypes/api/validators.py @@ -0,0 +1,38 @@ +from django.core.exceptions import ValidationError +from django.utils.translation import ugettext_lazy as _ + +from rest_framework import serializers + +from objecttypes.core.constants import ObjectVersionStatus +from objecttypes.core.utils import check_json_schema + + +class VersionUpdateValidator: + message = _("Only draft versions can be changed") + code = "non-draft-object" + + def set_context(self, serializer): + """ + This hook is called by the serializer instance, + prior to the validation call being made. + """ + # Determine the existing instance, if this is an update operation. + self.instance = getattr(serializer, "instance", None) + self.request = serializer.context["request"] + + def __call__(self, attrs): + if not self.instance: + return + + if self.instance.status != ObjectVersionStatus.draft: + raise serializers.ValidationError(self.message, code=self.code) + + +class JsonSchemaValidator: + code = "invalid-json-schema" + + def __call__(self, value): + try: + check_json_schema(value) + except ValidationError as exc: + raise serializers.ValidationError(exc.args[0], code=self.code) from exc diff --git a/src/objecttypes/core/models.py b/src/objecttypes/core/models.py index 1f25d830..3025df54 100644 --- a/src/objecttypes/core/models.py +++ b/src/objecttypes/core/models.py @@ -2,18 +2,15 @@ from datetime import date from django.contrib.postgres.fields import JSONField -from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import ugettext_lazy as _ -from jsonschema.exceptions import SchemaError -from jsonschema.validators import validator_for - from .constants import ( DataClassificationChoices, ObjectVersionStatus, UpdateFrequencyChoices, ) +from .utils import check_json_schema class ObjectType(models.Model): @@ -147,11 +144,7 @@ def __str__(self): def clean(self): super().clean() - schema_validator = validator_for(self.json_schema) - try: - schema_validator.check_schema(self.json_schema) - except SchemaError as exc: - raise ValidationError(exc.args[0]) from exc + check_json_schema(self.json_schema) def save(self, *args, **kwargs): if not self.version: diff --git a/src/objecttypes/core/utils.py b/src/objecttypes/core/utils.py new file mode 100644 index 00000000..a0d7dd78 --- /dev/null +++ b/src/objecttypes/core/utils.py @@ -0,0 +1,12 @@ +from django.core.exceptions import ValidationError + +from jsonschema.exceptions import SchemaError +from jsonschema.validators import validator_for + + +def check_json_schema(json_schema: dict): + schema_validator = validator_for(json_schema) + try: + schema_validator.check_schema(json_schema) + except SchemaError as exc: + raise ValidationError(exc.args[0]) from exc