netbox-plugin-dns 1.0.4__py3-none-any.whl → 1.0.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of netbox-plugin-dns might be problematic. Click here for more details.

Files changed (91) hide show
  1. netbox_dns/__init__.py +1 -1
  2. netbox_dns/api/nested_serializers.py +46 -1
  3. netbox_dns/api/serializers.py +2 -0
  4. netbox_dns/api/serializers_/contact.py +3 -0
  5. netbox_dns/api/serializers_/nameserver.py +4 -1
  6. netbox_dns/api/serializers_/record.py +5 -4
  7. netbox_dns/api/serializers_/record_template.py +58 -0
  8. netbox_dns/api/serializers_/registrar.py +3 -0
  9. netbox_dns/api/serializers_/view.py +3 -0
  10. netbox_dns/api/serializers_/zone.py +31 -6
  11. netbox_dns/api/serializers_/zone_template.py +130 -0
  12. netbox_dns/api/urls.py +4 -0
  13. netbox_dns/api/views.py +41 -1
  14. netbox_dns/choices/__init__.py +2 -0
  15. netbox_dns/choices/record.py +49 -0
  16. netbox_dns/choices/zone.py +20 -0
  17. netbox_dns/fields/address.py +6 -0
  18. netbox_dns/fields/network.py +3 -0
  19. netbox_dns/fields/rfc2317.py +6 -0
  20. netbox_dns/filtersets/__init__.py +3 -0
  21. netbox_dns/filtersets/contact.py +3 -0
  22. netbox_dns/filtersets/nameserver.py +3 -0
  23. netbox_dns/filtersets/record.py +5 -1
  24. netbox_dns/filtersets/record_template.py +54 -0
  25. netbox_dns/filtersets/registrar.py +3 -0
  26. netbox_dns/filtersets/view.py +3 -0
  27. netbox_dns/filtersets/zone.py +5 -8
  28. netbox_dns/filtersets/zone_template.py +116 -0
  29. netbox_dns/forms/__init__.py +2 -0
  30. netbox_dns/forms/contact.py +8 -0
  31. netbox_dns/forms/nameserver.py +21 -2
  32. netbox_dns/forms/record.py +24 -10
  33. netbox_dns/forms/record_template.py +220 -0
  34. netbox_dns/forms/registrar.py +8 -0
  35. netbox_dns/forms/view.py +10 -0
  36. netbox_dns/forms/zone.py +125 -41
  37. netbox_dns/forms/zone_template.py +298 -0
  38. netbox_dns/graphql/__init__.py +4 -0
  39. netbox_dns/graphql/filters.py +24 -1
  40. netbox_dns/graphql/schema.py +34 -1
  41. netbox_dns/graphql/types.py +70 -1
  42. netbox_dns/management/commands/cleanup_database.py +2 -6
  43. netbox_dns/management/commands/cleanup_rrset_ttl.py +2 -4
  44. netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +1 -2
  45. netbox_dns/migrations/0006_templating.py +172 -0
  46. netbox_dns/migrations/0021_record_ip_address.py +1 -1
  47. netbox_dns/mixins/object_modification.py +5 -0
  48. netbox_dns/models/__init__.py +7 -0
  49. netbox_dns/models/contact.py +6 -0
  50. netbox_dns/models/nameserver.py +8 -1
  51. netbox_dns/models/record.py +13 -122
  52. netbox_dns/models/record_template.py +180 -0
  53. netbox_dns/models/registrar.py +6 -0
  54. netbox_dns/models/view.py +7 -1
  55. netbox_dns/models/zone.py +63 -71
  56. netbox_dns/models/zone_template.py +150 -0
  57. netbox_dns/navigation.py +47 -0
  58. netbox_dns/tables/__init__.py +2 -0
  59. netbox_dns/tables/contact.py +3 -0
  60. netbox_dns/tables/nameserver.py +3 -2
  61. netbox_dns/tables/record.py +7 -3
  62. netbox_dns/tables/record_template.py +91 -0
  63. netbox_dns/tables/registrar.py +3 -0
  64. netbox_dns/tables/view.py +3 -0
  65. netbox_dns/tables/zone.py +3 -2
  66. netbox_dns/tables/zone_template.py +70 -0
  67. netbox_dns/template_content.py +2 -8
  68. netbox_dns/templates/netbox_dns/recordtemplate.html +84 -0
  69. netbox_dns/templates/netbox_dns/zonetemplate.html +86 -0
  70. netbox_dns/urls/__init__.py +4 -0
  71. netbox_dns/urls/record_template.py +65 -0
  72. netbox_dns/urls/zone_template.py +57 -0
  73. netbox_dns/utilities/ipam_coupling.py +2 -1
  74. netbox_dns/validators/__init__.py +1 -0
  75. netbox_dns/validators/dns_name.py +14 -9
  76. netbox_dns/validators/dns_value.py +83 -0
  77. netbox_dns/validators/rfc2317.py +7 -0
  78. netbox_dns/views/__init__.py +2 -0
  79. netbox_dns/views/contact.py +12 -0
  80. netbox_dns/views/nameserver.py +13 -0
  81. netbox_dns/views/record.py +14 -1
  82. netbox_dns/views/record_template.py +83 -0
  83. netbox_dns/views/registrar.py +12 -0
  84. netbox_dns/views/view.py +12 -0
  85. netbox_dns/views/zone.py +16 -0
  86. netbox_dns/views/zone_template.py +73 -0
  87. {netbox_plugin_dns-1.0.4.dist-info → netbox_plugin_dns-1.0.6.dist-info}/METADATA +2 -1
  88. netbox_plugin_dns-1.0.6.dist-info/RECORD +136 -0
  89. netbox_plugin_dns-1.0.4.dist-info/RECORD +0 -115
  90. {netbox_plugin_dns-1.0.4.dist-info → netbox_plugin_dns-1.0.6.dist-info}/LICENSE +0 -0
  91. {netbox_plugin_dns-1.0.4.dist-info → netbox_plugin_dns-1.0.6.dist-info}/WHEEL +0 -0
netbox_dns/forms/zone.py CHANGED
@@ -1,7 +1,8 @@
1
1
  from django import forms
2
+ from django.db import transaction
2
3
  from django.conf import settings
3
4
  from django.core.validators import MinValueValidator, MaxValueValidator
4
- from django.urls import reverse_lazy
5
+ from django.core.exceptions import ValidationError
5
6
 
6
7
  from netbox.forms import (
7
8
  NetBoxModelBulkEditForm,
@@ -9,6 +10,7 @@ from netbox.forms import (
9
10
  NetBoxModelImportForm,
10
11
  NetBoxModelForm,
11
12
  )
13
+ from netbox.context import events_queue
12
14
  from utilities.forms.fields import (
13
15
  DynamicModelMultipleChoiceField,
14
16
  TagFilterField,
@@ -17,26 +19,115 @@ from utilities.forms.fields import (
17
19
  CSVModelMultipleChoiceField,
18
20
  DynamicModelChoiceField,
19
21
  )
20
- from utilities.forms.widgets import BulkEditNullBooleanSelect, APISelect
22
+ from utilities.forms.widgets import BulkEditNullBooleanSelect
21
23
  from utilities.forms.rendering import FieldSet
22
- from utilities.forms import add_blank_choice
24
+ from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, add_blank_choice
23
25
  from tenancy.models import Tenant
24
26
  from tenancy.forms import TenancyForm, TenancyFilterForm
25
27
 
26
28
  from netbox_dns.models import (
27
29
  View,
28
30
  Zone,
29
- ZoneStatusChoices,
30
31
  NameServer,
31
32
  Registrar,
32
33
  Contact,
34
+ ZoneTemplate,
33
35
  )
36
+ from netbox_dns.choices import ZoneStatusChoices
34
37
  from netbox_dns.utilities import name_to_unicode
35
38
  from netbox_dns.fields import RFC2317NetworkFormField
36
39
  from netbox_dns.validators import validate_ipv4, validate_prefix, validate_rfc2317
37
40
 
38
41
 
39
- class ZoneForm(TenancyForm, NetBoxModelForm):
42
+ __all__ = (
43
+ "ZoneForm",
44
+ "ZoneFilterForm",
45
+ "ZoneImportForm",
46
+ "ZoneBulkEditForm",
47
+ )
48
+
49
+
50
+ class RollbackTransaction(Exception):
51
+ pass
52
+
53
+
54
+ class ZoneTemplateUpdateMixin:
55
+ def clean(self, *args, **kwargs):
56
+ super().clean(*args, **kwargs)
57
+
58
+ if (template := self.cleaned_data.get("template")) is None:
59
+ return
60
+
61
+ if not self.cleaned_data.get("nameservers") and template.nameservers.all():
62
+ self.cleaned_data["nameservers"] = template.nameservers.all()
63
+
64
+ if not self.cleaned_data.get("tags") and template.tags.all():
65
+ self.cleaned_data["tags"] = template.tags.all()
66
+
67
+ for field in template.template_fields:
68
+ if (
69
+ self.cleaned_data.get(field) is None
70
+ and getattr(template, field) is not None
71
+ ):
72
+ self.cleaned_data[field] = getattr(template, field)
73
+
74
+ template_error = None
75
+ saved_events_queue = events_queue.get()
76
+
77
+ try:
78
+ with transaction.atomic():
79
+ if self.instance.id is not None:
80
+ zone = super().save(*args, **kwargs)
81
+ else:
82
+ zone_data = self.cleaned_data.copy()
83
+
84
+ custom_fields = dict()
85
+ for key, value in zone_data.copy().items():
86
+ if key.startswith("cf_"):
87
+ custom_fields[key[3:]] = value
88
+ zone_data.pop(key)
89
+ if custom_fields:
90
+ zone_data["custom_field_data"] = custom_fields
91
+
92
+ zone_data.pop("template", None)
93
+ zone_data.pop("tenant_group", None)
94
+ zone_data.pop("_init_time", None)
95
+
96
+ nameservers = zone_data.pop("nameservers")
97
+ tags = zone_data.pop("tags")
98
+
99
+ zone = Zone.objects.create(**zone_data)
100
+
101
+ zone.nameservers.set(nameservers)
102
+ zone.tags.set(tags)
103
+
104
+ template.create_records(zone)
105
+ raise RollbackTransaction
106
+
107
+ except ValidationError as exc:
108
+ if isinstance(exc, dict):
109
+ template_error = item.value()
110
+ else:
111
+ template_error = [exc]
112
+ except RollbackTransaction:
113
+ pass
114
+
115
+ events_queue.set(saved_events_queue)
116
+ if template_error is not None:
117
+ raise ValidationError({"template": template_error})
118
+
119
+ return self.cleaned_data
120
+
121
+ def save(self, *args, **kwargs):
122
+ zone = super().save(*args, **kwargs)
123
+
124
+ if (template := self.cleaned_data.get("template")) is not None:
125
+ template.create_records(zone)
126
+
127
+ return zone
128
+
129
+
130
+ class ZoneForm(ZoneTemplateUpdateMixin, TenancyForm, NetBoxModelForm):
40
131
  nameservers = DynamicModelMultipleChoiceField(
41
132
  queryset=NameServer.objects.all(),
42
133
  required=False,
@@ -104,11 +195,17 @@ class ZoneForm(TenancyForm, NetBoxModelForm):
104
195
  help_text="IPv4 reverse zone for deletgating the RFC2317 PTR records is managed in NetBox DNS",
105
196
  required=False,
106
197
  )
198
+ template = DynamicModelChoiceField(
199
+ queryset=ZoneTemplate.objects.all(),
200
+ required=False,
201
+ label="Template",
202
+ )
107
203
 
108
204
  fieldsets = (
109
205
  FieldSet(
110
206
  "view",
111
207
  "name",
208
+ "template",
112
209
  "status",
113
210
  "nameservers",
114
211
  "default_ttl",
@@ -172,9 +269,6 @@ class ZoneForm(TenancyForm, NetBoxModelForm):
172
269
  if self.initial.get("soa_ttl") is None:
173
270
  self.initial["soa_ttl"] = self.initial.get("default_ttl")
174
271
 
175
- if self.initial.get("soa_serial_auto"):
176
- self.initial["soa_serial"] = None
177
-
178
272
  if self.initial.get("soa_mname") is None:
179
273
  default_soa_mname = defaults.get("zone_soa_mname")
180
274
  if default_soa_mname is not None:
@@ -206,6 +300,7 @@ class ZoneForm(TenancyForm, NetBoxModelForm):
206
300
  "name",
207
301
  "view",
208
302
  "status",
303
+ "template",
209
304
  "nameservers",
210
305
  "default_ttl",
211
306
  "description",
@@ -240,7 +335,12 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
240
335
  fieldsets = (
241
336
  FieldSet("q", "filter_id", "tag"),
242
337
  FieldSet(
243
- "view_id", "status", "name", "nameservers", "description", name="Attributes"
338
+ "view_id",
339
+ "status",
340
+ "name",
341
+ "nameserver_id",
342
+ "description",
343
+ name="Attributes",
244
344
  ),
245
345
  FieldSet(
246
346
  "soa_mname_id",
@@ -278,9 +378,10 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
278
378
  name = forms.CharField(
279
379
  required=False,
280
380
  )
281
- nameservers = DynamicModelMultipleChoiceField(
381
+ nameserver_id = DynamicModelMultipleChoiceField(
282
382
  queryset=NameServer.objects.all(),
283
383
  required=False,
384
+ label="Nameservers",
284
385
  )
285
386
  description = forms.CharField(
286
387
  required=False,
@@ -297,6 +398,7 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
297
398
  soa_serial_auto = forms.NullBooleanField(
298
399
  required=False,
299
400
  label="Generate Serial",
401
+ widget=forms.Select(choices=BOOLEAN_WITH_BLANK_CHOICES),
300
402
  )
301
403
  rfc2317_prefix = RFC2317NetworkFormField(
302
404
  required=False,
@@ -305,6 +407,7 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
305
407
  rfc2317_parent_managed = forms.NullBooleanField(
306
408
  required=False,
307
409
  label="Parent Managed",
410
+ widget=forms.Select(choices=BOOLEAN_WITH_BLANK_CHOICES),
308
411
  )
309
412
  rfc2317_parent_zone_id = DynamicModelMultipleChoiceField(
310
413
  queryset=Zone.objects.all(),
@@ -343,7 +446,7 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
343
446
  tag = TagFilterField(Zone)
344
447
 
345
448
 
346
- class ZoneImportForm(NetBoxModelImportForm):
449
+ class ZoneImportForm(ZoneTemplateUpdateMixin, NetBoxModelImportForm):
347
450
  view = CSVModelChoiceField(
348
451
  queryset=View.objects.all(),
349
452
  required=False,
@@ -385,7 +488,7 @@ class ZoneImportForm(NetBoxModelImportForm):
385
488
  required=False,
386
489
  help_text="Mailbox of the zone's administrator",
387
490
  )
388
- soa_serial_auto = forms.NullBooleanField(
491
+ soa_serial_auto = forms.BooleanField(
389
492
  required=False,
390
493
  help_text="Generate the SOA serial",
391
494
  )
@@ -473,6 +576,12 @@ class ZoneImportForm(NetBoxModelImportForm):
473
576
  to_field_name="name",
474
577
  help_text="Assigned tenant",
475
578
  )
579
+ template = CSVModelChoiceField(
580
+ queryset=ZoneTemplate.objects.all(),
581
+ required=False,
582
+ to_field_name="name",
583
+ label="Template",
584
+ )
476
585
 
477
586
  class Meta:
478
587
  model = Zone
@@ -481,6 +590,7 @@ class ZoneImportForm(NetBoxModelImportForm):
481
590
  "view",
482
591
  "name",
483
592
  "status",
593
+ "template",
484
594
  "nameservers",
485
595
  "default_ttl",
486
596
  "description",
@@ -532,9 +642,6 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
532
642
  queryset=View.objects.all(),
533
643
  required=False,
534
644
  label="View",
535
- widget=APISelect(
536
- attrs={"data-url": reverse_lazy("plugins-api:netbox_dns-api:view-list")}
537
- ),
538
645
  )
539
646
  status = forms.ChoiceField(
540
647
  choices=add_blank_choice(ZoneStatusChoices),
@@ -559,11 +666,6 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
559
666
  queryset=NameServer.objects.all(),
560
667
  required=False,
561
668
  label="SOA Primary Nameserver",
562
- widget=APISelect(
563
- attrs={
564
- "data-url": reverse_lazy("plugins-api:netbox_dns-api:nameserver-list")
565
- }
566
- ),
567
669
  )
568
670
  soa_rname = forms.CharField(
569
671
  required=False,
@@ -614,11 +716,6 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
614
716
  registrar = DynamicModelChoiceField(
615
717
  queryset=Registrar.objects.all(),
616
718
  required=False,
617
- widget=APISelect(
618
- attrs={
619
- "data-url": reverse_lazy("plugins-api:netbox_dns-api:registrar-list")
620
- }
621
- ),
622
719
  )
623
720
  registry_domain_id = forms.CharField(
624
721
  required=False,
@@ -627,41 +724,26 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
627
724
  registrant = DynamicModelChoiceField(
628
725
  queryset=Contact.objects.all(),
629
726
  required=False,
630
- widget=APISelect(
631
- attrs={"data-url": reverse_lazy("plugins-api:netbox_dns-api:contact-list")}
632
- ),
633
727
  )
634
728
  admin_c = DynamicModelChoiceField(
635
729
  queryset=Contact.objects.all(),
636
730
  required=False,
637
731
  label="Administrative Contact",
638
- widget=APISelect(
639
- attrs={"data-url": reverse_lazy("plugins-api:netbox_dns-api:contact-list")}
640
- ),
641
732
  )
642
733
  tech_c = DynamicModelChoiceField(
643
734
  queryset=Contact.objects.all(),
644
735
  required=False,
645
736
  label="Technical Contact",
646
- widget=APISelect(
647
- attrs={"data-url": reverse_lazy("plugins-api:netbox_dns-api:contact-list")}
648
- ),
649
737
  )
650
738
  billing_c = DynamicModelChoiceField(
651
739
  queryset=Contact.objects.all(),
652
740
  required=False,
653
741
  label="Billing Contact",
654
- widget=APISelect(
655
- attrs={"data-url": reverse_lazy("plugins-api:netbox_dns-api:contact-list")}
656
- ),
657
742
  )
658
- tenant = CSVModelChoiceField(
743
+ tenant = DynamicModelChoiceField(
659
744
  queryset=Tenant.objects.all(),
660
745
  required=False,
661
- to_field_name="name",
662
- help_text="Assigned tenant",
663
746
  )
664
- tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
665
747
 
666
748
  model = Zone
667
749
 
@@ -705,6 +787,7 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
705
787
 
706
788
  nullable_fields = (
707
789
  "description",
790
+ "nameservers",
708
791
  "rfc2317_prefix",
709
792
  "registrar",
710
793
  "registry_domain_id",
@@ -712,4 +795,5 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
712
795
  "admin_c",
713
796
  "tech_c",
714
797
  "billing_c",
798
+ "tenant",
715
799
  )
@@ -0,0 +1,298 @@
1
+ from django import forms
2
+
3
+ from netbox.forms import (
4
+ NetBoxModelBulkEditForm,
5
+ NetBoxModelFilterSetForm,
6
+ NetBoxModelImportForm,
7
+ NetBoxModelForm,
8
+ )
9
+ from utilities.forms.fields import (
10
+ DynamicModelMultipleChoiceField,
11
+ TagFilterField,
12
+ CSVModelChoiceField,
13
+ CSVModelMultipleChoiceField,
14
+ DynamicModelChoiceField,
15
+ )
16
+ from utilities.forms.rendering import FieldSet
17
+ from tenancy.models import Tenant
18
+ from tenancy.forms import TenancyForm, TenancyFilterForm
19
+
20
+ from netbox_dns.models import (
21
+ ZoneTemplate,
22
+ RecordTemplate,
23
+ NameServer,
24
+ Registrar,
25
+ Contact,
26
+ )
27
+
28
+
29
+ __all__ = (
30
+ "ZoneTemplateForm",
31
+ "ZoneTemplateFilterForm",
32
+ "ZoneTemplateImportForm",
33
+ "ZoneTemplateBulkEditForm",
34
+ )
35
+
36
+
37
+ class ZoneTemplateForm(TenancyForm, NetBoxModelForm):
38
+ nameservers = DynamicModelMultipleChoiceField(
39
+ queryset=NameServer.objects.all(),
40
+ required=False,
41
+ )
42
+ record_templates = DynamicModelMultipleChoiceField(
43
+ queryset=RecordTemplate.objects.all(),
44
+ required=False,
45
+ )
46
+
47
+ fieldsets = (
48
+ FieldSet("name", "description", "nameservers", name="Zone Template"),
49
+ FieldSet("record_templates", name="Record Templates"),
50
+ FieldSet(
51
+ "registrar",
52
+ "registrant",
53
+ "admin_c",
54
+ "tech_c",
55
+ "billing_c",
56
+ name="Domain Registration",
57
+ ),
58
+ FieldSet("tags", name="Tags"),
59
+ FieldSet("tenant_group", "tenant", name="Tenancy"),
60
+ )
61
+
62
+ class Meta:
63
+ model = ZoneTemplate
64
+
65
+ fields = (
66
+ "name",
67
+ "nameservers",
68
+ "record_templates",
69
+ "description",
70
+ "tags",
71
+ "registrar",
72
+ "registrant",
73
+ "admin_c",
74
+ "tech_c",
75
+ "billing_c",
76
+ "tenant",
77
+ )
78
+
79
+
80
+ class ZoneTemplateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
81
+ model = ZoneTemplate
82
+ fieldsets = (
83
+ FieldSet("q", "filter_id", "tag"),
84
+ FieldSet("name", "nameserver_id", "description", name="Attributes"),
85
+ FieldSet("record_template_id", name="Record Templates"),
86
+ FieldSet(
87
+ "registrar_id",
88
+ "registrant_id",
89
+ "admin_c_id",
90
+ "tech_c_id",
91
+ "billing_c_id",
92
+ name="Registration",
93
+ ),
94
+ FieldSet("tenant_group_id", "tenant_id", name="Tenancy"),
95
+ )
96
+
97
+ name = forms.CharField(
98
+ required=False,
99
+ label="Template name",
100
+ )
101
+ nameserver_id = DynamicModelMultipleChoiceField(
102
+ queryset=NameServer.objects.all(),
103
+ required=False,
104
+ label="Nameservers",
105
+ )
106
+ record_template_id = DynamicModelMultipleChoiceField(
107
+ queryset=RecordTemplate.objects.all(),
108
+ required=False,
109
+ label="Record templates",
110
+ )
111
+ description = forms.CharField(
112
+ required=False,
113
+ )
114
+ registrar_id = DynamicModelMultipleChoiceField(
115
+ queryset=Registrar.objects.all(),
116
+ required=False,
117
+ label="Registrar",
118
+ )
119
+ registrant_id = DynamicModelMultipleChoiceField(
120
+ queryset=Contact.objects.all(),
121
+ required=False,
122
+ label="Registrant",
123
+ )
124
+ admin_c_id = DynamicModelMultipleChoiceField(
125
+ queryset=Contact.objects.all(),
126
+ required=False,
127
+ label="Admin-C",
128
+ )
129
+ tech_c_id = DynamicModelMultipleChoiceField(
130
+ queryset=Contact.objects.all(),
131
+ required=False,
132
+ label="Tech-C",
133
+ )
134
+ billing_c_id = DynamicModelMultipleChoiceField(
135
+ queryset=Contact.objects.all(),
136
+ required=False,
137
+ label="Billing-C",
138
+ )
139
+ tag = TagFilterField(ZoneTemplate)
140
+
141
+
142
+ class ZoneTemplateImportForm(NetBoxModelImportForm):
143
+ nameservers = CSVModelMultipleChoiceField(
144
+ queryset=NameServer.objects.all(),
145
+ to_field_name="name",
146
+ required=False,
147
+ help_text="Name servers for the zone template",
148
+ )
149
+ record_templates = CSVModelMultipleChoiceField(
150
+ queryset=RecordTemplate.objects.all(),
151
+ to_field_name="name",
152
+ required=False,
153
+ help_text="Record templates used by this zone template",
154
+ )
155
+ registrar = CSVModelChoiceField(
156
+ queryset=Registrar.objects.all(),
157
+ required=False,
158
+ to_field_name="name",
159
+ help_text="Registrar the domain is registered with",
160
+ error_messages={
161
+ "invalid_choice": "Registrar not found.",
162
+ },
163
+ )
164
+ registrant = CSVModelChoiceField(
165
+ queryset=Contact.objects.all(),
166
+ required=False,
167
+ to_field_name="contact_id",
168
+ help_text="Owner of the domain",
169
+ error_messages={
170
+ "invalid_choice": "Registrant contact ID not found",
171
+ },
172
+ )
173
+ admin_c = CSVModelChoiceField(
174
+ queryset=Contact.objects.all(),
175
+ required=False,
176
+ to_field_name="contact_id",
177
+ help_text="Administrative contact for the domain",
178
+ error_messages={
179
+ "invalid_choice": "Administrative contact ID not found",
180
+ },
181
+ )
182
+ tech_c = CSVModelChoiceField(
183
+ queryset=Contact.objects.all(),
184
+ required=False,
185
+ to_field_name="contact_id",
186
+ help_text="Technical contact for the domain",
187
+ error_messages={
188
+ "invalid_choice": "Technical contact ID not found",
189
+ },
190
+ )
191
+ billing_c = CSVModelChoiceField(
192
+ queryset=Contact.objects.all(),
193
+ required=False,
194
+ to_field_name="contact_id",
195
+ help_text="Billing contact for the domain",
196
+ error_messages={
197
+ "invalid_choice": "Billing contact ID not found",
198
+ },
199
+ )
200
+ tenant = CSVModelChoiceField(
201
+ queryset=Tenant.objects.all(),
202
+ required=False,
203
+ to_field_name="name",
204
+ help_text="Assigned tenant",
205
+ )
206
+
207
+ class Meta:
208
+ model = ZoneTemplate
209
+
210
+ fields = (
211
+ "name",
212
+ "nameservers",
213
+ "record_templates",
214
+ "description",
215
+ "registrar",
216
+ "registrant",
217
+ "admin_c",
218
+ "tech_c",
219
+ "billing_c",
220
+ "tenant",
221
+ "tags",
222
+ )
223
+
224
+
225
+ class ZoneTemplateBulkEditForm(NetBoxModelBulkEditForm):
226
+ nameservers = DynamicModelMultipleChoiceField(
227
+ queryset=NameServer.objects.all(),
228
+ required=False,
229
+ )
230
+ record_templates = DynamicModelMultipleChoiceField(
231
+ queryset=RecordTemplate.objects.all(),
232
+ required=False,
233
+ )
234
+ description = forms.CharField(max_length=200, required=False)
235
+ registrar = DynamicModelChoiceField(
236
+ queryset=Registrar.objects.all(),
237
+ required=False,
238
+ )
239
+ registrant = DynamicModelChoiceField(
240
+ queryset=Contact.objects.all(),
241
+ required=False,
242
+ )
243
+ admin_c = DynamicModelChoiceField(
244
+ queryset=Contact.objects.all(),
245
+ required=False,
246
+ label="Administrative Contact",
247
+ )
248
+ tech_c = DynamicModelChoiceField(
249
+ queryset=Contact.objects.all(),
250
+ required=False,
251
+ label="Technical Contact",
252
+ )
253
+ billing_c = DynamicModelChoiceField(
254
+ queryset=Contact.objects.all(),
255
+ required=False,
256
+ label="Billing Contact",
257
+ )
258
+ tenant = CSVModelChoiceField(
259
+ queryset=Tenant.objects.all(),
260
+ required=False,
261
+ to_field_name="name",
262
+ help_text="Assigned tenant",
263
+ )
264
+ tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
265
+
266
+ model = ZoneTemplate
267
+
268
+ fieldsets = (
269
+ FieldSet(
270
+ "nameservers",
271
+ "description",
272
+ name="Attributes",
273
+ ),
274
+ FieldSet(
275
+ "record_templates",
276
+ name="Record Templates",
277
+ ),
278
+ FieldSet(
279
+ "registrar",
280
+ "registrant",
281
+ "admin_c",
282
+ "tech_c",
283
+ "billing_c",
284
+ name="Domain Registration",
285
+ ),
286
+ FieldSet("tenant_group", "tenant", name="Tenancy"),
287
+ )
288
+
289
+ nullable_fields = (
290
+ "description",
291
+ "nameservers",
292
+ "record_templates",
293
+ "registrar",
294
+ "registrant",
295
+ "admin_c",
296
+ "tech_c",
297
+ "billing_c",
298
+ )
@@ -5,6 +5,8 @@ from .schema import (
5
5
  NetBoxDNSRegistrarQuery,
6
6
  NetBoxDNSZoneQuery,
7
7
  NetBoxDNSRecordQuery,
8
+ NetBoxDNSZoneTemplateQuery,
9
+ NetBoxDNSRecordTemplateQuery,
8
10
  )
9
11
 
10
12
  schema = [
@@ -14,4 +16,6 @@ schema = [
14
16
  NetBoxDNSRecordQuery,
15
17
  NetBoxDNSContactQuery,
16
18
  NetBoxDNSRegistrarQuery,
19
+ NetBoxDNSZoneTemplateQuery,
20
+ NetBoxDNSRecordTemplateQuery,
17
21
  ]
@@ -2,7 +2,16 @@ import strawberry_django
2
2
 
3
3
  from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin
4
4
 
5
- from netbox_dns.models import NameServer, View, Zone, Record, Contact, Registrar
5
+ from netbox_dns.models import (
6
+ NameServer,
7
+ View,
8
+ Zone,
9
+ Record,
10
+ Contact,
11
+ Registrar,
12
+ ZoneTemplate,
13
+ RecordTemplate,
14
+ )
6
15
  from netbox_dns.filtersets import (
7
16
  NameServerFilterSet,
8
17
  ViewFilterSet,
@@ -10,6 +19,8 @@ from netbox_dns.filtersets import (
10
19
  RecordFilterSet,
11
20
  ContactFilterSet,
12
21
  RegistrarFilterSet,
22
+ ZoneTemplateFilterSet,
23
+ RecordTemplateFilterSet,
13
24
  )
14
25
 
15
26
 
@@ -37,6 +48,18 @@ class NetBoxDNSRecordFilter(BaseFilterMixin):
37
48
  ip_address: str | None
38
49
 
39
50
 
51
+ @strawberry_django.filter(ZoneTemplate, lookups=True)
52
+ @autotype_decorator(ZoneTemplateFilterSet)
53
+ class NetBoxDNSZoneTemplateFilter(BaseFilterMixin):
54
+ pass
55
+
56
+
57
+ @strawberry_django.filter(RecordTemplate, lookups=True)
58
+ @autotype_decorator(RecordTemplateFilterSet)
59
+ class NetBoxDNSRecordTemplateFilter(BaseFilterMixin):
60
+ pass
61
+
62
+
40
63
  @strawberry_django.filter(Contact, lookups=True)
41
64
  @autotype_decorator(ContactFilterSet)
42
65
  class NetBoxDNSContactFilter(BaseFilterMixin):