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
+45
-50
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Annotated
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request, Response
|
||||
@@ -18,72 +19,67 @@ from ..services.ddns import normalize_hostname
|
||||
from ..web.components import _copy_row
|
||||
from ..web.forms import first_form_value, request_form
|
||||
from ..web.html_utils import SafeHtml
|
||||
from ..web.templates_admin import _admin_notice, _admin_secret_panel, _render_admin_page
|
||||
from ..web.templates_admin import _admin_notice, _admin_page_context, _admin_secret_panel, _render_admin_page
|
||||
|
||||
ADMIN_TABLE_LIMIT = 100
|
||||
ADMIN_JSON_OFFSET_CAP = 10_000
|
||||
AdminAuthDep = Annotated[None, Depends(authenticate_admin)]
|
||||
AdminOffsetQuery = Annotated[int, Query(ge=0)]
|
||||
CleanupDoneQuery = Annotated[bool, Query()]
|
||||
CleanupCountQuery = Annotated[int, Query(ge=0)]
|
||||
|
||||
|
||||
def _admin_table_offsets(
|
||||
accounts_offset: AdminOffsetQuery = 0,
|
||||
cleanup_runs_offset: AdminOffsetQuery = 0,
|
||||
update_events_offset: AdminOffsetQuery = 0,
|
||||
) -> dict[str, int]:
|
||||
return {
|
||||
"accounts": accounts_offset,
|
||||
"cleanup_runs": cleanup_runs_offset,
|
||||
"update_events": update_events_offset,
|
||||
}
|
||||
|
||||
|
||||
def _admin_cleanup_notice(
|
||||
cleanup_done: CleanupDoneQuery = False,
|
||||
cleanup_unused: CleanupCountQuery = 0,
|
||||
cleanup_events: CleanupCountQuery = 0,
|
||||
) -> SafeHtml | None:
|
||||
if not cleanup_done:
|
||||
return None
|
||||
return _admin_notice(
|
||||
"success",
|
||||
f"Cleanup finished. Removed {cleanup_unused} hostnames and {cleanup_events} old events.",
|
||||
)
|
||||
|
||||
|
||||
AdminTableOffsetsDep = Annotated[dict[str, int], Depends(_admin_table_offsets)]
|
||||
AdminCleanupNoticeDep = Annotated[SafeHtml | None, Depends(_admin_cleanup_notice)]
|
||||
|
||||
|
||||
def make_router(admin_path: str = "/admin") -> APIRouter:
|
||||
router = APIRouter()
|
||||
|
||||
def render_admin(
|
||||
service: ServiceDep,
|
||||
settings: SettingsDep,
|
||||
store: StoreDep,
|
||||
table_offsets: dict[str, int] | None = None,
|
||||
notice: SafeHtml | None = None,
|
||||
) -> str:
|
||||
table_offsets = table_offsets or {}
|
||||
return _render_admin_page(
|
||||
service,
|
||||
settings,
|
||||
store.list_accounts(limit=ADMIN_TABLE_LIMIT, offset=table_offsets.get("accounts", 0)),
|
||||
store.list_cleanup_runs(limit=ADMIN_TABLE_LIMIT, offset=table_offsets.get("cleanup_runs", 0)),
|
||||
store.list_scheduled_tasks(),
|
||||
store.list_update_events(ADMIN_TABLE_LIMIT, offset=table_offsets.get("update_events", 0)),
|
||||
store.get_service_metrics(),
|
||||
{
|
||||
"accounts": store.count_accounts(),
|
||||
"cleanup_runs": store.count_cleanup_runs(),
|
||||
"update_events": store.count_update_events(),
|
||||
},
|
||||
table_offsets,
|
||||
ADMIN_TABLE_LIMIT,
|
||||
notice,
|
||||
)
|
||||
context = _admin_page_context(store, table_offsets, ADMIN_TABLE_LIMIT, notice)
|
||||
return _render_admin_page(settings, context)
|
||||
|
||||
@router.get(admin_path, response_class=HTMLResponse, include_in_schema=False)
|
||||
def admin(
|
||||
settings: SettingsDep,
|
||||
store: StoreDep,
|
||||
service: ServiceDep,
|
||||
_: None = Depends(authenticate_admin),
|
||||
accounts_offset: int = Query(0, ge=0),
|
||||
cleanup_runs_offset: int = Query(0, ge=0),
|
||||
update_events_offset: int = Query(0, ge=0),
|
||||
cleanup_done: bool = Query(False),
|
||||
cleanup_unused: int = Query(0, ge=0),
|
||||
cleanup_events: int = Query(0, ge=0),
|
||||
_: AdminAuthDep,
|
||||
table_offsets: AdminTableOffsetsDep,
|
||||
notice: AdminCleanupNoticeDep,
|
||||
) -> str:
|
||||
notice = (
|
||||
_admin_notice(
|
||||
"success", f"Cleanup finished. Removed {cleanup_unused} hostnames and {cleanup_events} old events."
|
||||
)
|
||||
if cleanup_done
|
||||
else None
|
||||
)
|
||||
return render_admin(
|
||||
service,
|
||||
settings,
|
||||
store,
|
||||
{
|
||||
"accounts": accounts_offset,
|
||||
"cleanup_runs": cleanup_runs_offset,
|
||||
"update_events": update_events_offset,
|
||||
},
|
||||
notice,
|
||||
)
|
||||
return render_admin(settings, store, table_offsets, notice)
|
||||
|
||||
@router.post(f"{admin_path}/hostnames/delete", include_in_schema=False)
|
||||
async def admin_delete_account(
|
||||
@@ -91,7 +87,7 @@ def make_router(admin_path: str = "/admin") -> APIRouter:
|
||||
settings: SettingsDep,
|
||||
store: StoreDep,
|
||||
service: ServiceDep,
|
||||
_: None = Depends(authenticate_admin),
|
||||
_: AdminAuthDep,
|
||||
) -> Response:
|
||||
form = await request_form(request, settings)
|
||||
require_admin_csrf(settings, first_form_value(form, "csrf"))
|
||||
@@ -118,7 +114,7 @@ def make_router(admin_path: str = "/admin") -> APIRouter:
|
||||
settings: SettingsDep,
|
||||
store: StoreDep,
|
||||
service: ServiceDep,
|
||||
_: None = Depends(authenticate_admin),
|
||||
_: AdminAuthDep,
|
||||
) -> Response:
|
||||
form = await request_form(request, settings)
|
||||
require_admin_csrf(settings, first_form_value(form, "csrf"))
|
||||
@@ -168,7 +164,7 @@ def make_router(admin_path: str = "/admin") -> APIRouter:
|
||||
)
|
||||
else:
|
||||
raise HTTPException(status_code=400, detail="invalid rotation action")
|
||||
page = await run_in_threadpool(render_admin, service, settings, store, None, notice)
|
||||
page = await run_in_threadpool(render_admin, settings, store, None, notice)
|
||||
return HTMLResponse(page)
|
||||
|
||||
@router.post(f"{admin_path}/cleanup", include_in_schema=False)
|
||||
@@ -176,8 +172,7 @@ def make_router(admin_path: str = "/admin") -> APIRouter:
|
||||
request: Request,
|
||||
settings: SettingsDep,
|
||||
store: StoreDep,
|
||||
service: ServiceDep,
|
||||
_: None = Depends(authenticate_admin),
|
||||
_: AdminAuthDep,
|
||||
) -> Response:
|
||||
form = await request_form(request, settings)
|
||||
require_admin_csrf(settings, first_form_value(form, "csrf"))
|
||||
|
||||
Reference in new issue
Block a user