from __future__ import annotations from ..services.ddns import DdnsService from ..settings import DdnsSettings from .components import ( _copy_menu, _copy_row, _event_label, _fritzbox_fields, _manual_update_commands, _manual_update_panel, _secret_notice, ) from .html_utils import SafeHtml, attr, escape, trusted from .layout import _page, _top_nav from .templates_public_sections import _created_hostname_panel def _render_management_page( service: DdnsService, settings: DdnsSettings, management_slug: str, account: dict[str, str | int | None], csrf_token: str, message: str | None = None, created_account: dict[str, str] | None = None, request_ip: str | None = None, ) -> str: account_for_url = { "hostname": str(account["hostname"]), "update_slug": str(account["update_slug"]), "management_slug": management_slug, } update_url = service.fritz_update_url(account_for_url) hostname = escape(account["hostname"]) ipv4 = escape(account.get("ipv4") or "-") ipv6 = escape(account.get("ipv6") or "-") updated = escape(account.get("updated_at") or "Never") fritzbox_fields = _fritzbox_fields(update_url, hostname) cname_record = f"your-subdomain.example.com. CNAME {hostname}." manual_commands = _manual_update_commands(update_url, request_ip) history_rows = "\n".join(_user_event_row(event) for event in service.store.list_update_events_for_hostname(str(account["hostname"]), 10)) or """ No router updates yet. """ message_html = _management_message(message) rotated_links = _created_hostname_panel(service, created_account, request_ip) dashboard_password_panel = _dashboard_password_panel(management_slug, csrf_token, bool(account.get("dashboard_password_hash"))) return _page( "KarlDNS management", trusted(f"""
{_top_nav()}

Dashboard

{hostname}

This private link can manage this hostname. Keep it safe.

Home
{message_html} {rotated_links}

Router settings

Router update settings

Use this Update-URL in your router or script. Optional: point another DNS name at this hostname with a CNAME.

{_secret_notice()}
{_copy_menu("Copy setup values", [("Router fields", fritzbox_fields), ("CNAME", cname_record)])}
{_copy_row("Update-URL:", update_url, "Secret")} {_copy_row("Domainnamen:", hostname, "Public")} {_copy_row("CNAME target:", hostname, "Public")}
{_manual_update_panel(manual_commands)}

Actions

Replace router update URL

Create a new update URL. Update your router after changing it.

{dashboard_password_panel}

Current address

Status

IPv4{ipv4}
IPv6{ipv6}
Updated{updated}

History

Router updates

Recent IP changes and failed updates for this hostname.

{history_rows}
TimeStatusIPv4IPv6CountDetail

Delete

Delete hostname

This removes the hostname and DNS records. The router update URL will stop working.

"""), extra_styles=trusted(''), ) def _render_pending_management_page( settings: DdnsSettings, management_slug: str, account: dict[str, str | int | None], csrf_token: str, message: str | None = None, ) -> str: hostname = escape(account["hostname"]) message_html = _management_message(message) cleanup_hours = settings.cleanup_pending_account_hours cleanup_text = f"{cleanup_hours} hours" if cleanup_hours != 24 else "24 hours" return _page( "Register hostname", trusted(f"""
{_top_nav()}

Pending setup

{hostname}

Register this hostname after you have copied the private values. Unregistered setups are cleaned up after {escape(cleanup_text)}.

{message_html}

Lost the first page? Create a new hostname. Private URLs are shown only once.

"""), ) def _management_message(message: str | None) -> SafeHtml: if not message: return trusted("") return trusted( f"""
{escape(message)}
""" ) def _dashboard_password_panel(management_slug: str, csrf_token: str, password_enabled: bool) -> SafeHtml: password_status = "Enabled" if password_enabled else "Not enabled" password_action = "Change password" if password_enabled else "Set password" remove_form = "" if password_enabled: remove_form = f"""
""" current_password_field = "" if password_enabled: current_password_field = """
""" return trusted( f"""

Dashboard password

Password protection

Status: {escape(password_status)}. This password protects only this dashboard. Router updates still work.

{current_password_field}
{remove_form}
""" ) def _render_management_unlock_page( management_slug: str, account: dict[str, str | int | None], csrf_token: str, message: str | None = None, ) -> str: hostname = escape(account["hostname"]) message_html = "" if message: message_html = f'' return _page( "Unlock KarlDNS management", trusted(f"""
{_top_nav()}

Dashboard locked

{hostname}

Enter the dashboard password for this hostname.

{message_html}
"""), ) def _user_event_row(event: dict[str, str | int | None]) -> str: created = escape(event.get("created_at") or "-") status = escape(_event_label(event.get("status"))) ipv4 = escape(event.get("ipv4") or "-") ipv6 = escape(event.get("ipv6") or "-") count = escape(event.get("count") or 1) detail = escape(event.get("detail") or "-") return f"{created}{status}{ipv4}{ipv6}{count}{detail}"