From 96306dcc6fb058be051a237b63915d81d4f6e2d4 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 8 Aug 2025 14:33:24 -0400 Subject: [PATCH] Misc cleanup --- netbox/extras/graphql/filters.py | 4 ++-- netbox/extras/models/configs.py | 7 ------- netbox/extras/tables/tables.py | 2 +- netbox/extras/tests/test_models.py | 28 +++++++++++++++++++++++++++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/netbox/extras/graphql/filters.py b/netbox/extras/graphql/filters.py index 4be282e47..dda9d947b 100644 --- a/netbox/extras/graphql/filters.py +++ b/netbox/extras/graphql/filters.py @@ -8,7 +8,7 @@ from strawberry_django import FilterLookup from core.graphql.filter_mixins import BaseObjectTypeFilterMixin, ChangeLogFilterMixin from extras import models from extras.graphql.filter_mixins import TagBaseFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin -from netbox.graphql.filter_mixins import SyncedDataFilterMixin +from netbox.graphql.filter_mixins import PrimaryModelFilterMixin, SyncedDataFilterMixin if TYPE_CHECKING: from core.graphql.filters import ContentTypeFilter @@ -99,7 +99,7 @@ class ConfigContextFilter(BaseObjectTypeFilterMixin, SyncedDataFilterMixin, Chan @strawberry_django.filter_type(models.ConfigContextProfile, lookups=True) -class ConfigContextProfileFilter(BaseObjectTypeFilterMixin, SyncedDataFilterMixin, ChangeLogFilterMixin): +class ConfigContextProfileFilter(SyncedDataFilterMixin, PrimaryModelFilterMixin): name: FilterLookup[str] = strawberry_django.filter_field() description: FilterLookup[str] = strawberry_django.filter_field() tags: Annotated['TagFilter', strawberry.lazy('extras.graphql.filters')] | None = strawberry_django.filter_field() diff --git a/netbox/extras/models/configs.py b/netbox/extras/models/configs.py index ad58b8529..e4a242af5 100644 --- a/netbox/extras/models/configs.py +++ b/netbox/extras/models/configs.py @@ -60,13 +60,6 @@ class ConfigContextProfile(SyncedDataMixin, PrimaryModel): def __str__(self): return self.name - def get_absolute_url(self): - return reverse('extras:configcontextprofile', kwargs={'pk': self.pk}) - - @property - def docs_url(self): - return f'{settings.STATIC_URL}docs/models/extras/configcontextprofile/' - class ConfigContext(SyncedDataMixin, CloningMixin, CustomLinksMixin, ChangeLoggedModel): """ diff --git a/netbox/extras/tables/tables.py b/netbox/extras/tables/tables.py index 21461a8c1..10f6e0344 100644 --- a/netbox/extras/tables/tables.py +++ b/netbox/extras/tables/tables.py @@ -559,7 +559,7 @@ class ConfigContextProfileTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = ConfigContextProfile fields = ( - 'pk', 'id', 'name', 'description', 'tags', 'created', 'last_updated', + 'pk', 'id', 'name', 'description', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'description') diff --git a/netbox/extras/tests/test_models.py b/netbox/extras/tests/test_models.py index 6b718569c..341920a81 100644 --- a/netbox/extras/tests/test_models.py +++ b/netbox/extras/tests/test_models.py @@ -6,7 +6,7 @@ from django.test import tag, TestCase from core.models import DataSource, ObjectType from dcim.models import Device, DeviceRole, DeviceType, Location, Manufacturer, Platform, Region, Site, SiteGroup -from extras.models import ConfigContext, ConfigTemplate, Tag +from extras.models import ConfigContext, ConfigContextProfile, ConfigTemplate, Tag from tenancy.models import Tenant, TenantGroup from utilities.exceptions import AbortRequest from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine @@ -159,6 +159,32 @@ class ConfigContextTest(TestCase): } self.assertEqual(device.get_config_context(), expected_data) + def test_schema_validation(self): + """ + Check that the JSON schema defined by the assigned profile is enforced. + """ + profile = ConfigContextProfile.objects.create( + name="Config context profile 1", + schema={ + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + ) + + with self.assertRaises(ValidationError): + # Missing required attribute + ConfigContext(name="CC1", profile=profile, data={}).clean() + with self.assertRaises(ValidationError): + # Invalid attribute type + ConfigContext(name="CC1", profile=profile, data={"foo": 123}).clean() + ConfigContext(name="CC1", profile=profile, data={"foo": "bar"}).clean() + def test_annotation_same_as_get_for_object(self): """ This test incorporates features from all of the above tests cases to ensure