netbox-plugin-dns 1.1.0b7__py3-none-any.whl → 1.1.2__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 (82) hide show
  1. netbox_dns/__init__.py +3 -2
  2. netbox_dns/api/nested_serializers.py +17 -16
  3. netbox_dns/api/serializers.py +1 -1
  4. netbox_dns/api/serializers_/record.py +1 -0
  5. netbox_dns/api/serializers_/{contact.py → registration_contact.py} +5 -5
  6. netbox_dns/api/serializers_/view.py +1 -0
  7. netbox_dns/api/serializers_/zone.py +5 -5
  8. netbox_dns/api/serializers_/zone_template.py +5 -5
  9. netbox_dns/api/urls.py +2 -2
  10. netbox_dns/api/views.py +7 -35
  11. netbox_dns/filtersets/__init__.py +1 -1
  12. netbox_dns/filtersets/nameserver.py +0 -0
  13. netbox_dns/filtersets/record.py +0 -0
  14. netbox_dns/filtersets/record_template.py +0 -0
  15. netbox_dns/filtersets/{contact.py → registration_contact.py} +4 -4
  16. netbox_dns/filtersets/zone.py +15 -15
  17. netbox_dns/filtersets/zone_template.py +15 -15
  18. netbox_dns/forms/__init__.py +1 -1
  19. netbox_dns/forms/nameserver.py +0 -0
  20. netbox_dns/forms/record.py +0 -0
  21. netbox_dns/forms/record_template.py +0 -0
  22. netbox_dns/forms/{contact.py → registration_contact.py} +16 -16
  23. netbox_dns/forms/view.py +29 -10
  24. netbox_dns/forms/zone.py +13 -13
  25. netbox_dns/forms/zone_template.py +13 -13
  26. netbox_dns/graphql/__init__.py +2 -2
  27. netbox_dns/graphql/filters.py +5 -5
  28. netbox_dns/graphql/schema.py +23 -53
  29. netbox_dns/graphql/types.py +39 -12
  30. netbox_dns/migrations/0007_alter_ordering_options.py +25 -0
  31. netbox_dns/migrations/{0007_view_prefixes.py → 0008_view_prefixes.py} +1 -1
  32. netbox_dns/migrations/0009_rename_contact_registrationcontact.py +36 -0
  33. netbox_dns/migrations/0010_view_ip_address_filter.py +18 -0
  34. netbox_dns/mixins/object_modification.py +30 -8
  35. netbox_dns/models/__init__.py +1 -1
  36. netbox_dns/models/nameserver.py +8 -3
  37. netbox_dns/models/record.py +47 -14
  38. netbox_dns/models/record_template.py +4 -1
  39. netbox_dns/models/registrar.py +7 -1
  40. netbox_dns/models/{contact.py → registration_contact.py} +15 -9
  41. netbox_dns/models/view.py +49 -2
  42. netbox_dns/models/zone.py +24 -18
  43. netbox_dns/models/zone_template.py +12 -9
  44. netbox_dns/navigation.py +7 -7
  45. netbox_dns/signals/ipam_dnssync.py +4 -4
  46. netbox_dns/tables/__init__.py +1 -1
  47. netbox_dns/tables/nameserver.py +1 -7
  48. netbox_dns/tables/record.py +10 -35
  49. netbox_dns/tables/record_template.py +0 -17
  50. netbox_dns/tables/registrar.py +0 -2
  51. netbox_dns/tables/{contact.py → registration_contact.py} +5 -6
  52. netbox_dns/tables/view.py +1 -8
  53. netbox_dns/tables/zone.py +0 -15
  54. netbox_dns/tables/zone_template.py +2 -16
  55. netbox_dns/templates/netbox_dns/{contact.html → registrationcontact.html} +1 -1
  56. netbox_dns/templates/netbox_dns/view.html +16 -0
  57. netbox_dns/urls/__init__.py +2 -2
  58. netbox_dns/urls/nameserver.py +14 -38
  59. netbox_dns/urls/record.py +7 -19
  60. netbox_dns/urls/record_template.py +18 -27
  61. netbox_dns/urls/registrar.py +11 -35
  62. netbox_dns/urls/registration_contact.py +60 -0
  63. netbox_dns/urls/view.py +8 -22
  64. netbox_dns/urls/zone.py +8 -46
  65. netbox_dns/urls/zone_template.py +16 -26
  66. netbox_dns/utilities/ipam_dnssync.py +58 -26
  67. netbox_dns/views/__init__.py +1 -1
  68. netbox_dns/views/nameserver.py +7 -3
  69. netbox_dns/views/record.py +12 -3
  70. netbox_dns/views/record_template.py +1 -1
  71. netbox_dns/views/registrar.py +0 -1
  72. netbox_dns/views/registration_contact.py +94 -0
  73. netbox_dns/views/view.py +6 -1
  74. netbox_dns/views/zone.py +7 -6
  75. netbox_dns/views/zone_template.py +2 -2
  76. {netbox_plugin_dns-1.1.0b7.dist-info → netbox_plugin_dns-1.1.2.dist-info}/METADATA +14 -14
  77. {netbox_plugin_dns-1.1.0b7.dist-info → netbox_plugin_dns-1.1.2.dist-info}/RECORD +80 -76
  78. {netbox_plugin_dns-1.1.0b7.dist-info → netbox_plugin_dns-1.1.2.dist-info}/WHEEL +2 -1
  79. netbox_plugin_dns-1.1.2.dist-info/top_level.txt +1 -0
  80. netbox_dns/urls/contact.py +0 -51
  81. netbox_dns/views/contact.py +0 -95
  82. {netbox_plugin_dns-1.1.0b7.dist-info → netbox_plugin_dns-1.1.2.dist-info}/LICENSE +0 -0
@@ -17,15 +17,37 @@ class ObjectModificationMixin:
17
17
 
18
18
  self.__class__.check_fields.add("custom_field_data")
19
19
 
20
+ self._save_field_values()
21
+
22
+ def _save_field_values(self):
23
+ for field in self.check_fields:
24
+ if f"{field}_id" in self.__dict__:
25
+ setattr(self, f"_saved_{field}_id", self.__dict__.get(f"{field}_id"))
26
+ else:
27
+ setattr(self, f"_saved_{field}", self.__dict__.get(field))
28
+
29
+ def save(self, *args, **kwargs):
30
+ super().save(*args, **kwargs)
31
+
32
+ self._save_field_values()
33
+
20
34
  @property
21
35
  def changed_fields(self):
22
- if self.pk is None:
36
+ if self._state.adding:
23
37
  return None
24
38
 
25
- saved = self.__class__.objects.get(pk=self.pk)
26
-
27
- return {
28
- field
29
- for field in self.check_fields
30
- if getattr(self, field) != getattr(saved, field)
31
- }
39
+ _changed_fields = set()
40
+ for field in self.check_fields:
41
+ if f"_saved_{field}_id" in self.__dict__:
42
+ if self.__dict__.get(f"_saved_{field}_id") != self.__dict__.get(
43
+ f"{field}_id"
44
+ ):
45
+ _changed_fields.add(field)
46
+ else:
47
+ if self.__dict__.get(f"_saved_{field}") != self.__dict__.get(field):
48
+ _changed_fields.add(field)
49
+
50
+ return _changed_fields
51
+
52
+ def get_saved_value(self, field):
53
+ return self.__dict__.get(f"_saved_{field}")
@@ -2,7 +2,7 @@ from .zone import *
2
2
  from .nameserver import *
3
3
  from .record import *
4
4
  from .view import *
5
- from .contact import *
5
+ from .registration_contact import *
6
6
  from .registrar import *
7
7
  from .zone_template import *
8
8
  from .record_template import *
@@ -7,6 +7,7 @@ from django.urls import reverse
7
7
 
8
8
  from netbox.models import NetBoxModel
9
9
  from netbox.search import SearchIndex, register_search
10
+ from netbox.models.features import ContactsMixin
10
11
 
11
12
  from netbox_dns.utilities import (
12
13
  name_to_unicode,
@@ -26,7 +27,7 @@ __all__ = (
26
27
  )
27
28
 
28
29
 
29
- class NameServer(ObjectModificationMixin, NetBoxModel):
30
+ class NameServer(ObjectModificationMixin, ContactsMixin, NetBoxModel):
30
31
  name = models.CharField(
31
32
  unique=True,
32
33
  max_length=255,
@@ -43,13 +44,17 @@ class NameServer(ObjectModificationMixin, NetBoxModel):
43
44
  null=True,
44
45
  )
45
46
 
46
- clone_fields = ["name", "description"]
47
+ clone_fields = (
48
+ "name",
49
+ "description",
50
+ )
47
51
 
48
52
  class Meta:
49
- ordering = ("name",)
50
53
  verbose_name = "Nameserver"
51
54
  verbose_name_plural = "Nameservers"
52
55
 
56
+ ordering = ("name",)
57
+
53
58
  def __str__(self):
54
59
  try:
55
60
  return dns_name.from_text(self.name, origin=None).to_unicode()
@@ -10,12 +10,14 @@ from django.urls import reverse
10
10
  from django.conf import settings
11
11
 
12
12
  from netbox.models import NetBoxModel
13
+ from ipam.models import IPAddress
14
+ from netbox.models.features import ContactsMixin
13
15
  from netbox.search import SearchIndex, register_search
14
16
  from netbox.plugins.utils import get_plugin_config
15
17
  from utilities.querysets import RestrictedQuerySet
16
18
 
17
19
  from netbox_dns.fields import AddressField
18
- from netbox_dns.utilities import arpa_to_prefix, name_to_unicode
20
+ from netbox_dns.utilities import arpa_to_prefix, name_to_unicode, get_query_from_filter
19
21
  from netbox_dns.validators import validate_generic_name, validate_record_value
20
22
  from netbox_dns.mixins import ObjectModificationMixin
21
23
  from netbox_dns.choices import RecordTypeChoices, RecordStatusChoices
@@ -40,6 +42,20 @@ def record_data_from_ip_address(ip_address, zone):
40
42
  cf_data = ip_address.custom_field_data
41
43
 
42
44
  if cf_data.get("ipaddress_dns_disabled"):
45
+ # +
46
+ # DNS record creation disabled for this address
47
+ # -
48
+ return None
49
+
50
+ if (
51
+ zone.view.ip_address_filter is not None
52
+ and not IPAddress.objects.filter(
53
+ Q(pk=ip_address.pk), get_query_from_filter(zone.view.ip_address_filter)
54
+ ).exists()
55
+ ):
56
+ # +
57
+ # IP address does not match the filter
58
+ # -
43
59
  return None
44
60
 
45
61
  data = {
@@ -100,7 +116,7 @@ class RecordManager(models.Manager.from_queryset(RestrictedQuerySet)):
100
116
  )
101
117
 
102
118
 
103
- class Record(ObjectModificationMixin, NetBoxModel):
119
+ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
104
120
  ACTIVE_STATUS_LIST = (RecordStatusChoices.STATUS_ACTIVE,)
105
121
 
106
122
  unique_ptr_qs = Q(
@@ -193,7 +209,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
193
209
  objects = RecordManager()
194
210
  raw_objects = RestrictedQuerySet.as_manager()
195
211
 
196
- clone_fields = [
212
+ clone_fields = (
197
213
  "zone",
198
214
  "type",
199
215
  "name",
@@ -202,10 +218,20 @@ class Record(ObjectModificationMixin, NetBoxModel):
202
218
  "ttl",
203
219
  "disable_ptr",
204
220
  "description",
205
- ]
221
+ )
206
222
 
207
223
  class Meta:
208
- ordering = ("zone", "name", "type", "value", "status")
224
+ verbose_name = "Record"
225
+ verbose_name_plural = "Records"
226
+
227
+ ordering = (
228
+ "fqdn",
229
+ "zone",
230
+ "name",
231
+ "type",
232
+ "value",
233
+ "status",
234
+ )
209
235
 
210
236
  def __str__(self):
211
237
  try:
@@ -462,22 +488,29 @@ class Record(ObjectModificationMixin, NetBoxModel):
462
488
  self.rfc2317_cname_record = None
463
489
 
464
490
  def update_from_ip_address(self, ip_address, zone=None):
491
+ """
492
+ Update an address record according to data from an IPAddress object.
493
+
494
+ Returns a tuple of two booleans: (update, delete).
495
+
496
+ update: The record was updated and needs to be cleaned and/or saved
497
+ delete: The record is no longer needed and needs to be deleted
498
+ """
465
499
  if zone is None:
466
500
  zone = self.zone
467
501
 
468
502
  data = record_data_from_ip_address(ip_address, zone)
469
503
 
470
504
  if data is None:
471
- self.delete()
472
- return
505
+ return False, True
473
506
 
474
507
  if all((getattr(self, attr) == data[attr] for attr in data.keys())):
475
- return
508
+ return False, False
476
509
 
477
510
  for attr, value in data.items():
478
511
  setattr(self, attr, value)
479
512
 
480
- return self
513
+ return True, False
481
514
 
482
515
  @classmethod
483
516
  def create_from_ip_address(cls, ip_address, zone):
@@ -574,7 +607,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
574
607
  status__in=Record.ACTIVE_STATUS_LIST,
575
608
  )
576
609
 
577
- if self.pk is not None:
610
+ if not self._state.adding:
578
611
  records = records.exclude(pk=self.pk)
579
612
 
580
613
  if records.exists():
@@ -613,7 +646,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
613
646
  record.save(update_fields=["status"])
614
647
 
615
648
  def check_unique_rrset_ttl(self):
616
- if self.pk is not None:
649
+ if not self._state.adding:
617
650
  return
618
651
 
619
652
  if not get_plugin_config("netbox_dns", "enforce_unique_rrset_ttl", False):
@@ -652,7 +685,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
652
685
  ) from None
653
686
 
654
687
  def update_rrset_ttl(self, ttl=None):
655
- if self.pk is None:
688
+ if self._state.adding:
656
689
  return
657
690
 
658
691
  if not get_plugin_config("netbox_dns", "enforce_unique_rrset_ttl", False):
@@ -688,7 +721,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
688
721
  self.validate_name(new_zone=new_zone)
689
722
  self.validate_value()
690
723
  self.check_unique_record(new_zone=new_zone)
691
- if self.pk is None:
724
+ if self._state.adding:
692
725
  self.check_unique_rrset_ttl()
693
726
 
694
727
  if not self.is_active:
@@ -776,7 +809,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
776
809
  ):
777
810
  self.full_clean()
778
811
 
779
- if self.pk is not None and update_rrset_ttl:
812
+ if not self._state.adding and update_rrset_ttl:
780
813
  self.update_rrset_ttl()
781
814
 
782
815
  if self.is_ptr_record:
@@ -85,7 +85,10 @@ class RecordTemplate(NetBoxModel):
85
85
  )
86
86
 
87
87
  class Meta:
88
- ordering = ["name"]
88
+ verbose_name = "Record Template"
89
+ verbose_name_plural = "Record Templates"
90
+
91
+ ordering = ("name",)
89
92
 
90
93
  def __str__(self):
91
94
  return str(self.name)
@@ -59,7 +59,13 @@ class Registrar(NetBoxModel):
59
59
  return str(self.name)
60
60
 
61
61
  class Meta:
62
- ordering = ("name", "iana_id")
62
+ verbose_name = "Registrar"
63
+ verbose_name_plural = "Registrars"
64
+
65
+ ordering = (
66
+ "name",
67
+ "iana_id",
68
+ )
63
69
 
64
70
 
65
71
  @register_search
@@ -8,12 +8,12 @@ from taggit.managers import TaggableManager
8
8
 
9
9
 
10
10
  __all__ = (
11
- "Contact",
12
- "ContactIndex",
11
+ "RegistrationContact",
12
+ "RegistrationContactIndex",
13
13
  )
14
14
 
15
15
 
16
- class Contact(NetBoxModel):
16
+ class RegistrationContact(NetBoxModel):
17
17
  # +
18
18
  # Data fields according to https://www.icann.org/resources/pages/rdds-labeling-policy-2017-02-01-en
19
19
  # -
@@ -87,7 +87,7 @@ class Contact(NetBoxModel):
87
87
  related_name="netbox_dns_contact_set",
88
88
  )
89
89
 
90
- clone_fields = [
90
+ clone_fields = (
91
91
  "name",
92
92
  "description",
93
93
  "organization",
@@ -102,10 +102,10 @@ class Contact(NetBoxModel):
102
102
  "fax_ext",
103
103
  "email",
104
104
  "tags",
105
- ]
105
+ )
106
106
 
107
107
  def get_absolute_url(self):
108
- return reverse("plugins:netbox_dns:contact", kwargs={"pk": self.pk})
108
+ return reverse("plugins:netbox_dns:registrationcontact", kwargs={"pk": self.pk})
109
109
 
110
110
  def __str__(self):
111
111
  if self.name is not None:
@@ -114,7 +114,13 @@ class Contact(NetBoxModel):
114
114
  return self.contact_id
115
115
 
116
116
  class Meta:
117
- ordering = ("name", "contact_id")
117
+ verbose_name = "Registration Contact"
118
+ verbose_name_plural = "Registration Contacts"
119
+
120
+ ordering = (
121
+ "name",
122
+ "contact_id",
123
+ )
118
124
 
119
125
  @property
120
126
  def zones(self):
@@ -127,8 +133,8 @@ class Contact(NetBoxModel):
127
133
 
128
134
 
129
135
  @register_search
130
- class ContactIndex(SearchIndex):
131
- model = Contact
136
+ class RegistrationContactIndex(SearchIndex):
137
+ model = RegistrationContact
132
138
  fields = (
133
139
  ("name", 100),
134
140
  ("contact_id", 100),
netbox_dns/models/view.py CHANGED
@@ -3,11 +3,19 @@ from django.urls import reverse
3
3
  from django.core.exceptions import ValidationError
4
4
 
5
5
  from netbox.models import NetBoxModel
6
+ from netbox.models.features import ContactsMixin
6
7
  from netbox.search import SearchIndex, register_search
7
8
  from netbox.context import current_request
8
9
  from utilities.exceptions import AbortRequest
9
10
 
10
11
  from netbox_dns.mixins import ObjectModificationMixin
12
+ from netbox_dns.utilities import (
13
+ get_ip_addresses_by_view,
14
+ check_dns_records,
15
+ update_dns_records,
16
+ delete_dns_records,
17
+ get_query_from_filter,
18
+ )
11
19
 
12
20
 
13
21
  __all__ = (
@@ -16,7 +24,7 @@ __all__ = (
16
24
  )
17
25
 
18
26
 
19
- class View(ObjectModificationMixin, NetBoxModel):
27
+ class View(ObjectModificationMixin, ContactsMixin, NetBoxModel):
20
28
  name = models.CharField(
21
29
  unique=True,
22
30
  max_length=255,
@@ -33,6 +41,11 @@ class View(ObjectModificationMixin, NetBoxModel):
33
41
  related_name="netbox_dns_views",
34
42
  blank=True,
35
43
  )
44
+ ip_address_filter = models.JSONField(
45
+ verbose_name="IP Address Filter",
46
+ blank=True,
47
+ null=True,
48
+ )
36
49
  tenant = models.ForeignKey(
37
50
  to="tenancy.Tenant",
38
51
  on_delete=models.PROTECT,
@@ -41,7 +54,10 @@ class View(ObjectModificationMixin, NetBoxModel):
41
54
  null=True,
42
55
  )
43
56
 
44
- clone_fields = ["name", "description"]
57
+ clone_fields = (
58
+ "name",
59
+ "description",
60
+ )
45
61
 
46
62
  @classmethod
47
63
  def get_default_view(cls):
@@ -54,6 +70,9 @@ class View(ObjectModificationMixin, NetBoxModel):
54
70
  return str(self.name)
55
71
 
56
72
  class Meta:
73
+ verbose_name = "View"
74
+ verbose_name_plural = "Views"
75
+
57
76
  ordering = ("name",)
58
77
 
59
78
  def delete(self, *args, **kwargs):
@@ -80,6 +99,21 @@ class View(ObjectModificationMixin, NetBoxModel):
80
99
  }
81
100
  )
82
101
 
102
+ if "ip_address_filter" in changed_fields and self.get_saved_value(
103
+ "ip_address_filter"
104
+ ):
105
+ try:
106
+ for ip_address in get_ip_addresses_by_view(self).filter(
107
+ get_query_from_filter(self.ip_address_filter)
108
+ ):
109
+ check_dns_records(ip_address, view=self)
110
+ except ValidationError as exc:
111
+ raise ValidationError(
112
+ {
113
+ "ip_address_filter": exc.messages,
114
+ }
115
+ )
116
+
83
117
  super().clean(*args, **kwargs)
84
118
 
85
119
  def save(self, *args, **kwargs):
@@ -99,6 +133,19 @@ class View(ObjectModificationMixin, NetBoxModel):
99
133
  view.default_view = False
100
134
  view.save()
101
135
 
136
+ if changed_fields is not None and "ip_address_filter" in changed_fields:
137
+ ip_addresses = get_ip_addresses_by_view(self)
138
+
139
+ for ip_address in ip_addresses.exclude(
140
+ get_query_from_filter(self.ip_address_filter)
141
+ ):
142
+ delete_dns_records(ip_address, view=self)
143
+
144
+ for ip_address in ip_addresses.filter(
145
+ get_query_from_filter(self.ip_address_filter)
146
+ ):
147
+ update_dns_records(ip_address, view=self)
148
+
102
149
 
103
150
  @register_search
104
151
  class ViewIndex(SearchIndex):
netbox_dns/models/zone.py CHANGED
@@ -5,8 +5,6 @@ from datetime import datetime
5
5
  from dns import name as dns_name
6
6
  from dns.exception import DNSException
7
7
  from dns.rdtypes.ANY import SOA
8
- from dns.exception import DNSException
9
-
10
8
  from django.core.validators import (
11
9
  MinValueValidator,
12
10
  MaxValueValidator,
@@ -20,6 +18,7 @@ from django.dispatch import receiver
20
18
  from django.conf import settings
21
19
 
22
20
  from netbox.models import NetBoxModel
21
+ from netbox.models.features import ContactsMixin
23
22
  from netbox.search import SearchIndex, register_search
24
23
  from netbox.plugins.utils import get_plugin_config
25
24
  from utilities.querysets import RestrictedQuerySet
@@ -37,7 +36,6 @@ from netbox_dns.utilities import (
37
36
  NameFormatError,
38
37
  )
39
38
  from netbox_dns.validators import (
40
- validate_fqdn,
41
39
  validate_rname,
42
40
  validate_domain_name,
43
41
  )
@@ -71,7 +69,7 @@ class ZoneManager(models.Manager.from_queryset(RestrictedQuerySet)):
71
69
  )
72
70
 
73
71
 
74
- class Zone(ObjectModificationMixin, NetBoxModel):
72
+ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
75
73
  ACTIVE_STATUS_LIST = (ZoneStatusChoices.STATUS_ACTIVE,)
76
74
 
77
75
  def __init__(self, *args, **kwargs):
@@ -194,7 +192,7 @@ class Zone(ObjectModificationMixin, NetBoxModel):
194
192
  null=True,
195
193
  )
196
194
  registrant = models.ForeignKey(
197
- to="Contact",
195
+ to="RegistrationContact",
198
196
  on_delete=models.SET_NULL,
199
197
  verbose_name="Registrant",
200
198
  help_text="The owner of the domain",
@@ -202,7 +200,7 @@ class Zone(ObjectModificationMixin, NetBoxModel):
202
200
  null=True,
203
201
  )
204
202
  admin_c = models.ForeignKey(
205
- to="Contact",
203
+ to="RegistrationContact",
206
204
  on_delete=models.SET_NULL,
207
205
  verbose_name="Admin Contact",
208
206
  related_name="admin_c_zones",
@@ -211,16 +209,16 @@ class Zone(ObjectModificationMixin, NetBoxModel):
211
209
  null=True,
212
210
  )
213
211
  tech_c = models.ForeignKey(
214
- to="Contact",
212
+ to="RegistrationContact",
215
213
  on_delete=models.SET_NULL,
216
- verbose_name="Tech Contact",
214
+ verbose_name="Technical Contact",
217
215
  related_name="tech_c_zones",
218
216
  help_text="The technical contact for the domain",
219
217
  blank=True,
220
218
  null=True,
221
219
  )
222
220
  billing_c = models.ForeignKey(
223
- to="Contact",
221
+ to="RegistrationContact",
224
222
  on_delete=models.SET_NULL,
225
223
  verbose_name="Billing Contact",
226
224
  related_name="billing_c_zones",
@@ -251,7 +249,7 @@ class Zone(ObjectModificationMixin, NetBoxModel):
251
249
 
252
250
  objects = ZoneManager()
253
251
 
254
- clone_fields = [
252
+ clone_fields = (
255
253
  "view",
256
254
  "name",
257
255
  "status",
@@ -265,9 +263,12 @@ class Zone(ObjectModificationMixin, NetBoxModel):
265
263
  "soa_expire",
266
264
  "soa_minimum",
267
265
  "description",
268
- ]
266
+ )
269
267
 
270
268
  class Meta:
269
+ verbose_name = "Zone"
270
+ verbose_name_plural = "Zones"
271
+
271
272
  ordering = (
272
273
  "view",
273
274
  "name",
@@ -648,14 +649,16 @@ class Zone(ObjectModificationMixin, NetBoxModel):
648
649
  }
649
650
  )
650
651
 
651
- if self.pk is not None:
652
- old_zone = Zone.objects.get(pk=self.pk)
652
+ if not self._state.adding:
653
+ old_soa_serial = self.get_saved_value("soa_serial")
654
+ old_soa_serial_auto = self.get_saved_value("soa_serial_auto")
655
+
653
656
  if not self.soa_serial_auto:
654
- self.check_soa_serial_increment(old_zone.soa_serial, self.soa_serial)
655
- else:
657
+ self.check_soa_serial_increment(old_soa_serial, self.soa_serial)
658
+ elif not old_soa_serial_auto:
656
659
  try:
657
660
  self.check_soa_serial_increment(
658
- old_zone.soa_serial, self.get_auto_serial()
661
+ old_soa_serial, self.get_auto_serial()
659
662
  )
660
663
  except ValidationError:
661
664
  raise ValidationError(
@@ -664,10 +667,13 @@ class Zone(ObjectModificationMixin, NetBoxModel):
664
667
  }
665
668
  )
666
669
 
670
+ old_name = self.get_saved_value("name")
671
+ old_view_id = self.get_saved_value("view_id")
672
+
667
673
  if (
668
674
  not self.ip_addresses_checked
669
- and old_zone.name != self.name
670
- or old_zone.view != self.view
675
+ and old_name != self.name
676
+ or old_view_id != self.view_id
671
677
  ):
672
678
  ip_addresses = IPAddress.objects.filter(
673
679
  netbox_dns_records__in=self.record_set.filter(
@@ -47,7 +47,7 @@ class ZoneTemplate(NetBoxModel):
47
47
  null=True,
48
48
  )
49
49
  registrant = models.ForeignKey(
50
- to="Contact",
50
+ to="RegistrationContact",
51
51
  on_delete=models.SET_NULL,
52
52
  related_name="+",
53
53
  help_text="The owner of the domain",
@@ -55,7 +55,7 @@ class ZoneTemplate(NetBoxModel):
55
55
  null=True,
56
56
  )
57
57
  admin_c = models.ForeignKey(
58
- to="Contact",
58
+ to="RegistrationContact",
59
59
  on_delete=models.SET_NULL,
60
60
  verbose_name="Admin contact",
61
61
  related_name="+",
@@ -64,7 +64,7 @@ class ZoneTemplate(NetBoxModel):
64
64
  null=True,
65
65
  )
66
66
  tech_c = models.ForeignKey(
67
- to="Contact",
67
+ to="RegistrationContact",
68
68
  on_delete=models.SET_NULL,
69
69
  verbose_name="Tech contact",
70
70
  related_name="+",
@@ -73,7 +73,7 @@ class ZoneTemplate(NetBoxModel):
73
73
  null=True,
74
74
  )
75
75
  billing_c = models.ForeignKey(
76
- to="Contact",
76
+ to="RegistrationContact",
77
77
  on_delete=models.SET_NULL,
78
78
  verbose_name="Billing contact",
79
79
  related_name="+",
@@ -82,7 +82,7 @@ class ZoneTemplate(NetBoxModel):
82
82
  null=True,
83
83
  )
84
84
 
85
- clone_fields = [
85
+ clone_fields = (
86
86
  "description",
87
87
  "nameservers",
88
88
  "record_templates",
@@ -92,19 +92,22 @@ class ZoneTemplate(NetBoxModel):
92
92
  "admin_c",
93
93
  "tech_c",
94
94
  "billing_c",
95
- ]
95
+ )
96
96
 
97
- template_fields = [
97
+ template_fields = (
98
98
  "tenant",
99
99
  "registrar",
100
100
  "registrant",
101
101
  "admin_c",
102
102
  "tech_c",
103
103
  "billing_c",
104
- ]
104
+ )
105
105
 
106
106
  class Meta:
107
- ordering = ["name"]
107
+ verbose_name = "Zone Template"
108
+ verbose_name_plural = "Zone Templates"
109
+
110
+ ordering = ("name",)
108
111
 
109
112
  def __str__(self):
110
113
  return str(self.name)
netbox_dns/navigation.py CHANGED
@@ -151,21 +151,21 @@ registrar_menu_item = PluginMenuItem(
151
151
  )
152
152
 
153
153
  contact_menu_item = PluginMenuItem(
154
- link="plugins:netbox_dns:contact_list",
155
- link_text="Contacts",
156
- permissions=["netbox_dns.view_contact"],
154
+ link="plugins:netbox_dns:registrationcontact_list",
155
+ link_text="Registration Contacts",
156
+ permissions=["netbox_dns.view_registrationcontact"],
157
157
  buttons=(
158
158
  PluginMenuButton(
159
- "plugins:netbox_dns:contact_add",
159
+ "plugins:netbox_dns:registrationcontact_add",
160
160
  "Add",
161
161
  "mdi mdi-plus-thick",
162
- permissions=["netbox_dns.add_contact"],
162
+ permissions=["netbox_dns.add_registrationcontact"],
163
163
  ),
164
164
  PluginMenuButton(
165
- "plugins:netbox_dns:contact_import",
165
+ "plugins:netbox_dns:registrationcontact_import",
166
166
  "Import",
167
167
  "mdi mdi-upload",
168
- permissions=["netbox_dns.add_contact"],
168
+ permissions=["netbox_dns.add_registrationcontact"],
169
169
  ),
170
170
  ),
171
171
  )