Refactor UI assets and harden quality checks

This commit is contained in:
StasonJatham committed 2026-06-17 23:18:00 +02:00
1 parent 23ab466c52
commit 4ecc8eb874
62 files changed
+3314 -3206

No files matched your search

+8 -3
View File
@@ -9,6 +9,7 @@ from .types import AccountRow, account_row
class AccountsMixin(StoreConnectionMixin):
def create_account(self, hostname: str, username: str | None = None, *, accepted: bool = True) -> AccountRow:
_ = username
now = datetime.now(UTC).isoformat()
update_slug = new_bearer_secret()
management_slug = new_bearer_secret()
@@ -27,6 +28,7 @@ class AccountsMixin(StoreConnectionMixin):
"update_slug": update_slug,
"management_slug": management_slug,
"accepted_at": accepted_at,
"disabled": 0,
}
def list_accounts(self, limit: int = 100, offset: int = 0) -> list[AccountRow]:
@@ -34,7 +36,8 @@ class AccountsMixin(StoreConnectionMixin):
rows = conn.execute(
"""
SELECT accounts.hostname, accounts.update_slug,
accounts.created_at, accounts.accepted_at, accounts.disabled, records.ipv4, records.ipv6, records.updated_at
accounts.created_at, accounts.accepted_at, accounts.disabled,
records.ipv4, records.ipv6, records.updated_at
FROM accounts
LEFT JOIN records ON records.hostname = accounts.hostname
ORDER BY accounts.hostname
@@ -54,7 +57,8 @@ class AccountsMixin(StoreConnectionMixin):
account = conn.execute(
"""
SELECT accounts.hostname, accounts.update_slug, accounts.dashboard_password_hash,
accounts.created_at, accounts.accepted_at, accounts.disabled, records.ipv4, records.ipv6, records.updated_at
accounts.created_at, accounts.accepted_at, accounts.disabled,
records.ipv4, records.ipv6, records.updated_at
FROM accounts
LEFT JOIN records ON records.hostname = accounts.hostname
WHERE accounts.hostname = ?
@@ -79,7 +83,8 @@ class AccountsMixin(StoreConnectionMixin):
account = conn.execute(
"""
SELECT accounts.hostname, accounts.update_slug, accounts.dashboard_password_hash,
accounts.created_at, accounts.accepted_at, accounts.disabled, records.ipv4, records.ipv6, records.updated_at
accounts.created_at, accounts.accepted_at, accounts.disabled,
records.ipv4, records.ipv6, records.updated_at
FROM accounts
LEFT JOIN records ON records.hostname = accounts.hostname
WHERE accounts.management_hash = ?
+30 -13
View File
@@ -5,6 +5,29 @@ from datetime import UTC, datetime
from .base import StoreConnectionMixin
def _update_metric_increments(
latency_ms: float,
*,
is_success: bool,
is_dns_failure: bool,
is_reconcile_failure: bool,
is_bad_ip: bool,
) -> dict[str, float]:
increments: dict[str, float] = {
"update_requests_total": 1,
"update_latency_ms_total": latency_ms,
"update_latency_samples_total": 1,
}
optional_increments = {
"update_success_total": is_success,
"dns_failures_total": is_dns_failure,
"dns_reconcile_failures_total": is_reconcile_failure,
"bad_ip_total": is_bad_ip,
}
increments.update({name: 1 for name, enabled in optional_increments.items() if enabled})
return increments
class MetricsMixin(StoreConnectionMixin):
def increment_metric(self, name: str, amount: float = 1.0) -> None:
now = datetime.now(UTC).isoformat()
@@ -48,19 +71,13 @@ class MetricsMixin(StoreConnectionMixin):
is_reconcile_failure: bool = False,
is_bad_ip: bool = False,
) -> None:
increments = {
"update_requests_total": 1,
"update_latency_ms_total": latency_ms,
"update_latency_samples_total": 1,
}
if is_success:
increments["update_success_total"] = 1
if is_dns_failure:
increments["dns_failures_total"] = 1
if is_reconcile_failure:
increments["dns_reconcile_failures_total"] = 1
if is_bad_ip:
increments["bad_ip_total"] = 1
increments = _update_metric_increments(
latency_ms,
is_success=is_success,
is_dns_failure=is_dns_failure,
is_reconcile_failure=is_reconcile_failure,
is_bad_ip=is_bad_ip,
)
now = datetime.now(UTC).isoformat()
with self.connect() as conn:
+5 -3
View File
@@ -199,9 +199,11 @@ class RateLimitCleanupMixin(StoreConnectionMixin):
[
(
row["hostname"],
CLEANUP_PENDING_HOSTNAME_DELETED
if row["cleanup_reason"] == "pending"
else CLEANUP_UNUSED_HOSTNAME_DELETED,
(
CLEANUP_PENDING_HOSTNAME_DELETED
if row["cleanup_reason"] == "pending"
else CLEANUP_UNUSED_HOSTNAME_DELETED
),
"cleanup deleted abandoned hostname",
"127.0.0.1",
datetime.now(UTC).isoformat(),
+93 -42
View File
@@ -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]:
+4 -1
View File
@@ -186,7 +186,10 @@ def _migrate_accounts_schema(conn: sqlite3.Connection) -> None:
)
""")
conn.execute("""
INSERT INTO accounts_new(hostname, update_slug, management_hash, dashboard_password_hash, created_at, accepted_at, disabled)
INSERT INTO accounts_new(
hostname, update_slug, management_hash, dashboard_password_hash,
created_at, accepted_at, disabled
)
SELECT hostname, update_slug, management_hash, dashboard_password_hash, created_at, accepted_at, disabled
FROM accounts
""")
+12 -12
View File
@@ -1,22 +1,22 @@
from __future__ import annotations
from typing import Any, TypedDict, cast
from typing import Any, NotRequired, TypedDict, cast
class AccountRow(TypedDict, total=False):
class AccountRow(TypedDict):
hostname: str
update_slug: str
management_slug: str
dashboard_password_hash: str | None
created_at: str
accepted_at: str | None
disabled: int
ipv4: str | None
ipv6: str | None
updated_at: str | None
management_slug: NotRequired[str]
dashboard_password_hash: NotRequired[str | None]
created_at: NotRequired[str]
ipv4: NotRequired[str | None]
ipv6: NotRequired[str | None]
updated_at: NotRequired[str | None]
class UpdateEventRow(TypedDict, total=False):
class UpdateEventRow(TypedDict):
hostname: str
ipv4: str | None
ipv6: str | None
@@ -33,9 +33,9 @@ class CleanupRunRow(TypedDict):
class ScheduledTaskRow(TypedDict, total=False):
name: str
interval_seconds: int
next_run_at: str
name: NotRequired[str]
interval_seconds: NotRequired[int]
next_run_at: NotRequired[str]
lease_owner: str | None
lease_expires_at: str | None
last_started_at: str | None