mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-27 02:48:38 -06:00
Introduce JSONSchemaProperty
This commit is contained in:
parent
93bd2ee5b8
commit
a67ea1305e
124
netbox/utilities/jsonschema.py
Normal file
124
netbox/utilities/jsonschema.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.contrib.postgres.forms import SimpleArrayField
|
||||||
|
from django.core.validators import RegexValidator
|
||||||
|
|
||||||
|
from utilities.string import title
|
||||||
|
from utilities.validators import MultipleOfValidator
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'JSONSchemaProperty',
|
||||||
|
'PropertyTypeEnum',
|
||||||
|
'StringFormatEnum',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyTypeEnum(Enum):
|
||||||
|
STRING = 'string'
|
||||||
|
INTEGER = 'integer'
|
||||||
|
NUMBER = 'number'
|
||||||
|
BOOLEAN = 'boolean'
|
||||||
|
ARRAY = 'array'
|
||||||
|
OBJECT = 'object'
|
||||||
|
|
||||||
|
|
||||||
|
class StringFormatEnum(Enum):
|
||||||
|
EMAIL = 'email'
|
||||||
|
URI = 'uri'
|
||||||
|
IRI = 'iri'
|
||||||
|
UUID = 'uuid'
|
||||||
|
DATE = 'date'
|
||||||
|
TIME = 'time'
|
||||||
|
DATETIME = 'datetime'
|
||||||
|
|
||||||
|
|
||||||
|
FORM_FIELDS = {
|
||||||
|
PropertyTypeEnum.STRING.value: forms.CharField,
|
||||||
|
PropertyTypeEnum.INTEGER.value: forms.IntegerField,
|
||||||
|
PropertyTypeEnum.NUMBER.value: forms.FloatField,
|
||||||
|
PropertyTypeEnum.BOOLEAN.value: forms.BooleanField,
|
||||||
|
PropertyTypeEnum.ARRAY.value: SimpleArrayField,
|
||||||
|
PropertyTypeEnum.OBJECT.value: forms.JSONField,
|
||||||
|
}
|
||||||
|
|
||||||
|
STRING_FORM_FIELDS = {
|
||||||
|
StringFormatEnum.EMAIL.value: forms.EmailField,
|
||||||
|
StringFormatEnum.URI.value: forms.URLField,
|
||||||
|
StringFormatEnum.IRI.value: forms.URLField,
|
||||||
|
StringFormatEnum.UUID.value: forms.UUIDField,
|
||||||
|
StringFormatEnum.DATE.value: forms.DateField,
|
||||||
|
StringFormatEnum.TIME.value: forms.TimeField,
|
||||||
|
StringFormatEnum.DATETIME.value: forms.DateTimeField,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class JSONSchemaProperty:
|
||||||
|
type: PropertyTypeEnum = PropertyTypeEnum.STRING.value
|
||||||
|
title: str | None = None
|
||||||
|
description: str | None = None
|
||||||
|
default: Any = None
|
||||||
|
enum: list | None = None
|
||||||
|
|
||||||
|
# Strings
|
||||||
|
minLength: int | None = None
|
||||||
|
maxLength: int | None = None
|
||||||
|
pattern: str | None = None # Regex
|
||||||
|
format: StringFormatEnum | None = None
|
||||||
|
|
||||||
|
# Numbers
|
||||||
|
minimum: int | float | None = None
|
||||||
|
maximum: int | float | None = None
|
||||||
|
multipleOf: int | float | None = None
|
||||||
|
|
||||||
|
def to_form_field(self, name, required=False):
|
||||||
|
"""
|
||||||
|
Instantiate and return a Django form field suitable for editing the property's value.
|
||||||
|
"""
|
||||||
|
field_kwargs = {
|
||||||
|
'label': self.title or title(name),
|
||||||
|
'help_text': self.description,
|
||||||
|
'required': required,
|
||||||
|
}
|
||||||
|
|
||||||
|
# String validation
|
||||||
|
if self.type == PropertyTypeEnum.STRING:
|
||||||
|
if self.minLength is not None:
|
||||||
|
field_kwargs['min_length'] = self.minLength
|
||||||
|
if self.maxLength is not None:
|
||||||
|
field_kwargs['max_length'] = self.maxLength
|
||||||
|
if self.pattern is not None:
|
||||||
|
field_kwargs['validators'] = [
|
||||||
|
RegexValidator(regex=self.pattern)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Integer/number validation
|
||||||
|
elif self.type in (PropertyTypeEnum.INTEGER, PropertyTypeEnum.NUMBER):
|
||||||
|
if self.minimum:
|
||||||
|
field_kwargs['min_value'] = self.minimum
|
||||||
|
if self.maximum:
|
||||||
|
field_kwargs['min_value'] = self.maximum
|
||||||
|
if self.multipleOf:
|
||||||
|
field_kwargs['validators'] = [
|
||||||
|
MultipleOfValidator(multiple=self.multipleOf)
|
||||||
|
]
|
||||||
|
|
||||||
|
return self.field_class(**field_kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def field_class(self):
|
||||||
|
"""
|
||||||
|
Resolve the property's type (and string format, if specified) to the appropriate field class.
|
||||||
|
"""
|
||||||
|
if self.type == PropertyTypeEnum.STRING.value and self.format is not None:
|
||||||
|
try:
|
||||||
|
return STRING_FORM_FIELDS[self.format]
|
||||||
|
except KeyError:
|
||||||
|
raise ValueError(f"Unsupported string format type: {self.format}")
|
||||||
|
try:
|
||||||
|
return FORM_FIELDS[self.type]
|
||||||
|
except KeyError:
|
||||||
|
raise ValueError(f"Unknown property type: {self.type}")
|
Loading…
Reference in New Issue
Block a user