Skip to content

Commit 5afe0bf

Browse files
committed
feat(serializers): Add generic source/destination support
Replaces source_prefix and destination_prefix with generic source and destination fields in ACL serializers. Introduces support for content types, dynamic querying, and enhanced validation in ACLStandardRule and ACLExtendedRule. Aligns serializers with the generic source/destination model for improved flexibility and consistency.
1 parent 05256c1 commit 5afe0bf

File tree

1 file changed

+92
-29
lines changed

1 file changed

+92
-29
lines changed

netbox_acls/api/serializers.py

Lines changed: 92 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55

66
from django.contrib.contenttypes.models import ContentType
77
from drf_spectacular.utils import extend_schema_field
8-
from ipam.api.serializers import PrefixSerializer
98
from netbox.api.fields import ContentTypeField
109
from netbox.api.serializers import NetBoxModelSerializer
1110
from rest_framework import serializers
1211
from utilities.api import get_serializer_for_model
1312

14-
from ..constants import ACL_HOST_ASSIGNMENT_MODELS, ACL_INTERFACE_ASSIGNMENT_MODELS
13+
from ..constants import (
14+
ACL_HOST_ASSIGNMENT_MODELS,
15+
ACL_INTERFACE_ASSIGNMENT_MODELS,
16+
ACL_RULE_SOURCE_DESTINATION_MODELS,
17+
)
1518
from ..models import (
1619
AccessList,
1720
ACLExtendedRule,
@@ -28,8 +31,8 @@
2831

2932
# Sets a standard error message for ACL rules with an action of remark, but no remark set.
3033
error_message_no_remark = "Action is set to remark, you MUST add a remark."
31-
# Sets a standard error message for ACL rules with an action of remark, but no source_prefix is set.
32-
error_message_action_remark_source_prefix_set = "Action is set to remark, Source Prefix CANNOT be set."
34+
# Sets a standard error message for ACL rules with an action of remark, but no source is set.
35+
error_message_action_remark_source_set = "Action is set to remark, Source CANNOT be set."
3336
# Sets a standard error message for ACL rules with an action not set to remark, but no remark is set.
3437
error_message_remark_without_action_remark = "CANNOT set remark unless action is set to remark."
3538
# Sets a standard error message for ACL rules no associated with an ACL of the same type.
@@ -186,12 +189,18 @@ class ACLStandardRuleSerializer(NetBoxModelSerializer):
186189
view_name="plugins-api:netbox_acls-api:aclstandardrule-detail",
187190
)
188191
access_list = AccessListSerializer(nested=True, required=True)
189-
source_prefix = PrefixSerializer(
190-
nested=True,
192+
source_type = ContentTypeField(
193+
queryset=ContentType.objects.filter(ACL_RULE_SOURCE_DESTINATION_MODELS),
191194
required=False,
195+
default=None,
192196
allow_null=True,
197+
)
198+
source_id = serializers.IntegerField(
199+
required=False,
193200
default=None,
201+
allow_null=True,
194202
)
203+
source = serializers.SerializerMethodField(read_only=True)
195204

196205
class Meta:
197206
"""
@@ -207,20 +216,36 @@ class Meta:
207216
"index",
208217
"action",
209218
"remark",
210-
"source_prefix",
219+
"source_type",
220+
"source_id",
221+
"source",
211222
"description",
212223
"tags",
213224
"created",
214225
"custom_fields",
215226
"last_updated",
216227
)
217-
brief_fields = ("id", "url", "display", "access_list", "index")
228+
brief_fields = (
229+
"id",
230+
"url",
231+
"display",
232+
"access_list",
233+
"index",
234+
)
235+
236+
@extend_schema_field(serializers.JSONField(allow_null=True))
237+
def get_source(self, obj):
238+
if obj.source_id is None:
239+
return None
240+
serializer = get_serializer_for_model(obj.source)
241+
context = {"request": self.context["request"]}
242+
return serializer(obj.source, nested=True, context=context).data
218243

219244
def validate(self, data):
220245
"""
221246
Validate the ACLStandardRule django model's inputs before allowing it to update the instance:
222247
- Check if action set to remark, but no remark set.
223-
- Check if action set to remark, but source_prefix set.
248+
- Check if action set to remark, but source set.
224249
"""
225250
error_message = {}
226251

@@ -230,10 +255,10 @@ def validate(self, data):
230255
error_message["remark"] = [
231256
error_message_no_remark,
232257
]
233-
# Check if action set to remark, but source_prefix set.
234-
if data.get("source_prefix"):
235-
error_message["source_prefix"] = [
236-
error_message_action_remark_source_prefix_set,
258+
# Check if action set to remark, but the source set.
259+
if data.get("source"):
260+
error_message["source"] = [
261+
error_message_action_remark_source_set,
237262
]
238263

239264
if error_message:
@@ -251,18 +276,30 @@ class ACLExtendedRuleSerializer(NetBoxModelSerializer):
251276
view_name="plugins-api:netbox_acls-api:aclextendedrule-detail",
252277
)
253278
access_list = AccessListSerializer(nested=True, required=True)
254-
source_prefix = PrefixSerializer(
255-
nested=True,
279+
source_type = ContentTypeField(
280+
queryset=ContentType.objects.filter(ACL_RULE_SOURCE_DESTINATION_MODELS),
256281
required=False,
282+
default=None,
257283
allow_null=True,
284+
)
285+
source_id = serializers.IntegerField(
286+
required=False,
258287
default=None,
288+
allow_null=True,
259289
)
260-
destination_prefix = PrefixSerializer(
261-
nested=True,
290+
source = serializers.SerializerMethodField(read_only=True)
291+
destination_type = ContentTypeField(
292+
queryset=ContentType.objects.filter(ACL_RULE_SOURCE_DESTINATION_MODELS),
262293
required=False,
294+
default=None,
263295
allow_null=True,
296+
)
297+
destination_id = serializers.IntegerField(
298+
required=False,
264299
default=None,
300+
allow_null=True,
265301
)
302+
destination = serializers.SerializerMethodField(read_only=True)
266303

267304
class Meta:
268305
"""
@@ -279,25 +316,51 @@ class Meta:
279316
"action",
280317
"remark",
281318
"protocol",
282-
"source_prefix",
319+
"source_type",
320+
"source_id",
321+
"source",
283322
"source_ports",
284-
"destination_prefix",
323+
"destination_type",
324+
"destination_id",
325+
"destination",
285326
"destination_ports",
286327
"description",
287328
"tags",
288329
"created",
289330
"custom_fields",
290331
"last_updated",
291332
)
292-
brief_fields = ("id", "url", "display", "access_list", "index")
333+
brief_fields = (
334+
"id",
335+
"url",
336+
"display",
337+
"access_list",
338+
"index",
339+
)
340+
341+
@extend_schema_field(serializers.JSONField(allow_null=True))
342+
def get_source(self, obj):
343+
if obj.source_id is None:
344+
return None
345+
serializer = get_serializer_for_model(obj.source)
346+
context = {"request": self.context["request"]}
347+
return serializer(obj.source, nested=True, context=context).data
348+
349+
@extend_schema_field(serializers.JSONField(allow_null=True))
350+
def get_destination(self, obj):
351+
if obj.destination_id is None:
352+
return None
353+
serializer = get_serializer_for_model(obj.destination)
354+
context = {"request": self.context["request"]}
355+
return serializer(obj.destination, nested=True, context=context).data
293356

294357
def validate(self, data):
295358
"""
296359
Validate the ACLExtendedRule django model's inputs before allowing it to update the instance:
297360
- Check if action set to remark, but no remark set.
298-
- Check if action set to remark, but source_prefix set.
361+
- Check if action set to remark, but source set.
299362
- Check if action set to remark, but source_ports set.
300-
- Check if action set to remark, but destination_prefix set.
363+
- Check if action set to remark, but destination set.
301364
- Check if action set to remark, but destination_ports set.
302365
- Check if action set to remark, but protocol set.
303366
- Check if action set to remark, but protocol set.
@@ -310,19 +373,19 @@ def validate(self, data):
310373
error_message["remark"] = [
311374
error_message_no_remark,
312375
]
313-
# Check if action set to remark, but source_prefix set.
314-
if data.get("source_prefix"):
315-
error_message["source_prefix"] = [
316-
error_message_action_remark_source_prefix_set,
376+
# Check if action set to remark, but the source set.
377+
if data.get("source"):
378+
error_message["source"] = [
379+
error_message_action_remark_source_set,
317380
]
318381
# Check if action set to remark, but source_ports set.
319382
if data.get("source_ports"):
320383
error_message["source_ports"] = [
321384
"Action is set to remark, Source Ports CANNOT be set.",
322385
]
323-
# Check if action set to remark, but destination_prefix set.
324-
if data.get("destination_prefix"):
325-
error_message["destination_prefix"] = [
386+
# Check if action set to remark, but destination set.
387+
if data.get("destination"):
388+
error_message["destination"] = [
326389
"Action is set to remark, Destination Prefix CANNOT be set.",
327390
]
328391
# Check if action set to remark, but destination_ports set.

0 commit comments

Comments
 (0)