diff --git a/router_dyndns/ddns.py b/router_dyndns/ddns.py index 7785a97..10a7928 100644 --- a/router_dyndns/ddns.py +++ b/router_dyndns/ddns.py @@ -334,34 +334,6 @@ def make_app(settings: DdnsSettings | None = None) -> FastAPI: store.list_cleanup_runs(), store.list_update_events(25), None, - None, - ) - - @app.post("/admin/accounts", include_in_schema=False) - async def admin_create_account(request: Request, _: None = Depends(authenticate_admin)) -> Response: - form = await _request_form(request, settings) - require_admin_csrf(settings, _first_form_value(form, "csrf")) - hostname = normalize_hostname(_first_form_value(form, "hostname"), settings) - username = _first_form_value(form, "username") or None - if not hostname: - raise HTTPException(status_code=400, detail="hostname is required") - if settings.allowed_hosts and hostname not in settings.allowed_hosts: - raise HTTPException(status_code=403, detail="hostname is not allowed") - try: - account = store.create_account(hostname, username) - except sqlite3.IntegrityError as exc: - raise HTTPException(status_code=409, detail="hostname already exists") from exc - return HTMLResponse( - _render_admin_page( - service, - settings, - store.list_accounts(), - store.list_domain_challenges(), - store.list_cleanup_runs(), - store.list_update_events(25), - account, - None, - ) ) @app.post("/admin/accounts/delete", include_in_schema=False) @@ -414,7 +386,6 @@ def make_app(settings: DdnsSettings | None = None) -> FastAPI: store.list_domain_challenges(), store.list_cleanup_runs(), store.list_update_events(25), - None, notice, ) ) @@ -439,7 +410,6 @@ def make_app(settings: DdnsSettings | None = None) -> FastAPI: store.list_domain_challenges(), store.list_cleanup_runs(), store.list_update_events(25), - None, notice, ) ) @@ -769,10 +739,6 @@ def _credentials_panel(service: DdnsService, created_account: dict[str, str] | N """ -def _created_account_panel(service: DdnsService, created_account: dict[str, str] | None) -> str: - return _credentials_panel(service, created_account) - - def _admin_secret_panel(title: str, rows: list[str]) -> str: return f"""
@@ -913,7 +879,6 @@ def _render_admin_page( domain_challenges: list[dict[str, str | None]], cleanup_runs: list[dict[str, str | int]], update_events: list[dict[str, str | None]], - created_account: dict[str, str] | None, notice_html: str | None, ) -> str: csrf = html.escape(admin_csrf_token(settings)) @@ -929,11 +894,6 @@ def _render_admin_page( event_rows = "\n".join(_event_row(event) for event in update_events) or """ No update events yet. """ - suffix_help = ( - f"Short names are expanded under {html.escape(settings.hostname_suffix)}." - if settings.hostname_suffix - else "Use a full hostname, for example home.example.net." - ) return _page( "DynDNS Admin", f""" @@ -942,12 +902,11 @@ def _render_admin_page(

DynDNS aktiv

-

Router credentials

-

Create, inspect, and retire router update credentials.

+

Operator console

+

Inspect hostnames, verify domain claims, rotate links, run cleanup, and review router update events.

- {_created_account_panel(service, created_account)} {notice_html or ""}
@@ -966,30 +925,6 @@ def _render_admin_page(
-
-
-
-
-

Generate credentials

-

Router credentials

-

Generated credentials produce the FRITZ!Box fields: Update-URL, Domainnamen, Benutzername, Kennwort.

-

{suffix_help}

-
-
- - - - -
-
-
-
-
diff --git a/tests/test_ddns.py b/tests/test_ddns.py index 8711743..f3c98a4 100644 --- a/tests/test_ddns.py +++ b/tests/test_ddns.py @@ -152,7 +152,7 @@ def test_generated_account_cannot_update_other_hostname(tmp_path: Path) -> None: assert response.status_code == 401 -def test_admin_page_shows_account_form(tmp_path: Path) -> None: +def test_admin_page_shows_operator_views_without_create_form(tmp_path: Path) -> None: database_path = tmp_path / "ddns.sqlite3" store = DdnsStore(database_path) store.create_domain_challenge("example.net") @@ -163,11 +163,11 @@ def test_admin_page_shows_account_form(tmp_path: Path) -> None: assert response.status_code == 200 assert response.headers["cache-control"] == "no-store" - assert "Update-URL" in response.text - assert "Domainnamen" in response.text - assert "Benutzername" in response.text - assert "Kennwort" in response.text + assert "Operator console" in response.text + assert "Generate credentials" not in response.text + assert 'action="/admin/accounts"' not in response.text assert "Scheduled cleanup" in response.text + assert "Active credentials" in response.text assert "Domain claims" in response.text assert "Recent events" in response.text assert "example.net" in response.text @@ -178,9 +178,9 @@ def test_admin_posts_require_csrf(tmp_path: Path) -> None: client = TestClient(app) response = client.post( - "/admin/accounts", + "/admin/cleanup", auth=("admin", "admin"), - data={"hostname": "home.example.net"}, + data={}, ) assert response.status_code == 403