diff --git a/club/tests.py b/club/tests.py index 2ea83d2..f6dce90 100644 --- a/club/tests.py +++ b/club/tests.py @@ -1043,6 +1043,40 @@ class BrandingTests(TestCase): self.assertNotContains(self.login_page("ajax-united.rosterchief.app"), "--color-secondary") +@override_settings( + ROSTERCHIEF_BASE_DOMAIN="rosterchief.app", + ALLOWED_HOSTS=["rosterchief.app", "ajax-united.rosterchief.app", "testserver"], +) +class Custom403PageTests(TestCase): + """Django's default 403 handler picks up templates/403.html automatically -- + branded per tenant (base_template, same as maintenance.html) so a permission + error still looks like the app, not a bare Django error page, and the navbar + (sign out, theme toggle, home link) stays reachable.""" + + def setUp(self): + self.club = Club.objects.create(name="Ajax United", slug="ajax-united") + + def test_a_club_subdomain_403_gets_the_club_skin(self): + member = get_user_model().objects.create_user(email="member-403@example.com", password="pw-secret-123") + self.client.force_login(member) + + response = self.client.get(reverse("management:position_list"), HTTP_HOST="ajax-united.rosterchief.app") + + self.assertEqual(response.status_code, 403) + self.assertContains(response, "Access denied", status_code=403) + self.assertContains(response, "Ajax United", status_code=403) + self.assertContains(response, "Sign out", status_code=403) + + def test_the_base_domain_403_gets_the_platform_skin(self): + self.client.force_login(get_user_model().objects.create_user(email="platform-403@example.com", password="pw-secret-123")) + + response = self.client.get(reverse("controlpanel:dashboard")) + + self.assertEqual(response.status_code, 403) + self.assertContains(response, "Access denied", status_code=403) + self.assertContains(response, "Club & Team Management", status_code=403) + + class ClubBrandingModelTests(TestCase): def test_initials_use_the_first_two_words(self): self.assertEqual(Club(name="Ajax United Football Club").initials, "AU") diff --git a/templates/403.html b/templates/403.html new file mode 100644 index 0000000..6e44cdc --- /dev/null +++ b/templates/403.html @@ -0,0 +1,26 @@ +{% extends base_template %} +{% load i18n lucide %} + +{% comment %} + Django's default 403 handler (django.views.defaults.permission_denied) looks up + this exact filename automatically -- no urls.py wiring needed. Rendered through + the tenant's own skin (base_template, from club.context_processors.branding), + same reasoning as maintenance.html: a club sees its own logo and colours, not a + bare error page, and the navbar (sign out, theme toggle, ...) stays reachable + since {% block main %} is the only thing this page actually replaces. +{% endcomment %} + +{% block head_title %}{% trans "Access denied" %}{% endblock head_title %} + +{% block main %} +
{% trans "You don't have permission to view this page." %}
+ {% lucide "house" size=16 %} {% trans "Go to home" %} +