|
1 | 1 | import secrets |
2 | 2 | from dataclasses import dataclass |
3 | | -from typing import Literal, cast |
| 3 | +from typing import Literal |
| 4 | + |
| 5 | +from lilya.requests import Request |
4 | 6 |
|
5 | 7 | try: |
6 | 8 | from lilya.middleware import DefineMiddleware |
@@ -95,13 +97,37 @@ def session_middleware(self) -> DefineMiddleware: |
95 | 97 | ) |
96 | 98 |
|
97 | 99 |
|
98 | | -def get_effective_prefix() -> str: |
99 | | - """Compute an absolute dashboard base path, combining ASGI root_path and the |
100 | | - configured dashboard URL prefix. |
| 100 | +def _normalize_prefix(value: str | None) -> str: |
| 101 | + """Ensure a leading slash and remove trailing slash (except for root).""" |
| 102 | + if not value: |
| 103 | + return "/" |
| 104 | + v = value.strip() |
| 105 | + if not v.startswith("/"): |
| 106 | + v = "/" + v |
| 107 | + return v if v == "/" else v.rstrip("/") |
| 108 | + |
101 | 109 |
|
102 | | - Guarantees: |
103 | | - - Always starts with '/' |
104 | | - - No trailing slash (except when the result is exactly '/') |
105 | | - - Never double-appends the configured prefix if it's already in root_path |
| 110 | +def get_effective_prefix(request: Request | None = None) -> str: |
| 111 | + """Compute the effective base URL prefix for the dashboard. |
| 112 | +
|
| 113 | + - If *request* is **None**, return the configured dashboard prefix exactly as before |
| 114 | + (leading '/', no trailing '/', except when it is '/'). This preserves |
| 115 | + backward compatibility with tests that called the old zero-arg function. |
| 116 | + - If *request* is provided, combine ASGI mount ``root_path`` (if any) with the |
| 117 | + configured prefix, avoiding double-prefixing and double slashes. |
106 | 118 | """ |
107 | | - return cast(str, monkay.settings.dashboard_config.dashboard_url_prefix) |
| 119 | + configured_prefix = _normalize_prefix( |
| 120 | + getattr(monkay.settings.dashboard_config, "dashboard_url_prefix", "/") |
| 121 | + ) |
| 122 | + |
| 123 | + # Prefer the configured prefix when it's meaningful (not '/') |
| 124 | + if configured_prefix != "/": |
| 125 | + return configured_prefix |
| 126 | + |
| 127 | + # Only when configured is '/' do we consider the mount root |
| 128 | + if request is not None: |
| 129 | + scope = getattr(request, "scope", {}) or {} |
| 130 | + mount_prefix = _normalize_prefix(scope.get("root_path") or "/") |
| 131 | + return mount_prefix |
| 132 | + |
| 133 | + return "/" |
0 commit comments