diff --git a/README.md b/README.md index 1788592..beb31bf 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,17 @@ pip3 install --upgrade pip pip3 install -f src/requirements.txt ``` -## Installation - -Run it manually via: +Test if your installation works: ``` python3 src/manage.py test ``` +## Installation + +Run it manually via: +``` +python3 src/manage.py runserver +``` + For production environments, gunicorn or a similar UWSGI implementation, preferably using a webserver as a proxy is recommended. diff --git a/src/pdns/migrations/0006_rename_domain_name_pdnsdomain_name_and_more.py b/src/pdns/migrations/0006_rename_domain_name_pdnsdomain_name_and_more.py new file mode 100644 index 0000000..a31eab7 --- /dev/null +++ b/src/pdns/migrations/0006_rename_domain_name_pdnsdomain_name_and_more.py @@ -0,0 +1,45 @@ +# Generated by Django 5.2.5 on 2025-10-24 09:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("pdns", "0005_pdnsdomain_domain_type"), + ] + + operations = [ + migrations.RenameField( + model_name="pdnsdomain", + old_name="domain_name", + new_name="name", + ), + migrations.RenameField( + model_name="pdnsdomain", + old_name="domain_type", + new_name="type", + ), + migrations.AddField( + model_name="pdnsdomain", + name="last_loaded", + field=models.DateTimeField( + editable=False, null=True, verbose_name="Last loaded" + ), + ), + migrations.AddField( + model_name="pdnsdomain", + name="last_notified", + field=models.PositiveIntegerField( + editable=False, null=True, verbose_name="Last notified serial" + ), + ), + migrations.AddField( + model_name="pdnsdomain", + name="serial", + field=models.PositiveIntegerField( + default=1970010101, verbose_name="Serial" + ), + preserve_default=False, + ), + ] diff --git a/src/pdns/migrations/0007_rename_type_pdnsdomain_domain_type_and_more.py b/src/pdns/migrations/0007_rename_type_pdnsdomain_domain_type_and_more.py new file mode 100644 index 0000000..5a373b7 --- /dev/null +++ b/src/pdns/migrations/0007_rename_type_pdnsdomain_domain_type_and_more.py @@ -0,0 +1,57 @@ +# Generated by Django 5.2.5 on 2025-10-27 21:51 + +import django.core.validators +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("pdns", "0006_rename_domain_name_pdnsdomain_name_and_more"), + ] + + operations = [ + migrations.RenameField( + model_name="pdnsdomain", + old_name="type", + new_name="domain_type", + ), + migrations.AlterField( + model_name="pdnsdomain", + name="name", + field=models.CharField( + max_length=250, + validators=[ + django.core.validators.DomainNameValidator( + message="Must be a valid domain name." + ) + ], + verbose_name="Name", + ), + ), + migrations.CreateModel( + name="PDNSResourceRecord", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("record_type", models.CharField(verbose_name="Type")), + ( + "domain", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="records", + to="pdns.pdnsdomain", + verbose_name="Domain", + ), + ), + ], + ), + ] diff --git a/src/pdns/models.py b/src/pdns/models.py index 25a4360..b893c8b 100644 --- a/src/pdns/models.py +++ b/src/pdns/models.py @@ -5,26 +5,29 @@ from django.db import models from django.utils.timezone import now from django.utils.translation import gettext as _ - -# Okay, going to illustrate my thinking here: -# A ##Context## is a set of servers that operate together as -# authoritative for a group of zones. - -# (I was going to call it a Network, but then I found out -# about https://doc.powerdns.com/authoritative/views.html ) - -# All ##Servers## within a Context are presumed to be -# using the same database and be otherwise interchangeable, -# Although given the limitations of some backends they can -# be set to read-only. +from django.core.validators import DomainNameValidator -# Basic code structure convention for models: -# 1. Meta information -# 2. Data fields -# 3. Functions -# Alphabetical order within each of those categories if -# possible. +""" + Okay, going to illustrate my thinking here: + A ##Context## is a set of servers that operate together + as authoritative for a group of zones. + + (I was going to call it a Network, but then I found out + about https://doc.powerdns.com/authoritative/views.html ) + + All ##Servers## within a Context are presumed to be + using the same database and be otherwise interchangeable, + 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 +""" class PDNSContext(models.Model): description = models.TextField(verbose_name=_('Description'), @@ -88,8 +91,10 @@ class PDNSServer(models.Model): default=False ) - # Depending on the PDNS cluster architecture certain servers - # might not be writeable due to the backend. + """ + Depending on the PDNS cluster architecture certain servers might not + be writeable due to the backend, so we allow for that. + """ readonly = models.BooleanField(verbose_name=_('Read Only'), default=False ) @@ -137,12 +142,47 @@ class PDNSDomain(models.Model): on_delete=models.CASCADE, ) - domain_name = models.CharField(verbose_name='Name', + name = models.CharField(verbose_name='Name', max_length=250, + validators=[DomainNameValidator(message=_('Must be a valid domain name.'))] ) + # Avoiding possible collision with the 'type' soft keyword; + # see https://docs.python.org/3/reference/lexical_analysis.html#soft-keywords + domain_type = models.CharField(verbose_name='Type', choices=DOMAIN_TYPE_CHOICES, default=DOMAIN_TYPE_CHOICES['NATIVE'] ) + """ + ##convention## for serials is YYYYMMDDNN with NN being incremented + each time the domain is updated on the same day, but there is no + rule against going 1,2,3,4... + """ + + serial = models.PositiveIntegerField(verbose_name=_('Serial'), + ) + + last_notified = models.PositiveIntegerField(verbose_name=_('Last notified serial'), + editable=False, + null=True + ) + + last_loaded = models.DateTimeField(verbose_name=_('Last loaded'), + editable=False, + null=True + ) + +class PDNSResourceRecord(models.Model): + """ + Individual record types will inherit from this and have custom + validators; this base class will serve for any record type we + didn't put in yet. + """ + domain = models.ForeignKey(PDNSDomain, verbose_name=_('Domain'), + on_delete=models.CASCADE, + related_name='records' + ) + + record_type = models.CharField(verbose_name='Type') \ No newline at end of file