auth urls: mount apps.lyric.urls under /dashboard/ to mirror gameboard/epic & billboard/drama convention
- core/urls.py: replace `path('lyric/', …)` with second `path('dashboard/', include('apps.lyric.urls'))` alongside existing dashboard mount; no path-name collision (lyric paths: send_login_email, login, logout, dev-login/<key>/)
- IT test URL strings flipped /lyric/ → /dashboard/ (test_views.py)
- setup_sig_session + setup_sea_session pre-auth URL builders updated
- CLAUDE.md doc note updated
- Templates use unnamespaced `{% url 'logout' %}` / `{% url 'send_login_email' %}` so they auto-resolve; no template edits needed
- /admin/lyric/user/ admin URL untouched (driven by app_label, not URL conf)
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -73,7 +73,7 @@ python src/manage.py setup_sig_session --base-url http://localhost:8000
|
||||
python src/manage.py setup_sig_session --room <uuid>
|
||||
```
|
||||
|
||||
Fixed gamers: `founder@test.io` (discoman), `amigo@test.io`, `bud@test.io`, `pal@test.io`, `dude@test.io`, `bro@test.io` — all superusers with Earthman deck. URLs use `/lyric/dev-login/<session_key>/` pre-auth pattern.
|
||||
Fixed gamers: `founder@test.io` (discoman), `amigo@test.io`, `bud@test.io`, `pal@test.io`, `dude@test.io`, `bro@test.io` — all superusers with Earthman deck. URLs use `/dashboard/dev-login/<session_key>/` pre-auth pattern.
|
||||
|
||||
## CI/CD + Hosting
|
||||
- Git remote: `git@gitea:discoman/python-tdd.git` (port 222, key `~/.ssh/gitea_keys/id_ed25519_python-tdd`)
|
||||
|
||||
@@ -9,13 +9,13 @@ from apps.lyric.models import LoginToken
|
||||
class SendLoginEmailViewTest(TestCase):
|
||||
def test_redirects_to_home_page(self, mock_delay):
|
||||
response = self.client.post(
|
||||
"/lyric/send_login_email", data={"email": "discoman@example.com"}
|
||||
"/dashboard/send_login_email", data={"email": "discoman@example.com"}
|
||||
)
|
||||
self.assertRedirects(response, "/")
|
||||
|
||||
def test_sends_mail_to_address_from_post(self, mock_delay):
|
||||
self.client.post(
|
||||
"/lyric/send_login_email", data={"email": "discoman@example.com"}
|
||||
"/dashboard/send_login_email", data={"email": "discoman@example.com"}
|
||||
)
|
||||
|
||||
self.assertEqual(mock_delay.called, True)
|
||||
@@ -23,7 +23,7 @@ class SendLoginEmailViewTest(TestCase):
|
||||
|
||||
def test_adds_success_message(self, mock_delay):
|
||||
response = self.client.post(
|
||||
"/lyric/send_login_email",
|
||||
"/dashboard/send_login_email",
|
||||
data={"email": "discoman@example.com"},
|
||||
follow=True
|
||||
)
|
||||
@@ -37,23 +37,23 @@ class SendLoginEmailViewTest(TestCase):
|
||||
|
||||
def test_creates_login_token_associated_with_email(self, mock_delay):
|
||||
self.client.post(
|
||||
"/lyric/send_login_email", data={"email": "discoman@example.com"}
|
||||
"/dashboard/send_login_email", data={"email": "discoman@example.com"}
|
||||
)
|
||||
login_token = LoginToken.objects.get()
|
||||
self.assertEqual(login_token.email, "discoman@example.com")
|
||||
|
||||
def test_sends_link_to_login_using_login_token_uid(self, mock_delay):
|
||||
self.client.post(
|
||||
"/lyric/send_login_email", data={"email": "discoman@example.com"}
|
||||
"/dashboard/send_login_email", data={"email": "discoman@example.com"}
|
||||
)
|
||||
|
||||
login_token = LoginToken.objects.get()
|
||||
expected_url = f"http://testserver/lyric/login?token={login_token.uid}"
|
||||
expected_url = f"http://testserver/dashboard/login?token={login_token.uid}"
|
||||
self.assertEqual(mock_delay.call_args.args[1], expected_url)
|
||||
|
||||
class LoginViewTest(TestCase):
|
||||
def test_redirects_to_home_page(self):
|
||||
response = self.client.get("/lyric/login?token=abc123")
|
||||
response = self.client.get("/dashboard/login?token=abc123")
|
||||
self.assertRedirects(response, "/")
|
||||
|
||||
def test_logs_in_if_given_valid_login_token(self):
|
||||
@@ -61,14 +61,14 @@ class LoginViewTest(TestCase):
|
||||
self.assertEqual(anon_user.is_authenticated, False)
|
||||
|
||||
login_token = LoginToken.objects.create(email="discoman@example.com")
|
||||
self.client.get(f"/lyric/login?token={login_token.uid}", follow=True)
|
||||
self.client.get(f"/dashboard/login?token={login_token.uid}", follow=True)
|
||||
|
||||
user = auth.get_user(self.client)
|
||||
self.assertEqual(user.is_authenticated, True)
|
||||
self.assertEqual(user.email, "discoman@example.com")
|
||||
|
||||
def test_shows_login_error_if_login_token_invalid(self):
|
||||
response = self.client.get("/lyric/login?token=invalid-token", follow=True)
|
||||
response = self.client.get("/dashboard/login?token=invalid-token", follow=True)
|
||||
user = auth.get_user(self.client)
|
||||
self.assertEqual(user.is_authenticated, False)
|
||||
message = list(response.context["messages"])[0]
|
||||
@@ -80,7 +80,7 @@ class LoginViewTest(TestCase):
|
||||
|
||||
@mock.patch("apps.lyric.views.auth")
|
||||
def test_calls_authenticate_with_uid_from_get_request(self, mock_auth):
|
||||
self.client.get("/lyric/login?token=abc123")
|
||||
self.client.get("/dashboard/login?token=abc123")
|
||||
self.assertEqual(
|
||||
mock_auth.authenticate.call_args,
|
||||
mock.call(uid="abc123")
|
||||
@@ -91,7 +91,7 @@ class DevLoginViewTest(TestCase):
|
||||
def test_happy_path_sets_session_cookie_and_redirects(self):
|
||||
from django.test import override_settings
|
||||
with override_settings(DEBUG=True):
|
||||
response = self.client.get("/lyric/dev-login/testsessionkey/")
|
||||
response = self.client.get("/dashboard/dev-login/testsessionkey/")
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response["Location"], "/")
|
||||
self.assertIn("sessionid", response.cookies)
|
||||
@@ -99,11 +99,11 @@ class DevLoginViewTest(TestCase):
|
||||
def test_next_param_sets_redirect_target(self):
|
||||
from django.test import override_settings
|
||||
with override_settings(DEBUG=True):
|
||||
response = self.client.get("/lyric/dev-login/key/?next=/gameboard/")
|
||||
response = self.client.get("/dashboard/dev-login/key/?next=/gameboard/")
|
||||
self.assertEqual(response["Location"], "/gameboard/")
|
||||
|
||||
def test_returns_404_when_debug_is_false(self):
|
||||
from django.test import override_settings
|
||||
with override_settings(DEBUG=False):
|
||||
response = self.client.get("/lyric/dev-login/key/")
|
||||
response = self.client.get("/dashboard/dev-login/key/")
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
@@ -11,7 +11,7 @@ urlpatterns = [
|
||||
path('', dash_views.home_page, name='home'),
|
||||
path('api/', include('apps.api.urls')),
|
||||
path('dashboard/', include('apps.dashboard.urls')),
|
||||
path('lyric/', include('apps.lyric.urls')),
|
||||
path('dashboard/', include('apps.lyric.urls')),
|
||||
path('gameboard/', include('apps.gameboard.urls')),
|
||||
path('gameboard/', include('apps.epic.urls')),
|
||||
path('billboard/', include('apps.billboard.urls')),
|
||||
|
||||
@@ -104,7 +104,7 @@ class Command(BaseCommand):
|
||||
# ── URL ──────────────────────────────────────────────────────────────
|
||||
room_path = f"/gameboard/room/{room.pk}/"
|
||||
session_key = _make_session(user)
|
||||
url = f"{base_url}/lyric/dev-login/{session_key}/?next={room_path}"
|
||||
url = f"{base_url}/dashboard/dev-login/{session_key}/?next={room_path}"
|
||||
|
||||
self.stdout.write(f"\nRoom: {base_url}{room_path}")
|
||||
self.stdout.write(f"Gamer: {GAMER_EMAIL} (PC / levity / earthman)")
|
||||
|
||||
@@ -120,7 +120,7 @@ class Command(BaseCommand):
|
||||
|
||||
for (email, container), user, role in zip(GAMERS, users, ROLES):
|
||||
session_key = _make_session(user)
|
||||
url = f"{base_url}/lyric/dev-login/{session_key}/?next={room_path}"
|
||||
url = f"{base_url}/dashboard/dev-login/{session_key}/?next={room_path}"
|
||||
self.stdout.write(f"{container:<12} {email:<22} {role:<6} {url}")
|
||||
|
||||
self.stdout.write("")
|
||||
|
||||
Reference in New Issue
Block a user