Move field validation to model, for API compatibility
This commit is contained in:
parent
8a8745f1fd
commit
0eb01457f4
2 changed files with 37 additions and 21 deletions
|
@ -1,5 +1,4 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from servala.core.models import ControlPlane
|
from servala.core.models import ControlPlane
|
||||||
|
@ -40,35 +39,31 @@ class ControlPlaneAdminForm(forms.ModelForm):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super().clean()
|
cleaned_data = super().clean()
|
||||||
|
|
||||||
# Get the three credential fields
|
|
||||||
ca_data = cleaned_data.get("certificate_authority_data")
|
ca_data = cleaned_data.get("certificate_authority_data")
|
||||||
server = cleaned_data.get("server")
|
server = cleaned_data.get("server")
|
||||||
token = cleaned_data.get("token")
|
token = cleaned_data.get("token")
|
||||||
|
|
||||||
# Check if any of the fields are filled
|
if ca_data and server and token:
|
||||||
has_ca = bool(ca_data)
|
|
||||||
has_server = bool(server)
|
|
||||||
has_token = bool(token)
|
|
||||||
|
|
||||||
# If some but not all fields are filled, raise validation error
|
|
||||||
if (has_ca or has_server or has_token) and not (
|
|
||||||
has_ca and has_server and has_token
|
|
||||||
):
|
|
||||||
raise ValidationError(
|
|
||||||
_(
|
|
||||||
"All credential fields (certificate authority data, server, and token) must be provided together or left empty."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# If all fields are filled, create the api_credentials JSON
|
|
||||||
if has_ca and has_server and has_token:
|
|
||||||
cleaned_data["api_credentials"] = {
|
cleaned_data["api_credentials"] = {
|
||||||
"certificate-authority-data": ca_data,
|
"certificate-authority-data": ca_data,
|
||||||
"server": server,
|
"server": server,
|
||||||
"token": token,
|
"token": token,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
cleaned_data["api_credentials"] = {}
|
if not (ca_data or server or token):
|
||||||
|
cleaned_data["api_credentials"] = {}
|
||||||
|
else:
|
||||||
|
# Some fields are filled but not all - validation will fail at model level,
|
||||||
|
# as model field validators are also called by the API.
|
||||||
|
# We still create the JSON with whatever we have so the model validator can run.
|
||||||
|
credentials = {}
|
||||||
|
if ca_data:
|
||||||
|
credentials["certificate-authority-data"] = ca_data
|
||||||
|
if server:
|
||||||
|
credentials["server"] = server
|
||||||
|
if token:
|
||||||
|
credentials["token"] = token
|
||||||
|
cleaned_data["api_credentials"] = credentials
|
||||||
|
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from encrypted_fields.fields import EncryptedJSONField
|
from encrypted_fields.fields import EncryptedJSONField
|
||||||
|
@ -63,14 +64,34 @@ class Service(models.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
def validate_api_credentials(value):
|
||||||
|
"""
|
||||||
|
Validates that api_credentials either contains all required fields or is empty.
|
||||||
|
"""
|
||||||
|
# If empty dict, that's valid
|
||||||
|
if not value:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check for required fields
|
||||||
|
required_fields = ("certificate-authority-data", "server", "token")
|
||||||
|
missing_fields = required_fields - set(value)
|
||||||
|
|
||||||
|
if missing_fields:
|
||||||
|
raise ValidationError(
|
||||||
|
_("Missing required fields in API credentials: %(fields)s"),
|
||||||
|
params={"fields": ", ".join(missing_fields)},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ControlPlane(models.Model):
|
class ControlPlane(models.Model):
|
||||||
name = models.CharField(max_length=100, verbose_name=_("Name"))
|
name = models.CharField(max_length=100, verbose_name=_("Name"))
|
||||||
description = models.TextField(blank=True, verbose_name=_("Description"))
|
description = models.TextField(blank=True, verbose_name=_("Description"))
|
||||||
k8s_api_endpoint = models.URLField(verbose_name=_("Kubernetes API endpoint"))
|
k8s_api_endpoint = models.URLField(verbose_name=_("Kubernetes API endpoint"))
|
||||||
# TODO: schema
|
# Either contains the fields "certificate_authority_data", "server" and "token", or is empty
|
||||||
api_credentials = EncryptedJSONField(
|
api_credentials = EncryptedJSONField(
|
||||||
verbose_name=_("API credentials"),
|
verbose_name=_("API credentials"),
|
||||||
help_text="Required fields: certificate-authority-data, server (URL), token",
|
help_text="Required fields: certificate-authority-data, server (URL), token",
|
||||||
|
validators=[validate_api_credentials],
|
||||||
)
|
)
|
||||||
|
|
||||||
cloud_provider = models.ForeignKey(
|
cloud_provider = models.ForeignKey(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue