mirror of
https://git.private.coffee/PrivateCoffee/mallarddns.git
synced 2026-04-22 21:46:23 +05:30
feat: Improve list import logic
This commit is contained in:
parent
377dece592
commit
7c12371655
3 changed files with 77 additions and 44 deletions
|
|
@ -1,11 +1,12 @@
|
|||
import requests
|
||||
import re
|
||||
from django.db import transaction
|
||||
|
||||
from .models import HostsOverrideRecord
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
def parse_hosts_lines(lines, source_name):
|
||||
def parse_hosts_lines(lines, source_obj):
|
||||
result = []
|
||||
hosts_re = re.compile(r"^\s*([0-9a-fA-F:\.]+)\s+([^\s#]+)")
|
||||
for line in lines:
|
||||
|
|
@ -27,7 +28,7 @@ def parse_hosts_lines(lines, source_name):
|
|||
"record_type": rtype,
|
||||
"value": ip,
|
||||
"wildcard": wildcard,
|
||||
"source": source_name,
|
||||
"import_source": source_obj,
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
|
@ -37,44 +38,25 @@ def import_hosts_from_url(source):
|
|||
resp = requests.get(source.url, timeout=60)
|
||||
resp.raise_for_status()
|
||||
lines = resp.text.splitlines()
|
||||
entries = parse_hosts_lines(lines, source.description or source.url)
|
||||
new_records = {(e["name"], e["record_type"], e["value"]): e for e in entries}
|
||||
existing_qs = HostsOverrideRecord.objects.filter(
|
||||
source=source.description or source.url
|
||||
)
|
||||
existing_records = {(r.name, r.record_type, r.value): r for r in existing_qs}
|
||||
to_create, to_update, to_enable, to_disable = [], [], [], []
|
||||
entries = parse_hosts_lines(lines, source)
|
||||
|
||||
# Remove all old records from this import source
|
||||
HostsOverrideRecord.objects.filter(import_source=source).delete()
|
||||
|
||||
# Create all new records
|
||||
bulk = [
|
||||
HostsOverrideRecord(
|
||||
name=e["name"],
|
||||
record_type=e["record_type"],
|
||||
value=e["value"],
|
||||
wildcard=e["wildcard"],
|
||||
import_source=source,
|
||||
enabled=True,
|
||||
)
|
||||
for e in entries
|
||||
]
|
||||
|
||||
HostsOverrideRecord.objects.bulk_create(bulk, batch_size=500)
|
||||
|
||||
for key, entry in new_records.items():
|
||||
if key in existing_records:
|
||||
record = existing_records[key]
|
||||
if not record.enabled:
|
||||
to_enable.append(record.pk)
|
||||
if record.wildcard != entry["wildcard"]:
|
||||
record.wildcard = entry["wildcard"]
|
||||
to_update.append(record)
|
||||
else:
|
||||
to_create.append(
|
||||
HostsOverrideRecord(
|
||||
name=entry["name"],
|
||||
record_type=entry["record_type"],
|
||||
value=entry["value"],
|
||||
wildcard=entry["wildcard"],
|
||||
source=entry["source"],
|
||||
enabled=True,
|
||||
)
|
||||
)
|
||||
for key, record in existing_records.items():
|
||||
if key not in new_records and record.enabled:
|
||||
to_disable.append(record.pk)
|
||||
with transaction.atomic():
|
||||
if to_create:
|
||||
HostsOverrideRecord.objects.bulk_create(to_create, batch_size=500)
|
||||
if to_update:
|
||||
HostsOverrideRecord.objects.bulk_update(to_update, ["wildcard"])
|
||||
if to_enable:
|
||||
HostsOverrideRecord.objects.filter(pk__in=to_enable).update(enabled=True)
|
||||
if to_disable:
|
||||
HostsOverrideRecord.objects.filter(pk__in=to_disable).update(enabled=False)
|
||||
source.last_import = timezone.now()
|
||||
source.save()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
# Generated by Django 5.2.7 on 2025-10-25 15:24
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("records", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="hostsoverriderecord",
|
||||
name="import_source",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Set for records imported from a hosts file source.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="records",
|
||||
to="records.hostsfileimportsource",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="hostsoverriderecord",
|
||||
name="source",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
help_text="Optional note for manually-added records.",
|
||||
max_length=255,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
@ -48,11 +48,27 @@ class HostsOverrideRecord(models.Model):
|
|||
)
|
||||
value = models.CharField(max_length=255)
|
||||
wildcard = models.BooleanField(default=False)
|
||||
source = models.CharField(max_length=255)
|
||||
source = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text="Optional note for manually-added records.",
|
||||
)
|
||||
import_source = models.ForeignKey(
|
||||
"HostsFileImportSource",
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="records",
|
||||
help_text="Set for records imported from a hosts file source.",
|
||||
)
|
||||
enabled = models.BooleanField(default=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} {self.record_type} {self.value} ({'wildcard' if self.wildcard else 'exact'})"
|
||||
if self.import_source:
|
||||
src = f"(imported from: {self.import_source})"
|
||||
else:
|
||||
src = self.source or "manual"
|
||||
return f"{self.name} {self.record_type} {self.value} ({'wildcard' if self.wildcard else 'exact'}) {src}"
|
||||
|
||||
|
||||
class HostsFileImportSource(models.Model):
|
||||
|
|
@ -84,4 +100,4 @@ class TrustAnchor(models.Model):
|
|||
last_updated = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"KSK {self.key_tag}" if self.flags & 0x0001 else f"ZSK {self.key_tag}"
|
||||
return f"KSK {self.key_tag}" if self.flags & 0x0001 else f"ZSK {self.key_tag}"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue