From 7df213902e49fcb81e92ba3d201d3cbd8db625ec Mon Sep 17 00:00:00 2001 From: Rens Houben Date: Tue, 21 Oct 2025 16:47:44 +0200 Subject: [PATCH] Starting to expand the domain definitions. --- ...saccount_pdnsserver_readonly_pdnsdomain.py | 67 ++++++++++ .../migrations/0005_pdnsdomain_domain_type.py | 26 ++++ src/pdns/models.py | 114 ++++++++++++------ src/tests/basedata.py | 0 4 files changed, 173 insertions(+), 34 deletions(-) create mode 100644 src/pdns/migrations/0004_pdnsaccount_pdnsserver_readonly_pdnsdomain.py create mode 100644 src/pdns/migrations/0005_pdnsdomain_domain_type.py delete mode 100644 src/tests/basedata.py diff --git a/src/pdns/migrations/0004_pdnsaccount_pdnsserver_readonly_pdnsdomain.py b/src/pdns/migrations/0004_pdnsaccount_pdnsserver_readonly_pdnsdomain.py new file mode 100644 index 0000000..deaa6e6 --- /dev/null +++ b/src/pdns/migrations/0004_pdnsaccount_pdnsserver_readonly_pdnsdomain.py @@ -0,0 +1,67 @@ +# Generated by Django 5.2.5 on 2025-10-21 14:41 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("pdns", "0003_rename_fk_network_pdnsserver_context_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="PDNSAccount", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("description", models.TextField(verbose_name="Description")), + ("name", models.CharField(max_length=20, verbose_name="Name")), + ], + ), + migrations.AddField( + model_name="pdnsserver", + name="readonly", + field=models.BooleanField(default=False, verbose_name="Read Only"), + ), + migrations.CreateModel( + name="PDNSDomain", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("domain_name", models.CharField(max_length=250, verbose_name="Name")), + ( + "account", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="accounts", + to="pdns.pdnsaccount", + verbose_name="Account", + ), + ), + ( + "context", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="pdns.pdnscontext", + verbose_name="Context", + ), + ), + ], + ), + ] diff --git a/src/pdns/migrations/0005_pdnsdomain_domain_type.py b/src/pdns/migrations/0005_pdnsdomain_domain_type.py new file mode 100644 index 0000000..a501178 --- /dev/null +++ b/src/pdns/migrations/0005_pdnsdomain_domain_type.py @@ -0,0 +1,26 @@ +# Generated by Django 5.2.5 on 2025-10-21 14:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("pdns", "0004_pdnsaccount_pdnsserver_readonly_pdnsdomain"), + ] + + operations = [ + migrations.AddField( + model_name="pdnsdomain", + name="domain_type", + field=models.CharField( + choices=[ + ("NATIVE", "Native"), + ("PRIMARY", "Primary"), + ("SECONDARY", "Secondary"), + ], + default="Native", + verbose_name="Type", + ), + ), + ] diff --git a/src/pdns/models.py b/src/pdns/models.py index 560fc79..25a4360 100644 --- a/src/pdns/models.py +++ b/src/pdns/models.py @@ -18,30 +18,38 @@ from django.utils.translation import gettext as _ # Although given the limitations of some backends they can # be set to read-only. + +# Basic code structure convention for models: +# 1. Meta information +# 2. Data fields +# 3. Functions +# Alphabetical order within each of those categories if +# possible. + class PDNSContext(models.Model): + description = models.TextField(verbose_name=_('Description'), + blank=True, + null=True, + ) + name = models.CharField(verbose_name=_('Name'), max_length=20, unique=True, primary_key=True, ) - description = models.TextField(verbose_name=_('Description'), - blank=True, - null=True, - ) - def __str__(self): return self.name - def total_servers(self): - return self.servers.all().count() - - def online_servers(self): - return self.servers.filter(online=True).count() - + def available(self): + return self.online_servers() > 0 + def offline_servers(self): return self.servers.filter(online=False).count() - + + def online_servers(self): + return self.servers.filter(online=True).count() + def status(self): return _('Context %(name)s: %(total)d total, %(online)d online, %(offline)d offline.') % { 'name': self.name, @@ -49,35 +57,16 @@ class PDNSContext(models.Model): 'online': self.online_servers(), 'offline': self.offline_servers()} - def available(self): - return self.online_servers() > 0 - + def total_servers(self): + return self.servers.all().count() class PDNSServer(models.Model): - name = models.CharField(verbose_name=_('Name'), - max_length=40, - unique=True, - primary_key=True, - ) - - server_uri = models.URLField(verbose_name=_('Server URL'), - help_text='Prefer IP addresses; use FQDN at your own risk.', - max_length=80, - blank=False, - null=False - ) - - context=models.ForeignKey(PDNSContext, + context = models.ForeignKey(PDNSContext, verbose_name=_('Context'), on_delete=models.PROTECT, related_name='servers' ) - online = models.BooleanField(verbose_name=_('Online status'), - editable=False, - default=False - ) - last_checked = models.DateTimeField(verbose_name=_('Last checked'), editable=False, null=True @@ -88,6 +77,30 @@ class PDNSServer(models.Model): null=True ) + name = models.CharField(verbose_name=_('Name'), + max_length=40, + unique=True, + primary_key=True, + ) + + online = models.BooleanField(verbose_name=_('Online status'), + editable=False, + default=False + ) + + # Depending on the PDNS cluster architecture certain servers + # might not be writeable due to the backend. + readonly = models.BooleanField(verbose_name=_('Read Only'), + default=False + ) + + server_uri = models.URLField(verbose_name=_('Server URL'), + help_text='Prefer IP addresses; use FQDN at your own risk.', + max_length=80, + blank=False, + null=False + ) + def __str__(self): selfstr= _("%(name)s (%(context)s): %(url)s") % { 'name': self.name, 'context': self.context.name, @@ -100,3 +113,36 @@ class PDNSServer(models.Model): 'status': status, 'time': self.last_checked } + +class PDNSAccount(models.Model): + description = models.TextField(verbose_name=_('Description')) + name = models.CharField(verbose_name=_('Name'), + max_length=20 + ) + +class PDNSDomain(models.Model): + DOMAIN_TYPE_CHOICES = { + 'NATIVE': _('Native'), + 'PRIMARY': _('Primary'), + 'SECONDARY': _('Secondary') + } + account = models.ForeignKey(PDNSAccount, + verbose_name=_('Account'), + related_name='accounts', + on_delete=models.PROTECT, + null=False) + + context = models.ForeignKey(PDNSContext, + verbose_name=_('Context'), + on_delete=models.CASCADE, + ) + + domain_name = models.CharField(verbose_name='Name', + max_length=250, + ) + + domain_type = models.CharField(verbose_name='Type', + choices=DOMAIN_TYPE_CHOICES, + default=DOMAIN_TYPE_CHOICES['NATIVE'] + ) + diff --git a/src/tests/basedata.py b/src/tests/basedata.py deleted file mode 100644 index e69de29..0000000