Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions modules/users/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ async def test_dev_accounts_resolved_via_dotenv_fallback(
{"label": "User", "email": "user@example.com", "password": "UserPass1!"},
]

@pytest.mark.anyio
async def test_login_redirect_url_is_dashboard_when_installed(self, anon_client):
"""Regression for #173: with Dashboard installed, prop stays /dashboard/."""
resp = await anon_client.get(
"/users/login",
headers={"X-Inertia": "true", "X-Inertia-Version": "1.0"},
)
assert resp.json()["props"]["login_redirect_url"] == "/dashboard/"


class TestRegisterPage:
@pytest.mark.anyio
Expand Down Expand Up @@ -241,3 +250,28 @@ async def test_roles_payload_returns_id_name_dicts(users_app):
names = [item["name"] for item in payload]
assert "admin" in names
assert "user" in names


@pytest.mark.anyio
async def test_login_redirect_fallback_without_dashboard(users_app):
"""Regression for #173: without Dashboard, redirect falls back to
the first sibling module view_prefix, not ``/`` (which may 404)."""
sm = users_app.state.sm
original = sm.modules
no_dash = tuple(m for m in original if m.meta.name != "Dashboard")
assert len(no_dash) < len(original), "test setup: Dashboard should exist"

settings = users_app.state.users.settings
settings.login_redirect_url = "/dashboard/"
object.__setattr__(sm, "modules", no_dash)
try:
from users.module import UsersModule

mod = UsersModule()
await mod.on_startup(users_app)
url = settings.login_redirect_url
assert url != "/", "must not fall back to / (may 404)"
assert url.startswith("/"), "must be an absolute path"
assert url.endswith("/"), "must have trailing slash"
finally:
object.__setattr__(sm, "modules", original)
19 changes: 15 additions & 4 deletions modules/users/users/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,24 @@ async def on_startup(self, app: FastAPI) -> None:
)
state.oauth_providers = enabled_provider_names(s)

# Auto-fall-back from the default ``/dashboard/`` to ``/`` when the
# Dashboard module isn't installed, so ``--preset minimal`` doesn't
# 404 on login. Operator-set overrides are preserved.
# Auto-fall-back when the default ``/dashboard/`` target is
# unreachable because the Dashboard module isn't installed (e.g.
# ``--preset minimal`` or apps like smpy_gis that omit it).
# Pick the first sibling module that exposes view routes instead
# of hard-coding ``/`` which may itself 404 (#173). Operator-set
# overrides are always preserved.
if s.login_redirect_url == "/dashboard/" and not any(
m.meta.name == "Dashboard" for m in app.state.sm.modules
):
s.login_redirect_url = "/"
first_view = next(
(
m.meta.view_prefix
for m in app.state.sm.modules
if m.meta.view_prefix and m.meta.name != self.meta.name
),
None,
)
s.login_redirect_url = f"{first_view}/" if first_view else "/"

reconfigure_cookie_transport(auth_backend, s)

Expand Down
Loading