diff --git a/roundtable/core/settings.py b/roundtable/core/settings.py index e924565..c6ae158 100644 --- a/roundtable/core/settings.py +++ b/roundtable/core/settings.py @@ -202,3 +202,27 @@ def load_settings_sync(db_url: str) -> dict[str, Any]: if key.startswith("plugin.") and key not in out: out[key] = value return out + + +# ───────────────────────────────────────────────────────────────────────────── +# External URL helper +# ───────────────────────────────────────────────────────────────────────────── + +def public_base_url(request) -> str: + """Return the externally-reachable base URL for this Roundtable instance. + + Prefers the admin-configured 'general.public_base_url' setting (cached in + current_app.config['PUBLIC_BASE_URL']) when set. Falls back to + request.host_url stripped of its trailing slash, so unconfigured + single-hostname installs keep working with zero config. + + Use this — NOT request.host_url — anywhere you build a URL that will be + consumed by something outside this Quart request: install scripts, share + links, alert notifications, webhook callbacks. The Host header is not + reliable behind proxies or on multi-hostname deployments. + """ + from quart import current_app + configured = (current_app.config.get("PUBLIC_BASE_URL") or "").strip() + if configured: + return configured.rstrip("/") + return request.host_url.rstrip("/")