diff --git a/src/servala/core/crd.py b/src/servala/core/crd.py index e1ca8d2..42ca351 100644 --- a/src/servala/core/crd.py +++ b/src/servala/core/crd.py @@ -5,6 +5,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator, RegexVa from django.db import models from django.forms.models import ModelForm, ModelFormMetaclass from django.utils.translation import gettext_lazy as _ +from jsonschema import validate from servala.core.models import ServiceInstance @@ -39,6 +40,9 @@ def generate_django_model(schema, group, version, kind): spec["properties"].pop("resourceRef", None) model_fields.update(build_object_fields(spec, "spec", parent_required=True)) + # Store the original schema on the model class + model_fields["SCHEMA"] = schema + meta_class = type("Meta", (), {"app_label": "crd_models"}) model_fields["Meta"] = meta_class @@ -138,6 +142,7 @@ def get_django_field( class CrdModelFormMixin: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.schema = self._meta.model.SCHEMA for field in ("organization", "context"): self.fields[field].widget = forms.HiddenInput() @@ -170,10 +175,18 @@ class CrdModelFormMixin: def clean(self): cleaned_data = super().clean() - # TODO implement custom validation logic - # nested_data = self.get_nested_data() + self.validate_nested_data( + self.get_nested_data().get("spec", {}), self.schema["properties"]["spec"] + ) return cleaned_data + def validate_nested_data(self, data, schema): + """Validate data against the provided OpenAPI v3 schema""" + try: + validate(instance=data, schema=schema) + except Exception as e: + raise forms.ValidationError(f"Validation error: {e.message}") + def generate_model_form_class(model): meta_attrs = {