mirror of
https://git.private.coffee/PrivateCoffee/mallarddns.git
synced 2026-04-23 05:56: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 requests
|
||||||
import re
|
import re
|
||||||
from django.db import transaction
|
|
||||||
from .models import HostsOverrideRecord
|
from .models import HostsOverrideRecord
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
def parse_hosts_lines(lines, source_name):
|
def parse_hosts_lines(lines, source_obj):
|
||||||
result = []
|
result = []
|
||||||
hosts_re = re.compile(r"^\s*([0-9a-fA-F:\.]+)\s+([^\s#]+)")
|
hosts_re = re.compile(r"^\s*([0-9a-fA-F:\.]+)\s+([^\s#]+)")
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
|
@ -27,7 +28,7 @@ def parse_hosts_lines(lines, source_name):
|
||||||
"record_type": rtype,
|
"record_type": rtype,
|
||||||
"value": ip,
|
"value": ip,
|
||||||
"wildcard": wildcard,
|
"wildcard": wildcard,
|
||||||
"source": source_name,
|
"import_source": source_obj,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
@ -37,44 +38,25 @@ def import_hosts_from_url(source):
|
||||||
resp = requests.get(source.url, timeout=60)
|
resp = requests.get(source.url, timeout=60)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
lines = resp.text.splitlines()
|
lines = resp.text.splitlines()
|
||||||
entries = parse_hosts_lines(lines, source.description or source.url)
|
entries = parse_hosts_lines(lines, source)
|
||||||
new_records = {(e["name"], e["record_type"], e["value"]): e for e in entries}
|
|
||||||
existing_qs = HostsOverrideRecord.objects.filter(
|
# Remove all old records from this import source
|
||||||
source=source.description or source.url
|
HostsOverrideRecord.objects.filter(import_source=source).delete()
|
||||||
)
|
|
||||||
existing_records = {(r.name, r.record_type, r.value): r for r in existing_qs}
|
# Create all new records
|
||||||
to_create, to_update, to_enable, to_disable = [], [], [], []
|
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.last_import = timezone.now()
|
||||||
source.save()
|
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)
|
value = models.CharField(max_length=255)
|
||||||
wildcard = models.BooleanField(default=False)
|
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)
|
enabled = models.BooleanField(default=True)
|
||||||
|
|
||||||
def __str__(self):
|
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):
|
class HostsFileImportSource(models.Model):
|
||||||
|
|
@ -84,4 +100,4 @@ class TrustAnchor(models.Model):
|
||||||
last_updated = models.DateTimeField(auto_now=True)
|
last_updated = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
def __str__(self):
|
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