Media was unreachable from either portal, which is why the certificate button on the buyer compliance page returned page-not-found and no document row had anything to click. The cause was structural: the portal and ops hosts proxy location / to the app with a path prefix, so a stored /media/... URL arrives as /portal/media/... and matches no route. Add a download view per portal behind the same role gate as the page that links to it — buyer-visible documents and published certificates for buyers, anything the ops list shows for operations — resolving the stored path safely under MEDIA_ROOT so a traversal or an absolute path is refused. Point the seven templates that list files at the new routes. Also add a portal-wide render sweep: nothing in the suite was fetching the ops or portal pages, so a view could lose its template_name and 500 in front of a user with every test still green.
59 lines
1.9 KiB
Python
59 lines
1.9 KiB
Python
"""Every portal page must actually render.
|
|
|
|
Nothing in the suite was rendering the ops or portal HTML pages, which is how a
|
|
view can lose a line — a `template_name`, say — and 500 in front of a user while
|
|
68 tests still pass. These sweeps fetch each read-only page with an empty
|
|
database, so they cover the empty-state branches as well as the templates.
|
|
"""
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import Client, TestCase
|
|
|
|
User = get_user_model()
|
|
|
|
OPS_ROUTES = [
|
|
"/ops/",
|
|
"/ops/batches/",
|
|
"/ops/qc/",
|
|
"/ops/qc/verify/",
|
|
"/ops/coa/",
|
|
"/ops/shipments/",
|
|
"/ops/capa/",
|
|
"/ops/documents/",
|
|
"/ops/esg/",
|
|
"/ops/eudr/",
|
|
"/ops/help/",
|
|
]
|
|
|
|
PORTAL_ROUTES = [
|
|
"/portal/",
|
|
"/portal/batches/",
|
|
"/portal/documents/",
|
|
"/portal/compliance/",
|
|
"/portal/subscription/",
|
|
"/portal/help/",
|
|
]
|
|
|
|
|
|
class PortalPagesRenderTests(TestCase):
|
|
def make_user(self, email, role):
|
|
return User.objects.create_user(
|
|
email=email, password="pass1234", role=role,
|
|
full_name=email.split("@")[0], is_staff=True,
|
|
)
|
|
|
|
def sweep(self, user, routes, host):
|
|
client = Client(SERVER_NAME=host)
|
|
client.force_login(user)
|
|
for route in routes:
|
|
with self.subTest(route=route):
|
|
response = client.get(route)
|
|
body = response.content
|
|
self.assertEqual(response.status_code, 200, f"{route} did not render")
|
|
for marker in (b"Traceback", b"TemplateDoesNotExist", b"Django Version"):
|
|
self.assertNotIn(marker, body, f"{route} rendered an error page")
|
|
|
|
def test_ops_pages_render(self):
|
|
self.sweep(self.make_user("ops-sweep@ixg.local", "ops"), OPS_ROUTES, "ops.ixgltd.com")
|
|
|
|
def test_buyer_pages_render(self):
|
|
self.sweep(self.make_user("buyer-sweep@ixg.local", "buyer"), PORTAL_ROUTES, "portal.ixgltd.com")
|