Archived
Refactor UI assets and harden quality checks
This commit is contained in:
1 parent
23ab466c52
commit
4ecc8eb874
62 files changed
+3314
-3206
No files matched your search
+93
-42
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from ..models import UpdateResult
|
||||
@@ -8,6 +9,60 @@ from .base import StoreConnectionMixin
|
||||
from .types import RecordRow, UpdateEventRow, record_row, update_event_row
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class UpdateEventInput:
|
||||
hostname: str
|
||||
ipv4: str | None
|
||||
ipv6: str | None
|
||||
status: str
|
||||
detail: str
|
||||
source_ip: str
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class RecordUpdateInput:
|
||||
hostname: str
|
||||
ipv4: str | None
|
||||
ipv6: str | None
|
||||
update_ipv4: bool = True
|
||||
update_ipv6: bool = True
|
||||
|
||||
|
||||
def _update_event_input(event: UpdateEventInput | str, legacy_values: tuple[object, ...]) -> UpdateEventInput:
|
||||
if isinstance(event, UpdateEventInput):
|
||||
return event
|
||||
if len(legacy_values) != 5:
|
||||
raise TypeError("legacy update event values must be ipv4, ipv6, status, detail, source_ip")
|
||||
ipv4, ipv6, status, detail, source_ip = legacy_values
|
||||
return UpdateEventInput(
|
||||
hostname=event,
|
||||
ipv4=str(ipv4) if ipv4 is not None else None,
|
||||
ipv6=str(ipv6) if ipv6 is not None else None,
|
||||
status=str(status),
|
||||
detail=str(detail),
|
||||
source_ip=str(source_ip),
|
||||
)
|
||||
|
||||
|
||||
def _planned_record_update(
|
||||
update: RecordUpdateInput,
|
||||
*,
|
||||
current_ipv4: str | None,
|
||||
current_ipv6: str | None,
|
||||
existing: bool,
|
||||
) -> UpdateResult:
|
||||
effective_ipv4 = update.ipv4 if update.update_ipv4 else current_ipv4
|
||||
effective_ipv6 = update.ipv6 if update.update_ipv6 else current_ipv6
|
||||
return UpdateResult(
|
||||
hostname=update.hostname,
|
||||
ipv4=effective_ipv4,
|
||||
ipv6=effective_ipv6,
|
||||
changed=not existing or current_ipv4 != effective_ipv4 or current_ipv6 != effective_ipv6,
|
||||
update_ipv4=update.update_ipv4,
|
||||
update_ipv6=update.update_ipv6,
|
||||
)
|
||||
|
||||
|
||||
class RecordsEventsMixin(StoreConnectionMixin):
|
||||
def upsert(
|
||||
self,
|
||||
@@ -18,13 +73,17 @@ class RecordsEventsMixin(StoreConnectionMixin):
|
||||
update_ipv6: bool = True,
|
||||
) -> UpdateResult:
|
||||
now = datetime.now(UTC).isoformat()
|
||||
update = RecordUpdateInput(hostname, ipv4, ipv6, update_ipv4, update_ipv6)
|
||||
with self.connect() as conn:
|
||||
existing = conn.execute("SELECT ipv4, ipv6 FROM records WHERE hostname = ?", (hostname,)).fetchone()
|
||||
current_ipv4 = existing["ipv4"] if existing else None
|
||||
current_ipv6 = existing["ipv6"] if existing else None
|
||||
effective_ipv4 = ipv4 if update_ipv4 else current_ipv4
|
||||
effective_ipv6 = ipv6 if update_ipv6 else current_ipv6
|
||||
changed = existing is None or current_ipv4 != effective_ipv4 or current_ipv6 != effective_ipv6
|
||||
result = _planned_record_update(
|
||||
update,
|
||||
current_ipv4=current_ipv4,
|
||||
current_ipv6=current_ipv6,
|
||||
existing=existing is not None,
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO records(hostname, ipv4, ipv6, updated_at)
|
||||
@@ -34,16 +93,9 @@ class RecordsEventsMixin(StoreConnectionMixin):
|
||||
ipv6=excluded.ipv6,
|
||||
updated_at=excluded.updated_at
|
||||
""",
|
||||
(hostname, effective_ipv4, effective_ipv6, now),
|
||||
(result.hostname, result.ipv4, result.ipv6, now),
|
||||
)
|
||||
return UpdateResult(
|
||||
hostname=hostname,
|
||||
ipv4=effective_ipv4,
|
||||
ipv6=effective_ipv6,
|
||||
changed=changed,
|
||||
update_ipv4=update_ipv4,
|
||||
update_ipv6=update_ipv6,
|
||||
)
|
||||
return result
|
||||
|
||||
def commit_update_result(self, result: UpdateResult) -> UpdateResult:
|
||||
now = datetime.now(UTC).isoformat()
|
||||
@@ -69,20 +121,16 @@ class RecordsEventsMixin(StoreConnectionMixin):
|
||||
update_ipv4: bool = True,
|
||||
update_ipv6: bool = True,
|
||||
) -> UpdateResult:
|
||||
update = RecordUpdateInput(hostname, ipv4, ipv6, update_ipv4, update_ipv6)
|
||||
with self.connect() as conn:
|
||||
existing = conn.execute("SELECT ipv4, ipv6 FROM records WHERE hostname = ?", (hostname,)).fetchone()
|
||||
current_ipv4 = existing["ipv4"] if existing else None
|
||||
current_ipv6 = existing["ipv6"] if existing else None
|
||||
effective_ipv4 = ipv4 if update_ipv4 else current_ipv4
|
||||
effective_ipv6 = ipv6 if update_ipv6 else current_ipv6
|
||||
changed = existing is None or current_ipv4 != effective_ipv4 or current_ipv6 != effective_ipv6
|
||||
return UpdateResult(
|
||||
hostname=hostname,
|
||||
ipv4=effective_ipv4,
|
||||
ipv6=effective_ipv6,
|
||||
changed=changed,
|
||||
update_ipv4=update_ipv4,
|
||||
update_ipv6=update_ipv6,
|
||||
return _planned_record_update(
|
||||
update,
|
||||
current_ipv4=current_ipv4,
|
||||
current_ipv6=current_ipv6,
|
||||
existing=existing is not None,
|
||||
)
|
||||
|
||||
def list_records(self) -> list[RecordRow]:
|
||||
@@ -106,33 +154,27 @@ class RecordsEventsMixin(StoreConnectionMixin):
|
||||
row = conn.execute("SELECT COUNT(*) FROM records").fetchone()
|
||||
return int(row[0])
|
||||
|
||||
def log_update_event(
|
||||
self,
|
||||
hostname: str,
|
||||
ipv4: str | None,
|
||||
ipv6: str | None,
|
||||
status: str,
|
||||
detail: str,
|
||||
source_ip: str,
|
||||
) -> None:
|
||||
def log_update_event(self, event: UpdateEventInput | str, *legacy_values: object) -> None:
|
||||
event = _update_event_input(event, legacy_values)
|
||||
with self.connect() as conn:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO update_events(hostname, ipv4, ipv6, status, detail, source_ip, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(hostname, ipv4, ipv6, status, detail[:500], source_ip, datetime.now(UTC).isoformat()),
|
||||
(
|
||||
event.hostname,
|
||||
event.ipv4,
|
||||
event.ipv6,
|
||||
event.status,
|
||||
event.detail[:500],
|
||||
event.source_ip,
|
||||
datetime.now(UTC).isoformat(),
|
||||
),
|
||||
)
|
||||
|
||||
def log_update_rollup(
|
||||
self,
|
||||
hostname: str,
|
||||
ipv4: str | None,
|
||||
ipv6: str | None,
|
||||
status: str,
|
||||
detail: str,
|
||||
source_ip: str,
|
||||
) -> None:
|
||||
def log_update_rollup(self, event: UpdateEventInput | str, *legacy_values: object) -> None:
|
||||
event = _update_event_input(event, legacy_values)
|
||||
now = datetime.now(UTC).isoformat()
|
||||
with self.connect() as conn:
|
||||
conn.execute(
|
||||
@@ -145,7 +187,16 @@ class RecordsEventsMixin(StoreConnectionMixin):
|
||||
last_seen_at=excluded.last_seen_at,
|
||||
count=count + 1
|
||||
""",
|
||||
(hostname, ipv4 or "", ipv6 or "", status, detail[:500], source_ip, now, now),
|
||||
(
|
||||
event.hostname,
|
||||
event.ipv4 or "",
|
||||
event.ipv6 or "",
|
||||
event.status,
|
||||
event.detail[:500],
|
||||
event.source_ip,
|
||||
now,
|
||||
now,
|
||||
),
|
||||
)
|
||||
|
||||
def list_update_events(self, limit: int = 100, offset: int = 0) -> list[UpdateEventRow]:
|
||||
|
||||
Reference in new issue
Block a user