netbox-plugin-dns 1.1.1__py3-none-any.whl → 1.1.3__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 (88) hide show
  1. netbox_dns/__init__.py +8 -6
  2. netbox_dns/api/nested_serializers.py +3 -2
  3. netbox_dns/api/serializers_/nameserver.py +2 -1
  4. netbox_dns/api/serializers_/record.py +5 -4
  5. netbox_dns/api/serializers_/record_template.py +2 -1
  6. netbox_dns/api/serializers_/view.py +3 -1
  7. netbox_dns/api/serializers_/zone.py +12 -11
  8. netbox_dns/api/serializers_/zone_template.py +8 -7
  9. netbox_dns/api/views.py +9 -4
  10. netbox_dns/choices/record.py +4 -2
  11. netbox_dns/choices/zone.py +6 -4
  12. netbox_dns/fields/address.py +2 -1
  13. netbox_dns/fields/network.py +2 -1
  14. netbox_dns/fields/rfc2317.py +7 -3
  15. netbox_dns/filtersets/nameserver.py +3 -2
  16. netbox_dns/filtersets/record.py +10 -9
  17. netbox_dns/filtersets/record_template.py +3 -2
  18. netbox_dns/filtersets/view.py +3 -2
  19. netbox_dns/filtersets/zone.py +24 -22
  20. netbox_dns/filtersets/zone_template.py +15 -14
  21. netbox_dns/forms/nameserver.py +41 -17
  22. netbox_dns/forms/record.py +43 -26
  23. netbox_dns/forms/record_template.py +49 -28
  24. netbox_dns/forms/registrar.py +21 -17
  25. netbox_dns/forms/registration_contact.py +37 -25
  26. netbox_dns/forms/view.py +75 -34
  27. netbox_dns/forms/zone.py +167 -120
  28. netbox_dns/forms/zone_template.py +53 -43
  29. netbox_dns/graphql/schema.py +0 -10
  30. netbox_dns/graphql/types.py +1 -0
  31. netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
  32. netbox_dns/locale/en/LC_MESSAGES/django.mo +0 -0
  33. netbox_dns/management/commands/rebuild_dnssync.py +14 -1
  34. netbox_dns/migrations/0010_view_ip_address_filter.py +18 -0
  35. netbox_dns/mixins/object_modification.py +30 -8
  36. netbox_dns/models/nameserver.py +6 -2
  37. netbox_dns/models/record.py +95 -40
  38. netbox_dns/models/record_template.py +16 -8
  39. netbox_dns/models/registrar.py +11 -7
  40. netbox_dns/models/registration_contact.py +23 -11
  41. netbox_dns/models/view.py +54 -5
  42. netbox_dns/models/zone.py +77 -50
  43. netbox_dns/models/zone_template.py +12 -10
  44. netbox_dns/navigation.py +30 -28
  45. netbox_dns/signals/ipam_dnssync.py +25 -18
  46. netbox_dns/tables/ipam_dnssync.py +2 -1
  47. netbox_dns/tables/nameserver.py +2 -0
  48. netbox_dns/tables/record.py +21 -11
  49. netbox_dns/tables/record_template.py +12 -5
  50. netbox_dns/tables/registrar.py +2 -0
  51. netbox_dns/tables/registration_contact.py +2 -0
  52. netbox_dns/tables/view.py +4 -2
  53. netbox_dns/tables/zone.py +15 -2
  54. netbox_dns/tables/zone_template.py +7 -0
  55. netbox_dns/templates/netbox_dns/nameserver.html +6 -5
  56. netbox_dns/templates/netbox_dns/record/managed.html +2 -1
  57. netbox_dns/templates/netbox_dns/record/related.html +26 -14
  58. netbox_dns/templates/netbox_dns/record.html +39 -20
  59. netbox_dns/templates/netbox_dns/recordtemplate.html +27 -15
  60. netbox_dns/templates/netbox_dns/registrar.html +11 -10
  61. netbox_dns/templates/netbox_dns/registrationcontact.html +16 -15
  62. netbox_dns/templates/netbox_dns/view/button.html +2 -1
  63. netbox_dns/templates/netbox_dns/view/prefix.html +7 -4
  64. netbox_dns/templates/netbox_dns/view/related.html +26 -10
  65. netbox_dns/templates/netbox_dns/view.html +22 -9
  66. netbox_dns/templates/netbox_dns/zone/base.html +2 -1
  67. netbox_dns/templates/netbox_dns/zone/child.html +3 -2
  68. netbox_dns/templates/netbox_dns/zone/record.html +3 -2
  69. netbox_dns/templates/netbox_dns/zone/registration.html +8 -7
  70. netbox_dns/templates/netbox_dns/zone.html +28 -30
  71. netbox_dns/templates/netbox_dns/zonetemplate.html +27 -17
  72. netbox_dns/utilities/ipam_dnssync.py +71 -28
  73. netbox_dns/validators/dns_name.py +11 -4
  74. netbox_dns/validators/dns_value.py +9 -4
  75. netbox_dns/validators/rfc2317.py +6 -3
  76. netbox_dns/views/nameserver.py +4 -2
  77. netbox_dns/views/record_template.py +4 -3
  78. netbox_dns/views/registrar.py +3 -1
  79. netbox_dns/views/registration_contact.py +2 -1
  80. netbox_dns/views/view.py +2 -1
  81. netbox_dns/views/zone.py +6 -4
  82. netbox_dns/views/zone_template.py +8 -7
  83. {netbox_plugin_dns-1.1.1.dist-info → netbox_plugin_dns-1.1.3.dist-info}/METADATA +1 -1
  84. netbox_plugin_dns-1.1.3.dist-info/RECORD +150 -0
  85. {netbox_plugin_dns-1.1.1.dist-info → netbox_plugin_dns-1.1.3.dist-info}/WHEEL +1 -1
  86. netbox_plugin_dns-1.1.1.dist-info/RECORD +0 -147
  87. {netbox_plugin_dns-1.1.1.dist-info → netbox_plugin_dns-1.1.3.dist-info}/LICENSE +0 -0
  88. {netbox_plugin_dns-1.1.1.dist-info → netbox_plugin_dns-1.1.3.dist-info}/top_level.txt +0 -0
@@ -8,15 +8,17 @@ from django.db import transaction, models
8
8
  from django.db.models import Q, ExpressionWrapper, BooleanField, Min
9
9
  from django.urls import reverse
10
10
  from django.conf import settings
11
+ from django.utils.translation import gettext_lazy as _
11
12
 
12
13
  from netbox.models import NetBoxModel
14
+ from ipam.models import IPAddress
13
15
  from netbox.models.features import ContactsMixin
14
16
  from netbox.search import SearchIndex, register_search
15
17
  from netbox.plugins.utils import get_plugin_config
16
18
  from utilities.querysets import RestrictedQuerySet
17
19
 
18
20
  from netbox_dns.fields import AddressField
19
- from netbox_dns.utilities import arpa_to_prefix, name_to_unicode
21
+ from netbox_dns.utilities import arpa_to_prefix, name_to_unicode, get_query_from_filter
20
22
  from netbox_dns.validators import validate_generic_name, validate_record_value
21
23
  from netbox_dns.mixins import ObjectModificationMixin
22
24
  from netbox_dns.choices import RecordTypeChoices, RecordStatusChoices
@@ -41,6 +43,20 @@ def record_data_from_ip_address(ip_address, zone):
41
43
  cf_data = ip_address.custom_field_data
42
44
 
43
45
  if cf_data.get("ipaddress_dns_disabled"):
46
+ # +
47
+ # DNS record creation disabled for this address
48
+ # -
49
+ return None
50
+
51
+ if (
52
+ zone.view.ip_address_filter is not None
53
+ and not IPAddress.objects.filter(
54
+ Q(pk=ip_address.pk), get_query_from_filter(zone.view.ip_address_filter)
55
+ ).exists()
56
+ ):
57
+ # +
58
+ # IP address does not match the filter
59
+ # -
44
60
  return None
45
61
 
46
62
  data = {
@@ -110,58 +126,67 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
110
126
  )
111
127
 
112
128
  name = models.CharField(
129
+ verbose_name=_("Name"),
113
130
  max_length=255,
114
131
  )
115
132
  zone = models.ForeignKey(
116
- "Zone",
133
+ verbose_name=_("Zone"),
134
+ to="Zone",
117
135
  on_delete=models.CASCADE,
118
136
  )
119
137
  fqdn = models.CharField(
138
+ verbose_name=_("FQDN"),
120
139
  max_length=255,
121
140
  null=True,
122
141
  blank=True,
123
142
  default=None,
124
143
  )
125
144
  type = models.CharField(
145
+ verbose_name=_("Type"),
126
146
  choices=RecordTypeChoices,
127
147
  max_length=10,
128
148
  )
129
149
  value = models.CharField(
150
+ verbose_name=_("Value"),
130
151
  max_length=65535,
131
152
  )
132
153
  status = models.CharField(
154
+ verbose_name=_("Status"),
133
155
  max_length=50,
134
156
  choices=RecordStatusChoices,
135
157
  default=RecordStatusChoices.STATUS_ACTIVE,
136
158
  blank=False,
137
159
  )
138
160
  ttl = models.PositiveIntegerField(
139
- verbose_name="TTL",
161
+ verbose_name=_("TTL"),
140
162
  null=True,
141
163
  blank=True,
142
164
  )
143
165
  managed = models.BooleanField(
166
+ verbose_name=_("Managed"),
144
167
  null=False,
145
168
  default=False,
146
169
  )
147
170
  ptr_record = models.OneToOneField(
148
- "self",
171
+ verbose_name="PTR Record",
172
+ to="self",
149
173
  on_delete=models.SET_NULL,
150
174
  related_name="address_record",
151
- verbose_name="PTR record",
152
175
  null=True,
153
176
  blank=True,
154
177
  )
155
178
  disable_ptr = models.BooleanField(
156
- verbose_name="Disable PTR",
157
- help_text="Disable PTR record creation",
179
+ verbose_name=_("Disable PTR"),
180
+ help_text=_("Disable PTR record creation"),
158
181
  default=False,
159
182
  )
160
183
  description = models.CharField(
184
+ verbose_name=_("Description"),
161
185
  max_length=200,
162
186
  blank=True,
163
187
  )
164
188
  tenant = models.ForeignKey(
189
+ verbose_name=_("Tenant"),
165
190
  to="tenancy.Tenant",
166
191
  on_delete=models.PROTECT,
167
192
  related_name="netbox_dns_records",
@@ -169,13 +194,13 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
169
194
  null=True,
170
195
  )
171
196
  ip_address = AddressField(
172
- verbose_name="Related IP Address",
173
- help_text="IP address related to an address (A/AAAA) or PTR record",
197
+ verbose_name=_("Related IP Address"),
198
+ help_text=_("IP address related to an address (A/AAAA) or PTR record"),
174
199
  blank=True,
175
200
  null=True,
176
201
  )
177
202
  ipam_ip_address = models.ForeignKey(
178
- verbose_name="IPAM IP Address",
203
+ verbose_name=_("IPAM IP Address"),
179
204
  to="ipam.IPAddress",
180
205
  on_delete=models.CASCADE,
181
206
  related_name="netbox_dns_records",
@@ -183,10 +208,10 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
183
208
  null=True,
184
209
  )
185
210
  rfc2317_cname_record = models.ForeignKey(
186
- "self",
211
+ verbose_name=_("RFC2317 CNAME Record"),
212
+ to="self",
187
213
  on_delete=models.SET_NULL,
188
214
  related_name="rfc2317_ptr_records",
189
- verbose_name="RFC2317 CNAME record",
190
215
  null=True,
191
216
  blank=True,
192
217
  )
@@ -206,8 +231,8 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
206
231
  )
207
232
 
208
233
  class Meta:
209
- verbose_name = "Record"
210
- verbose_name_plural = "Records"
234
+ verbose_name = _("Record")
235
+ verbose_name_plural = _("Records")
211
236
 
212
237
  ordering = (
213
238
  "fqdn",
@@ -473,22 +498,29 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
473
498
  self.rfc2317_cname_record = None
474
499
 
475
500
  def update_from_ip_address(self, ip_address, zone=None):
501
+ """
502
+ Update an address record according to data from an IPAddress object.
503
+
504
+ Returns a tuple of two booleans: (update, delete).
505
+
506
+ update: The record was updated and needs to be cleaned and/or saved
507
+ delete: The record is no longer needed and needs to be deleted
508
+ """
476
509
  if zone is None:
477
510
  zone = self.zone
478
511
 
479
512
  data = record_data_from_ip_address(ip_address, zone)
480
513
 
481
514
  if data is None:
482
- self.delete()
483
- return
515
+ return False, True
484
516
 
485
517
  if all((getattr(self, attr) == data[attr] for attr in data.keys())):
486
- return
518
+ return False, False
487
519
 
488
520
  for attr, value in data.items():
489
521
  setattr(self, attr, value)
490
522
 
491
- return self
523
+ return True, False
492
524
 
493
525
  @classmethod
494
526
  def create_from_ip_address(cls, ip_address, zone):
@@ -515,7 +547,9 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
515
547
  if not fqdn.is_subdomain(_zone):
516
548
  raise ValidationError(
517
549
  {
518
- "name": f"{self.name} is not a name in {zone.name}",
550
+ "name": _("{name} is not a name in {zone}").format(
551
+ name=self.name, zone=zone.name
552
+ ),
519
553
  }
520
554
  )
521
555
 
@@ -559,13 +593,13 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
559
593
  {
560
594
  "name": exc,
561
595
  }
562
- ) from None
596
+ )
563
597
 
564
598
  def validate_value(self):
565
599
  try:
566
600
  validate_record_value(self.type, self.value)
567
601
  except ValidationError as exc:
568
- raise ValidationError({"value": exc}) from None
602
+ raise ValidationError({"value": exc})
569
603
 
570
604
  def check_unique_record(self, new_zone=None):
571
605
  if not get_plugin_config("netbox_dns", "enforce_unique_records", False):
@@ -585,7 +619,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
585
619
  status__in=Record.ACTIVE_STATUS_LIST,
586
620
  )
587
621
 
588
- if self.pk is not None:
622
+ if not self._state.adding:
589
623
  records = records.exclude(pk=self.pk)
590
624
 
591
625
  if records.exists():
@@ -599,9 +633,13 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
599
633
 
600
634
  raise ValidationError(
601
635
  {
602
- "value": f"There is already an active {self.type} record for name {self.name} in zone {self.zone} with value {self.value}."
636
+ "value": _(
637
+ "There is already an active {type} record for name {name} in zone {zone} with value {value}."
638
+ ).format(
639
+ type=self.type, name=self.name, zone=self.zone, value=self.value
640
+ )
603
641
  }
604
- ) from None
642
+ )
605
643
 
606
644
  def handle_conflicting_address_records(self):
607
645
  if self.ipam_ip_address is None or not self.is_active:
@@ -624,7 +662,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
624
662
  record.save(update_fields=["status"])
625
663
 
626
664
  def check_unique_rrset_ttl(self):
627
- if self.pk is not None:
665
+ if not self._state.adding:
628
666
  return
629
667
 
630
668
  if not get_plugin_config("netbox_dns", "enforce_unique_rrset_ttl", False):
@@ -658,12 +696,19 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
658
696
  conflicting_ttls = ", ".join({str(record.ttl) for record in records})
659
697
  raise ValidationError(
660
698
  {
661
- "ttl": f"There is at least one active {self.type} record for name {self.name} in zone {self.zone} and TTL is different ({conflicting_ttls})."
699
+ "ttl": _(
700
+ "There is at least one active {type} record for name {name} in zone {zone} and TTL is different ({ttls})."
701
+ ).format(
702
+ type=self.type,
703
+ name=self.name,
704
+ zone=self.zone,
705
+ ttls=conflicting_ttls,
706
+ )
662
707
  }
663
- ) from None
708
+ )
664
709
 
665
710
  def update_rrset_ttl(self, ttl=None):
666
- if self.pk is None:
711
+ if self._state.adding:
667
712
  return
668
713
 
669
714
  if not get_plugin_config("netbox_dns", "enforce_unique_rrset_ttl", False):
@@ -699,7 +744,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
699
744
  self.validate_name(new_zone=new_zone)
700
745
  self.validate_value()
701
746
  self.check_unique_record(new_zone=new_zone)
702
- if self.pk is None:
747
+ if self._state.adding:
703
748
  self.check_unique_rrset_ttl()
704
749
 
705
750
  if not self.is_active:
@@ -738,24 +783,30 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
738
783
  ):
739
784
  raise ValidationError(
740
785
  {
741
- "value": f"There is already an active record for name {ptr_cname_name} in zone {ptr_cname_zone}, RFC2317 CNAME is not allowed."
786
+ "value": _(
787
+ "There is already an active record for name {name} in zone {zone}, RFC2317 CNAME is not allowed."
788
+ ).format(name=ptr_cname_name, zone=ptr_cname_zone)
742
789
  }
743
- ) from None
790
+ )
744
791
 
745
792
  if self.type == RecordTypeChoices.SOA and self.name != "@":
746
793
  raise ValidationError(
747
794
  {
748
- "name": "SOA records are only allowed with name @ and are created automatically by NetBox DNS"
795
+ "name": _(
796
+ "SOA records are only allowed with name @ and are created automatically by NetBox DNS"
797
+ )
749
798
  }
750
- ) from None
799
+ )
751
800
 
752
801
  if self.type == RecordTypeChoices.CNAME:
753
802
  if records.exclude(type=RecordTypeChoices.NSEC).exists():
754
803
  raise ValidationError(
755
804
  {
756
- "type": f"There is already an active record for name {self.name} in zone {self.zone}, CNAME is not allowed."
805
+ "type": _(
806
+ "There is already an active record for name {name} in zone {zone}, CNAME is not allowed."
807
+ ).format(name=self.name, zone=self.zone)
757
808
  }
758
- ) from None
809
+ )
759
810
 
760
811
  elif (
761
812
  records.filter(type=RecordTypeChoices.CNAME).exists()
@@ -763,17 +814,21 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
763
814
  ):
764
815
  raise ValidationError(
765
816
  {
766
- "type": f"There is already an active CNAME record for name {self.name} in zone {self.zone}, no other record allowed."
817
+ "type": _(
818
+ "There is already an active CNAME record for name {name} in zone {zone}, no other record allowed."
819
+ ).format(name=self.name, zone=self.zone)
767
820
  }
768
- ) from None
821
+ )
769
822
 
770
823
  elif self.type in RecordTypeChoices.SINGLETONS:
771
824
  if records.filter(type=self.type).exists():
772
825
  raise ValidationError(
773
826
  {
774
- "type": f"There is already an active {self.type} record for name {self.name} in zone {self.zone}, more than one are not allowed."
827
+ "type": _(
828
+ "There is already an active {type} record for name {name} in zone {zone}, more than one are not allowed."
829
+ ).format(type=self.type, name=self.name, zone=self.zone)
775
830
  }
776
- ) from None
831
+ )
777
832
 
778
833
  super().clean(*args, **kwargs)
779
834
 
@@ -787,7 +842,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
787
842
  ):
788
843
  self.full_clean()
789
844
 
790
- if self.pk is not None and update_rrset_ttl:
845
+ if not self._state.adding and update_rrset_ttl:
791
846
  self.update_rrset_ttl()
792
847
 
793
848
  if self.is_ptr_record:
@@ -4,6 +4,7 @@ from dns import name as dns_name
4
4
  from django.core.exceptions import ValidationError
5
5
  from django.db import models
6
6
  from django.urls import reverse
7
+ from django.utils.translation import gettext_lazy as _
7
8
 
8
9
  from netbox.models import NetBoxModel
9
10
  from netbox.search import SearchIndex, register_search
@@ -23,40 +24,45 @@ __all__ = (
23
24
 
24
25
  class RecordTemplate(NetBoxModel):
25
26
  name = models.CharField(
26
- verbose_name="Template name",
27
+ verbose_name=_("Template Name"),
27
28
  unique=True,
28
29
  max_length=200,
29
30
  )
30
31
  record_name = models.CharField(
31
- verbose_name="Name",
32
+ verbose_name=_("Name"),
32
33
  max_length=255,
33
34
  )
34
35
  description = models.CharField(
36
+ verbose_name=_("Description"),
35
37
  max_length=200,
36
38
  blank=True,
37
39
  )
38
40
  type = models.CharField(
41
+ verbose_name=_("Type"),
39
42
  choices=RecordTypeChoices,
40
43
  )
41
44
  value = models.CharField(
45
+ verbose_name=_("Value"),
42
46
  max_length=65535,
43
47
  )
44
48
  status = models.CharField(
49
+ verbose_name=_("Status"),
45
50
  choices=RecordStatusChoices,
46
51
  default=RecordStatusChoices.STATUS_ACTIVE,
47
52
  blank=False,
48
53
  )
49
54
  ttl = models.PositiveIntegerField(
50
- verbose_name="TTL",
55
+ verbose_name=_("TTL"),
51
56
  null=True,
52
57
  blank=True,
53
58
  )
54
59
  disable_ptr = models.BooleanField(
55
- verbose_name="Disable PTR",
56
- help_text="Disable PTR record creation",
60
+ verbose_name=_("Disable PTR"),
61
+ help_text=_("Disable PTR record creation"),
57
62
  default=False,
58
63
  )
59
64
  tenant = models.ForeignKey(
65
+ verbose_name=_("Tenant"),
60
66
  to="tenancy.Tenant",
61
67
  on_delete=models.PROTECT,
62
68
  related_name="+",
@@ -85,8 +91,8 @@ class RecordTemplate(NetBoxModel):
85
91
  )
86
92
 
87
93
  class Meta:
88
- verbose_name = "Record Template"
89
- verbose_name_plural = "Record Templates"
94
+ verbose_name = _("Record Template")
95
+ verbose_name_plural = _("Record Templates")
90
96
 
91
97
  ordering = ("name",)
92
98
 
@@ -155,7 +161,9 @@ class RecordTemplate(NetBoxModel):
155
161
  record = Record.objects.create(**record_data)
156
162
  except ValidationError as exc:
157
163
  raise ValidationError(
158
- f"Error while processing record template {self}: {exc.messages[0]}"
164
+ _("Error while processing record template {template}: {error}").format(
165
+ template=self, error=exc.messages[0]
166
+ )
159
167
  )
160
168
 
161
169
  if tags := self.tags.all():
@@ -1,5 +1,6 @@
1
1
  from django.db import models
2
2
  from django.urls import reverse
3
+ from django.utils.translation import gettext_lazy as _
3
4
 
4
5
  from netbox.models import NetBoxModel
5
6
  from netbox.search import SearchIndex, register_search
@@ -16,38 +17,41 @@ class Registrar(NetBoxModel):
16
17
  # Data fields according to https://www.icann.org/resources/pages/rdds-labeling-policy-2017-02-01-en
17
18
  # -
18
19
  name = models.CharField(
20
+ verbose_name=_("Name"),
19
21
  unique=True,
20
22
  max_length=255,
21
23
  )
22
24
  description = models.CharField(
25
+ verbose_name=_("Description"),
23
26
  blank=True,
24
27
  max_length=200,
25
28
  )
26
29
  iana_id = models.IntegerField(
27
- verbose_name="IANA ID",
30
+ verbose_name=_("IANA ID"),
28
31
  null=True,
29
32
  blank=True,
30
33
  )
31
34
  referral_url = models.URLField(
32
- verbose_name="Referral URL",
35
+ verbose_name=_("Referral URL"),
33
36
  max_length=255,
34
37
  blank=True,
35
38
  )
36
39
  whois_server = models.CharField(
37
- verbose_name="WHOIS Server",
40
+ verbose_name=_("WHOIS Server"),
38
41
  max_length=255,
39
42
  blank=True,
40
43
  )
41
44
  address = models.CharField(
45
+ verbose_name=_("Address"),
42
46
  max_length=200,
43
47
  blank=True,
44
48
  )
45
49
  abuse_email = models.EmailField(
46
- verbose_name="Abuse Email",
50
+ verbose_name=_("Abuse Email"),
47
51
  blank=True,
48
52
  )
49
53
  abuse_phone = models.CharField(
50
- verbose_name="Abuse Phone",
54
+ verbose_name=_("Abuse Phone"),
51
55
  max_length=50,
52
56
  blank=True,
53
57
  )
@@ -59,8 +63,8 @@ class Registrar(NetBoxModel):
59
63
  return str(self.name)
60
64
 
61
65
  class Meta:
62
- verbose_name = "Registrar"
63
- verbose_name_plural = "Registrars"
66
+ verbose_name = _("Registrar")
67
+ verbose_name_plural = _("Registrars")
64
68
 
65
69
  ordering = (
66
70
  "name",
@@ -1,5 +1,6 @@
1
1
  from django.db import models
2
2
  from django.urls import reverse
3
+ from django.utils.translation import gettext_lazy as _
3
4
 
4
5
  from netbox.models import NetBoxModel
5
6
  from netbox.search import SearchIndex, register_search
@@ -18,70 +19,81 @@ class RegistrationContact(NetBoxModel):
18
19
  # Data fields according to https://www.icann.org/resources/pages/rdds-labeling-policy-2017-02-01-en
19
20
  # -
20
21
  contact_id = models.CharField(
21
- verbose_name="Contact ID",
22
+ verbose_name=_("Contact ID"),
22
23
  max_length=50,
23
24
  unique=True,
24
25
  )
25
26
  name = models.CharField(
27
+ verbose_name=_("Name"),
26
28
  blank=True,
27
29
  max_length=100,
28
30
  )
29
31
  description = models.CharField(
32
+ verbose_name=_("Description"),
30
33
  blank=True,
31
34
  max_length=200,
32
35
  )
33
36
  organization = models.CharField(
37
+ verbose_name=_("Organization"),
34
38
  blank=True,
35
39
  max_length=200,
36
40
  )
37
41
  street = models.CharField(
42
+ verbose_name=_("Street"),
38
43
  blank=True,
39
44
  max_length=50,
40
45
  )
41
46
  city = models.CharField(
47
+ verbose_name=_("City"),
42
48
  blank=True,
43
49
  max_length=50,
44
50
  )
45
51
  state_province = models.CharField(
46
- verbose_name="State/Province",
52
+ verbose_name=_("State/Province"),
47
53
  blank=True,
48
54
  max_length=255,
49
55
  )
50
56
  postal_code = models.CharField(
51
- verbose_name="Postal Code",
57
+ verbose_name=_("Postal Code"),
52
58
  blank=True,
53
59
  max_length=20,
54
60
  )
55
61
  country = models.CharField(
56
- verbose_name="Country (ISO 3166)",
62
+ verbose_name=_("Country (ISO 3166)"),
57
63
  blank=True,
58
64
  max_length=2,
59
65
  )
60
66
  phone = models.CharField(
61
- verbose_name="Phone",
67
+ verbose_name=_("Phone"),
62
68
  blank=True,
63
69
  max_length=50,
64
70
  )
65
71
  phone_ext = models.CharField(
66
- verbose_name="Phone Extension",
72
+ verbose_name=_("Phone Extension"),
67
73
  blank=True,
68
74
  max_length=50,
69
75
  )
70
76
  fax = models.CharField(
71
- verbose_name="Fax",
77
+ verbose_name=_("Fax"),
72
78
  blank=True,
73
79
  max_length=50,
74
80
  )
75
81
  fax_ext = models.CharField(
76
- verbose_name="Fax Extension",
82
+ verbose_name=_("Fax Extension"),
77
83
  blank=True,
78
84
  max_length=50,
79
85
  )
80
86
  email = models.EmailField(
81
- verbose_name="Email",
87
+ verbose_name=_("Email"),
82
88
  blank=True,
83
89
  )
84
90
 
91
+ # +
92
+ # TODO: Retained for backwards compatibility with older versions where
93
+ # 'RegistrationContact' was still ambiguously named 'Contact'.
94
+ #
95
+ # Removing it requires a data migration.
96
+ # -
85
97
  tags = TaggableManager(
86
98
  through="extras.TaggedItem",
87
99
  related_name="netbox_dns_contact_set",
@@ -114,8 +126,8 @@ class RegistrationContact(NetBoxModel):
114
126
  return self.contact_id
115
127
 
116
128
  class Meta:
117
- verbose_name = "Registration Contact"
118
- verbose_name_plural = "Registration Contacts"
129
+ verbose_name = _("Registration Contact")
130
+ verbose_name_plural = _("Registration Contacts")
119
131
 
120
132
  ordering = (
121
133
  "name",