netbox-plugin-dns 1.0b2__py3-none-any.whl → 1.0.1__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 (38) hide show
  1. netbox_dns/__init__.py +3 -3
  2. netbox_dns/api/serializers_/view.py +6 -1
  3. netbox_dns/fields/network.py +20 -21
  4. netbox_dns/fields/rfc2317.py +2 -2
  5. netbox_dns/filtersets/view.py +1 -1
  6. netbox_dns/filtersets/zone.py +4 -4
  7. netbox_dns/forms/record.py +30 -2
  8. netbox_dns/forms/view.py +6 -3
  9. netbox_dns/forms/zone.py +71 -102
  10. netbox_dns/graphql/types.py +1 -4
  11. netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +4 -2
  12. netbox_dns/migrations/0003_default_view.py +15 -0
  13. netbox_dns/migrations/0004_create_and_assign_default_view.py +26 -0
  14. netbox_dns/migrations/0005_alter_zone_view_not_null.py +18 -0
  15. netbox_dns/models/nameserver.py +3 -1
  16. netbox_dns/models/record.py +84 -31
  17. netbox_dns/models/view.py +53 -0
  18. netbox_dns/models/zone.py +91 -46
  19. netbox_dns/signals/ipam_coupling.py +1 -2
  20. netbox_dns/tables/view.py +12 -2
  21. netbox_dns/template_content.py +1 -1
  22. netbox_dns/templates/netbox_dns/record.html +1 -1
  23. netbox_dns/templates/netbox_dns/view.html +4 -0
  24. netbox_dns/templates/netbox_dns/zone.html +2 -4
  25. netbox_dns/urls/__init__.py +17 -0
  26. netbox_dns/urls/contact.py +51 -0
  27. netbox_dns/urls/nameserver.py +69 -0
  28. netbox_dns/urls/record.py +41 -0
  29. netbox_dns/urls/registrar.py +63 -0
  30. netbox_dns/urls/view.py +39 -0
  31. netbox_dns/urls/zone.py +57 -0
  32. netbox_dns/validators/dns_name.py +24 -11
  33. netbox_dns/views/record.py +10 -18
  34. {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.1.dist-info}/METADATA +14 -14
  35. {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.1.dist-info}/RECORD +37 -28
  36. netbox_dns/urls.py +0 -297
  37. {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.1.dist-info}/LICENSE +0 -0
  38. {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.1.dist-info}/WHEEL +0 -0
netbox_dns/__init__.py CHANGED
@@ -1,20 +1,20 @@
1
1
  from netbox.plugins import PluginConfig
2
2
 
3
- __version__ = "1.0-beta2"
3
+ __version__ = "1.0.1"
4
4
 
5
5
 
6
6
  class DNSConfig(PluginConfig):
7
7
  name = "netbox_dns"
8
8
  verbose_name = "NetBox DNS"
9
9
  description = "NetBox plugin for DNS data"
10
- min_version = "4.0-beta1"
10
+ min_version = "4.0.0"
11
11
  version = __version__
12
12
  author = "Peter Eckel"
13
13
  author_email = "pete@netbox-dns.org"
14
14
  required_settings = []
15
15
  default_settings = {
16
16
  "zone_default_ttl": 86400,
17
- "zone_soa_serial_auto": True,
17
+ "zone_soa_ttl": 86400,
18
18
  "zone_soa_serial": 1,
19
19
  "zone_soa_refresh": 43200,
20
20
  "zone_soa_retry": 7200,
@@ -10,6 +10,10 @@ class ViewSerializer(NetBoxModelSerializer):
10
10
  url = serializers.HyperlinkedIdentityField(
11
11
  view_name="plugins-api:netbox_dns-api:view-detail"
12
12
  )
13
+ default_view = serializers.BooleanField(
14
+ read_only=True,
15
+ )
16
+
13
17
  tenant = TenantSerializer(nested=True, required=False, allow_null=True)
14
18
 
15
19
  class Meta:
@@ -19,6 +23,7 @@ class ViewSerializer(NetBoxModelSerializer):
19
23
  "url",
20
24
  "display",
21
25
  "name",
26
+ "default_view",
22
27
  "tags",
23
28
  "description",
24
29
  "created",
@@ -26,4 +31,4 @@ class ViewSerializer(NetBoxModelSerializer):
26
31
  "custom_fields",
27
32
  "tenant",
28
33
  )
29
- brief_fields = ("id", "url", "display", "name", "description")
34
+ brief_fields = ("id", "url", "display", "name", "default_view", "description")
@@ -9,51 +9,51 @@ from netaddr import AddrFormatError, IPNetwork
9
9
  class NetContains(Lookup):
10
10
  lookup_name = "net_contains"
11
11
 
12
- def as_sql(self, qn, connection):
13
- lhs, lhs_params = self.process_lhs(qn, connection)
14
- rhs, rhs_params = self.process_rhs(qn, connection)
12
+ def as_sql(self, compiler, connection):
13
+ lhs, lhs_params = self.process_lhs(compiler, connection)
14
+ rhs, rhs_params = self.process_rhs(compiler, connection)
15
15
  params = lhs_params + rhs_params
16
- return "%s >> %s" % (lhs, rhs), params
16
+ return f"{lhs} >> {rhs}", params
17
17
 
18
18
 
19
19
  class NetContainsOrEquals(Lookup):
20
20
  lookup_name = "net_contains_or_equals"
21
21
 
22
- def as_sql(self, qn, connection):
23
- lhs, lhs_params = self.process_lhs(qn, connection)
24
- rhs, rhs_params = self.process_rhs(qn, connection)
22
+ def as_sql(self, compiler, connection):
23
+ lhs, lhs_params = self.process_lhs(compiler, connection)
24
+ rhs, rhs_params = self.process_rhs(compiler, connection)
25
25
  params = lhs_params + rhs_params
26
- return "%s >>= %s" % (lhs, rhs), params
26
+ return f"{lhs} >>= {rhs}", params
27
27
 
28
28
 
29
29
  class NetContained(Lookup):
30
30
  lookup_name = "net_contained"
31
31
 
32
- def as_sql(self, qn, connection):
33
- lhs, lhs_params = self.process_lhs(qn, connection)
34
- rhs, rhs_params = self.process_rhs(qn, connection)
32
+ def as_sql(self, compiler, connection):
33
+ lhs, lhs_params = self.process_lhs(compiler, connection)
34
+ rhs, rhs_params = self.process_rhs(compiler, connection)
35
35
  params = lhs_params + rhs_params
36
- return "%s << %s" % (lhs, rhs), params
36
+ return f"{lhs} << {rhs}", params
37
37
 
38
38
 
39
39
  class NetContainedOrEqual(Lookup):
40
40
  lookup_name = "net_contained_or_equal"
41
41
 
42
- def as_sql(self, qn, connection):
43
- lhs, lhs_params = self.process_lhs(qn, connection)
44
- rhs, rhs_params = self.process_rhs(qn, connection)
42
+ def as_sql(self, compiler, connection):
43
+ lhs, lhs_params = self.process_lhs(compiler, connection)
44
+ rhs, rhs_params = self.process_rhs(compiler, connection)
45
45
  params = lhs_params + rhs_params
46
- return "%s <<= %s" % (lhs, rhs), params
46
+ return f"{lhs} <<= {rhs}", params
47
47
 
48
48
 
49
49
  class NetOverlap(Lookup):
50
50
  lookup_name = "net_overlap"
51
51
 
52
- def as_sql(self, qn, connection):
53
- lhs, lhs_params = self.process_lhs(qn, connection)
54
- rhs, rhs_params = self.process_rhs(qn, connection)
52
+ def as_sql(self, compiler, connection):
53
+ lhs, lhs_params = self.process_lhs(compiler, connection)
54
+ rhs, rhs_params = self.process_rhs(compiler, connection)
55
55
  params = lhs_params + rhs_params
56
- return "%s && %s" % (lhs, rhs), params
56
+ return f"{lhs} && {rhs}", params
57
57
 
58
58
 
59
59
  class NetworkFormField(forms.Field):
@@ -118,7 +118,6 @@ class NetMaskLength(Transform):
118
118
  function = "MASKLEN"
119
119
  lookup_name = "net_mask_length"
120
120
 
121
- @property
122
121
  def output_field(self):
123
122
  return IntegerField()
124
123
 
@@ -18,8 +18,8 @@ class RFC2317NetworkFormField(forms.Field):
18
18
  if isinstance(value, IPNetwork):
19
19
  if value.version == 4 and value.prefixlen > 24:
20
20
  return value
21
- else:
22
- raise ValidationError(INVALID_RFC2317)
21
+
22
+ raise ValidationError(INVALID_RFC2317)
23
23
 
24
24
  if len(value.split("/")) != 2:
25
25
  raise ValidationError("Please specify the prefix length")
@@ -9,7 +9,7 @@ from netbox_dns.models import View
9
9
  class ViewFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
10
10
  class Meta:
11
11
  model = View
12
- fields = ("id", "name", "description")
12
+ fields = ("id", "name", "default_view", "description")
13
13
 
14
14
  def search(self, queryset, name, value):
15
15
  if not value.strip():
@@ -31,14 +31,14 @@ class ZoneFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
31
31
  to_field_name="name",
32
32
  label="View",
33
33
  )
34
- # DEPRECATED: Remove in 1.0
34
+ # DEPRECATED: Remove in 1.1
35
35
  name_server_id = django_filters.ModelMultipleChoiceFilter(
36
36
  queryset=NameServer.objects.all(),
37
37
  field_name="nameservers",
38
38
  to_field_name="id",
39
39
  label="Nameserver IDs",
40
40
  )
41
- # DEPRECATED: Remove in 1.0
41
+ # DEPRECATED: Remove in 1.1
42
42
  name_server = django_filters.ModelMultipleChoiceFilter(
43
43
  queryset=NameServer.objects.all(),
44
44
  field_name="nameservers__name",
@@ -59,13 +59,13 @@ class ZoneFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
59
59
  )
60
60
  soa_mname_id = django_filters.ModelMultipleChoiceFilter(
61
61
  queryset=NameServer.objects.all(),
62
- label="SOA MNname ID",
62
+ label="SOA MName ID",
63
63
  )
64
64
  soa_mname = django_filters.ModelMultipleChoiceFilter(
65
65
  queryset=NameServer.objects.all(),
66
66
  field_name="soa_mname__name",
67
67
  to_field_name="name",
68
- label="SOA MNname",
68
+ label="SOA MName",
69
69
  )
70
70
  arpa_network = MultiValueCharFilter(
71
71
  method="filter_arpa_network",
@@ -28,10 +28,30 @@ class RecordForm(TenancyForm, NetBoxModelForm):
28
28
  def __init__(self, *args, **kwargs):
29
29
  super().__init__(*args, **kwargs)
30
30
 
31
+ initial_zone_id = self.initial.get("zone")
32
+ if initial_zone_id is not None:
33
+ self.initial["view"] = Zone.objects.get(pk=initial_zone_id).view
34
+ else:
35
+ self.initial["view"] = View.get_default_view()
36
+
31
37
  initial_name = self.initial.get("name")
32
38
  if initial_name:
33
39
  self.initial["name"] = name_to_unicode(initial_name)
34
40
 
41
+ view = DynamicModelChoiceField(
42
+ queryset=View.objects.all(),
43
+ required=False,
44
+ label="View",
45
+ )
46
+ zone = DynamicModelChoiceField(
47
+ queryset=Zone.objects.all(),
48
+ required=True,
49
+ query_params={
50
+ "view_id": "$view",
51
+ },
52
+ label="Zone",
53
+ )
54
+
35
55
  disable_ptr = forms.BooleanField(
36
56
  label="Disable PTR",
37
57
  required=False,
@@ -44,6 +64,7 @@ class RecordForm(TenancyForm, NetBoxModelForm):
44
64
  fieldsets = (
45
65
  FieldSet(
46
66
  "name",
67
+ "view",
47
68
  "zone",
48
69
  "type",
49
70
  "value",
@@ -84,6 +105,7 @@ class RecordFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
84
105
  "fqdn",
85
106
  "type",
86
107
  "value",
108
+ "disable_ptr",
87
109
  "status",
88
110
  "description",
89
111
  name="Attributes",
@@ -105,6 +127,10 @@ class RecordFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
105
127
  value = forms.CharField(
106
128
  required=False,
107
129
  )
130
+ disable_ptr = forms.NullBooleanField(
131
+ required=False,
132
+ label="Disable PTR",
133
+ )
108
134
  status = forms.MultipleChoiceField(
109
135
  choices=RecordStatusChoices,
110
136
  required=False,
@@ -131,10 +157,12 @@ class RecordImportForm(NetBoxModelImportForm):
131
157
  except forms.ValidationError:
132
158
  pass
133
159
 
134
- if view:
160
+ if view is not None:
135
161
  self.fields["zone"].queryset = Zone.objects.filter(view=view)
136
162
  else:
137
- self.fields["zone"].queryset = Zone.objects.filter(view__isnull=True)
163
+ self.fields["zone"].queryset = Zone.objects.filter(
164
+ view=View.get_default_view()
165
+ )
138
166
 
139
167
  zone = CSVModelChoiceField(
140
168
  queryset=Zone.objects.all(),
netbox_dns/forms/view.py CHANGED
@@ -20,26 +20,29 @@ from netbox_dns.models import View
20
20
 
21
21
  class ViewForm(TenancyForm, NetBoxModelForm):
22
22
  fieldsets = (
23
- FieldSet("name", "description", "tags", name="View"),
23
+ FieldSet("name", "default_view", "description", "tags", name="View"),
24
24
  FieldSet("tenant_group", "tenant", name="Tenancy"),
25
25
  )
26
26
 
27
27
  class Meta:
28
28
  model = View
29
- fields = ("name", "description", "tags", "tenant")
29
+ fields = ("name", "default_view", "description", "tags", "tenant")
30
30
 
31
31
 
32
32
  class ViewFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
33
33
  model = View
34
34
  fieldsets = (
35
35
  FieldSet("q", "filter_id", "tag"),
36
- FieldSet("name", "description", name="Attributes"),
36
+ FieldSet("name", "default_view", "description", name="Attributes"),
37
37
  FieldSet("tenant_group_id", "tenant_id", name="Tenancy"),
38
38
  )
39
39
 
40
40
  name = forms.CharField(
41
41
  required=False,
42
42
  )
43
+ default_view = forms.NullBooleanField(
44
+ required=False,
45
+ )
43
46
  description = forms.CharField(
44
47
  required=False,
45
48
  )
netbox_dns/forms/zone.py CHANGED
@@ -1,6 +1,5 @@
1
1
  from django import forms
2
2
  from django.conf import settings
3
- from django.core.exceptions import ValidationError
4
3
  from django.core.validators import MinValueValidator, MaxValueValidator
5
4
  from django.urls import reverse_lazy
6
5
 
@@ -56,7 +55,7 @@ class ZoneForm(TenancyForm, NetBoxModelForm):
56
55
  )
57
56
  soa_rname = forms.CharField(
58
57
  required=True,
59
- label="SOA Responsible",
58
+ label="SOA RName",
60
59
  help_text="Mailbox of the zone's administrator",
61
60
  )
62
61
  soa_serial_auto = forms.BooleanField(
@@ -143,23 +142,20 @@ class ZoneForm(TenancyForm, NetBoxModelForm):
143
142
  name="Domain Registration",
144
143
  ),
145
144
  FieldSet("tags", name="Tags"),
146
- FieldSet("tenant", name="Tenancy"),
145
+ FieldSet("tenant_group", "tenant", name="Tenancy"),
147
146
  )
148
147
 
149
148
  def __init__(self, *args, **kwargs):
150
- """Override the __init__ method in order to provide the initial value for the default fields"""
151
149
  super().__init__(*args, **kwargs)
152
150
 
153
151
  initial_name = self.initial.get("name")
154
152
  if initial_name:
155
153
  self.initial["name"] = name_to_unicode(initial_name)
156
154
 
157
- defaults = settings.PLUGINS_CONFIG.get("netbox_dns")
158
-
159
- def _initialize(initial, setting):
160
- if initial.get(setting, None) in (None, ""):
161
- initial[setting] = defaults.get(f"zone_{setting}", None)
155
+ if self.initial.get("view") is None:
156
+ self.initial["view"] = View.get_default_view()
162
157
 
158
+ defaults = settings.PLUGINS_CONFIG.get("netbox_dns")
163
159
  for setting in (
164
160
  "default_ttl",
165
161
  "soa_ttl",
@@ -170,16 +166,17 @@ class ZoneForm(TenancyForm, NetBoxModelForm):
170
166
  "soa_expire",
171
167
  "soa_minimum",
172
168
  ):
173
- _initialize(self.initial, setting)
169
+ if self.initial.get(setting) in (None, ""):
170
+ self.initial[setting] = defaults.get(f"zone_{setting}")
174
171
 
175
- if self.initial.get("soa_ttl", None) is None:
176
- self.initial["soa_ttl"] = self.initial.get("default_ttl", None)
172
+ if self.initial.get("soa_ttl") is None:
173
+ self.initial["soa_ttl"] = self.initial.get("default_ttl")
177
174
 
178
175
  if self.initial.get("soa_serial_auto"):
179
176
  self.initial["soa_serial"] = None
180
177
 
181
- if self.initial.get("soa_mname", None) in (None, ""):
182
- default_soa_mname = defaults.get("zone_soa_mname", None)
178
+ if self.initial.get("soa_mname") is None:
179
+ default_soa_mname = defaults.get("zone_soa_mname")
183
180
  if default_soa_mname is not None:
184
181
  try:
185
182
  self.initial["soa_mname"] = NameServer.objects.get(
@@ -245,6 +242,18 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
245
242
  FieldSet(
246
243
  "view_id", "status", "name", "nameservers", "description", name="Attributes"
247
244
  ),
245
+ FieldSet(
246
+ "soa_mname_id",
247
+ "soa_rname",
248
+ "soa_serial_auto",
249
+ name="SOA",
250
+ ),
251
+ FieldSet(
252
+ "rfc2317_prefix",
253
+ "rfc2317_parent_managed",
254
+ "rfc2317_parent_zone_id",
255
+ name="RFC2317",
256
+ ),
248
257
  FieldSet(
249
258
  "registrar_id",
250
259
  "registry_domain_id",
@@ -276,6 +285,32 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
276
285
  description = forms.CharField(
277
286
  required=False,
278
287
  )
288
+ soa_mname_id = DynamicModelMultipleChoiceField(
289
+ queryset=NameServer.objects.all(),
290
+ label="MName",
291
+ required=False,
292
+ )
293
+ soa_rname = forms.CharField(
294
+ required=False,
295
+ label="RName",
296
+ )
297
+ soa_serial_auto = forms.NullBooleanField(
298
+ required=False,
299
+ label="Generate Serial",
300
+ )
301
+ rfc2317_prefix = RFC2317NetworkFormField(
302
+ required=False,
303
+ label="Prefix",
304
+ )
305
+ rfc2317_parent_managed = forms.NullBooleanField(
306
+ required=False,
307
+ label="Parent Managed",
308
+ )
309
+ rfc2317_parent_zone_id = DynamicModelMultipleChoiceField(
310
+ queryset=Zone.objects.all(),
311
+ required=False,
312
+ label="Parent Zone",
313
+ )
279
314
  registrar_id = DynamicModelMultipleChoiceField(
280
315
  queryset=Registrar.objects.all(),
281
316
  required=False,
@@ -439,87 +474,6 @@ class ZoneImportForm(NetBoxModelImportForm):
439
474
  help_text="Assigned tenant",
440
475
  )
441
476
 
442
- def _get_default_value(self, field):
443
- _default_values = settings.PLUGINS_CONFIG.get("netbox_dns", {})
444
- if _default_values.get("zone_soa_ttl", None) is None:
445
- _default_values["zone_soa_ttl"] = _default_values.get(
446
- "zone_default_ttl", None
447
- )
448
-
449
- return _default_values.get(f"zone_{field}", None)
450
-
451
- def _clean_field_with_defaults(self, field):
452
- if self.cleaned_data[field]:
453
- value = self.cleaned_data[field]
454
- else:
455
- value = self._get_default_value(field)
456
-
457
- if value is None:
458
- raise ValidationError(f"{field} not set and no default value available")
459
-
460
- return value
461
-
462
- def clean_default_ttl(self):
463
- return self._clean_field_with_defaults("default_ttl")
464
-
465
- def clean_soa_ttl(self):
466
- return self._clean_field_with_defaults("soa_ttl")
467
-
468
- def clean_soa_mname(self):
469
- soa_mname = self._clean_field_with_defaults("soa_mname")
470
- if isinstance(soa_mname, str):
471
- try:
472
- soa_mname = NameServer.objects.get(name=soa_mname)
473
- except NameServer.DoesNotExist:
474
- raise ValidationError(f"Default name server {soa_mname} does not exist")
475
-
476
- return soa_mname
477
-
478
- def clean_soa_rname(self):
479
- return self._clean_field_with_defaults("soa_rname")
480
-
481
- def clean_soa_refresh(self):
482
- return self._clean_field_with_defaults("soa_refresh")
483
-
484
- def clean_soa_retry(self):
485
- return self._clean_field_with_defaults("soa_retry")
486
-
487
- def clean_soa_expire(self):
488
- return self._clean_field_with_defaults("soa_expire")
489
-
490
- def clean_soa_minimum(self):
491
- return self._clean_field_with_defaults("soa_minimum")
492
-
493
- def clean(self, *args, **kwargs):
494
- super().clean(*args, **kwargs)
495
-
496
- soa_serial_auto = self.cleaned_data.get("soa_serial_auto")
497
- soa_serial = self.cleaned_data.get("soa_serial")
498
-
499
- if soa_serial is None:
500
- soa_serial = self._get_default_value("soa_serial")
501
-
502
- if soa_serial_auto is None:
503
- if self._get_default_value("soa_serial_auto") is not None:
504
- soa_serial_auto = self._get_default_value("soa_serial_auto")
505
-
506
- elif soa_serial is not None:
507
- soa_serial_auto = False
508
-
509
- else:
510
- raise ValidationError(
511
- "SOA Serial Auto not set and no default value and SOA Serial available"
512
- )
513
-
514
- if "soa_serial_auto" in self.cleaned_data:
515
- self.cleaned_data["soa_serial_auto"] = soa_serial_auto
516
-
517
- if "soa_serial" in self.cleaned_data:
518
- if soa_serial_auto:
519
- self.cleaned_data["soa_serial"] = None
520
- else:
521
- self.cleaned_data["soa_serial"] = soa_serial
522
-
523
477
  class Meta:
524
478
  model = Zone
525
479
 
@@ -551,6 +505,27 @@ class ZoneImportForm(NetBoxModelImportForm):
551
505
  "tags",
552
506
  )
553
507
 
508
+ def clean_view(self):
509
+ view = self.cleaned_data.get("view")
510
+ if view is None:
511
+ return View.get_default_view()
512
+
513
+ return view
514
+
515
+ def clean_nameservers(self):
516
+ nameservers = self.cleaned_data.get("nameservers")
517
+ zone_defaults = settings.PLUGINS_CONFIG.get("netbox_dns")
518
+
519
+ if (
520
+ self.data.get("nameservers") is None
521
+ and zone_defaults.get("zone_nameservers") is not None
522
+ ):
523
+ nameservers = NameServer.objects.filter(
524
+ name__in=zone_defaults.get("zone_nameservers")
525
+ )
526
+
527
+ return nameservers
528
+
554
529
 
555
530
  class ZoneBulkEditForm(NetBoxModelBulkEditForm):
556
531
  view = DynamicModelChoiceField(
@@ -592,7 +567,7 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
592
567
  )
593
568
  soa_rname = forms.CharField(
594
569
  required=False,
595
- label="SOA Responsible",
570
+ label="SOA RName",
596
571
  )
597
572
  soa_serial_auto = forms.NullBooleanField(
598
573
  required=False,
@@ -729,7 +704,6 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
729
704
  )
730
705
 
731
706
  nullable_fields = (
732
- "view",
733
707
  "description",
734
708
  "rfc2317_prefix",
735
709
  "registrar",
@@ -739,8 +713,3 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
739
713
  "tech_c",
740
714
  "billing_c",
741
715
  )
742
-
743
- def clean(self):
744
- cleaned_data = super().clean()
745
- if cleaned_data.get("soa_serial_auto"):
746
- cleaned_data["soa_serial"] = None
@@ -36,10 +36,7 @@ class NetBoxDNSZoneType(NetBoxObjectType):
36
36
  name: str
37
37
  status: str
38
38
  active: bool
39
- view: (
40
- Annotated["NetBoxDNSViewType", strawberry.lazy("netbox_dns.graphql.types")]
41
- | None
42
- )
39
+ view: Annotated["NetBoxDNSViewType", strawberry.lazy("netbox_dns.graphql.types")]
43
40
  nameservers: (
44
41
  Annotated[
45
42
  "NetBoxDNSNameServerType", strawberry.lazy("netbox_dns.graphql.types")
@@ -1,5 +1,7 @@
1
1
  # Generated by Django 5.0.1 on 2024-02-12 14:49
2
2
 
3
+ from dns import name as dns_name
4
+
3
5
  import django.core.validators
4
6
  import django.db.models.deletion
5
7
  import netbox_dns.fields.address
@@ -48,9 +50,9 @@ def update_record_fqdn(apps, schema_editor):
48
50
 
49
51
  for record in Record.objects.filter(fqdn__isnull=True):
50
52
  zone = dns_name.from_text(record.zone.name, origin=dns_name.root)
51
- fqdn = dns_name.from_text(record.name, origin=zone)
53
+ _fqdn = dns_name.from_text(record.name, origin=zone)
52
54
 
53
- record.fqdn = fqdn.to_text()
55
+ record.fqdn = _fqdn.to_text()
54
56
 
55
57
  record.save()
56
58
 
@@ -0,0 +1,15 @@
1
+ from django.db import migrations, models
2
+
3
+
4
+ class Migration(migrations.Migration):
5
+ dependencies = [
6
+ ("netbox_dns", "0002_contact_description_registrar_description"),
7
+ ]
8
+
9
+ operations = [
10
+ migrations.AddField(
11
+ model_name="view",
12
+ name="default_view",
13
+ field=models.BooleanField(default=False),
14
+ ),
15
+ ]
@@ -0,0 +1,26 @@
1
+ from django.db import migrations
2
+
3
+
4
+ def create_and_assign_default_view(apps, schema_editor):
5
+ View = apps.get_model("netbox_dns", "View")
6
+ Zone = apps.get_model("netbox_dns", "Zone")
7
+
8
+ default_view = View.objects.create(
9
+ name="_default_",
10
+ description="Default View",
11
+ default_view=True,
12
+ )
13
+
14
+ for zone in Zone.objects.filter(view=None):
15
+ zone.view = default_view
16
+ zone.save()
17
+
18
+
19
+ class Migration(migrations.Migration):
20
+ dependencies = [
21
+ ("netbox_dns", "0003_default_view"),
22
+ ]
23
+
24
+ operations = [
25
+ migrations.RunPython(create_and_assign_default_view),
26
+ ]
@@ -0,0 +1,18 @@
1
+ import django.db.models.deletion
2
+ from django.db import migrations, models
3
+
4
+
5
+ class Migration(migrations.Migration):
6
+ dependencies = [
7
+ ("netbox_dns", "0004_create_and_assign_default_view"),
8
+ ]
9
+
10
+ operations = [
11
+ migrations.AlterField(
12
+ model_name="zone",
13
+ name="view",
14
+ field=models.ForeignKey(
15
+ on_delete=django.db.models.deletion.PROTECT, to="netbox_dns.view"
16
+ ),
17
+ ),
18
+ ]
@@ -55,7 +55,7 @@ class NameServer(NetBoxModel):
55
55
  def get_absolute_url(self):
56
56
  return reverse("plugins:netbox_dns:nameserver", kwargs={"pk": self.pk})
57
57
 
58
- def clean(self):
58
+ def clean(self, *args, **kwargs):
59
59
  try:
60
60
  self.name = normalize_name(self.name)
61
61
  except NameFormatError as exc:
@@ -74,6 +74,8 @@ class NameServer(NetBoxModel):
74
74
  }
75
75
  ) from None
76
76
 
77
+ super().clean(*args, **kwargs)
78
+
77
79
  def save(self, *args, **kwargs):
78
80
  self.full_clean()
79
81