1# SPDX-License-Identifier: Apache-2.0
2# Copyright (C) 2025 Marcin Zieba <marcinpsk@gmail.com>
3from netbox.api.serializers import NetBoxModelSerializer
4from rest_framework import serializers
5
6from netbox_interface_name_rules.models import InterfaceNameRule
7
8
9class InterfaceNameRuleSerializer(NetBoxModelSerializer):
10 """Serializer for InterfaceNameRule with mutual-exclusivity validation."""
11
12 class Meta:
13 model = InterfaceNameRule
14 fields = [
15 "id",
16 "url",
17 "display",
18 "module_type",
19 "module_type_pattern",
20 "module_type_is_regex",
21 "parent_module_type",
22 "device_type",
23 "platform",
24 "name_template",
25 "parent_name_template",
26 "breakout_mode",
27 "channel_count",
28 "channel_start",
29 "description",
30 "enabled",
31 "applies_to_device_interfaces",
32 "tags",
33 "custom_fields",
34 "created",
35 "last_updated",
36 ]
37 brief_fields = ["id", "url", "display", "name_template", "description"]
38
39 def validate(self, attrs):
40 """Ensure module_type XOR module_type_pattern depending on regex mode."""
41 attrs = super().validate(attrs)
42 instance = self.instance
43
44 # For PATCH requests, fall back to existing instance values for fields not in attrs
45 is_device_level = attrs.get(
46 "applies_to_device_interfaces", getattr(instance, "applies_to_device_interfaces", False)
47 )
48 is_regex = attrs.get("module_type_is_regex", getattr(instance, "module_type_is_regex", False))
49 module_type = attrs.get("module_type", getattr(instance, "module_type", None))
50 pattern = attrs.get("module_type_pattern", getattr(instance, "module_type_pattern", ""))
51
52 if is_device_level:
53 # Device-level rules must not have a module_type FK
54 if module_type: # pragma: no cover # model.clean() runs first
55 raise serializers.ValidationError(
56 {"module_type": "Module type must be empty for device-level interface rules."}
57 )
58 elif is_regex:
59 if not pattern: # pragma: no cover # model.clean() runs first
60 raise serializers.ValidationError(
61 {"module_type_pattern": "Regex pattern is required when regex mode is enabled."}
62 )
63 if module_type: # pragma: no cover # model.clean() runs first
64 raise serializers.ValidationError(
65 {"module_type": "Cannot set both module_type and module_type_pattern. Choose one."}
66 )
67 else:
68 if not module_type: # pragma: no cover # model.clean() runs first
69 raise serializers.ValidationError(
70 {"module_type": "module_type is required when regex mode is disabled."}
71 )
72 if pattern: # pragma: no cover # model.clean() runs first
73 raise serializers.ValidationError(
74 {"module_type_pattern": "Cannot set module_type_pattern when regex mode is disabled."}
75 )
76 return attrs