From c3f770ef0ed6a2568e4a13e32d85354cd44e130d Mon Sep 17 00:00:00 2001 From: Sage Abdullah Date: Wed, 5 Jun 2024 15:35:55 +0100 Subject: [PATCH] Link to inspect view from index view if user only has view permission This also allows the user to access the index view with only 'view' permission --- .../tests/viewsets/test_model_viewset.py | 47 ++++++++++++++++++- wagtail/admin/views/generic/models.py | 16 +++++-- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/wagtail/admin/tests/viewsets/test_model_viewset.py b/wagtail/admin/tests/viewsets/test_model_viewset.py index 78ba116793..f0030191d6 100644 --- a/wagtail/admin/tests/viewsets/test_model_viewset.py +++ b/wagtail/admin/tests/viewsets/test_model_viewset.py @@ -1483,13 +1483,56 @@ class TestListingButtons(WagtailTestUtils, TestCase): ) self.user.user_permissions.add(admin_permission, add_permission) + response = self.client.get(reverse("fctoy-alt2:index")) + self.assertEqual(response.status_code, 200) + soup = self.get_soup(response.content) + title_wrapper = soup.select_one("#listing-results td.title .title-wrapper") + self.assertIsNotNone(title_wrapper) + + # fctoy-alt2 doesn't have inspect view enabled, so the title cell should + # not link anywhere + self.assertIsNone(title_wrapper.select_one("a")) + self.assertEqual(title_wrapper.text.strip(), str(self.object)) + + # There should be no edit link at all on the page + self.assertNotContains( + response, + reverse("fctoy-alt2:edit", args=[quote(self.object.pk)]), + ) + + def test_title_cell_links_to_inspect_view_when_no_edit_permission(self): + self.user.is_superuser = False + self.user.save() + admin_permission = Permission.objects.get( + content_type__app_label="wagtailadmin", + codename="access_admin", + ) + view_permission = Permission.objects.get( + content_type__app_label=self.object._meta.app_label, + codename=get_permission_codename("view", self.object._meta), + ) + self.user.user_permissions.add(admin_permission, view_permission) + response = self.client.get(reverse("feature_complete_toy:index")) self.assertEqual(response.status_code, 200) soup = self.get_soup(response.content) title_wrapper = soup.select_one("#listing-results td.title .title-wrapper") self.assertIsNotNone(title_wrapper) - self.assertIsNone(title_wrapper.select_one("a")) - self.assertEqual(title_wrapper.text.strip(), self.object.name) + link = title_wrapper.select_one("a") + self.assertIsNotNone(link) + self.assertEqual(link.text.strip(), self.object.name) + self.assertEqual( + link.get("href"), + reverse("feature_complete_toy:inspect", args=[quote(self.object.pk)]), + ) + + # Should contain the inspect link twice: + # once in the title cell and once in the dropdown + self.assertContains( + response, + reverse("feature_complete_toy:inspect", args=[quote(self.object.pk)]), + count=2, + ) # There should be no edit link at all on the page self.assertNotContains( diff --git a/wagtail/admin/views/generic/models.py b/wagtail/admin/views/generic/models.py index 848f2b4d6b..a1736d05ea 100644 --- a/wagtail/admin/views/generic/models.py +++ b/wagtail/admin/views/generic/models.py @@ -73,7 +73,7 @@ class IndexView( copy_url_name = None inspect_url_name = None delete_url_name = None - any_permission_required = ["add", "change", "delete"] + any_permission_required = ["add", "change", "delete", "view"] search_fields = None search_backend_name = "default" is_searchable = None @@ -249,15 +249,21 @@ class IndexView( def _get_title_column(self, field_name, column_class=TitleColumn, **kwargs): column_class = self._get_title_column_class(column_class) + + def get_url(instance): + if edit_url := self.get_edit_url(instance): + return edit_url + return self.get_inspect_url(instance) + if not self.model: return column_class( "name", label=gettext_lazy("Name"), accessor=str, - get_url=self.get_edit_url, + get_url=get_url, ) return self._get_custom_column( - field_name, column_class, get_url=self.get_edit_url, **kwargs + field_name, column_class, get_url=get_url, **kwargs ) def _get_custom_column(self, field_name, column_class=Column, **kwargs): @@ -328,7 +334,9 @@ class IndexView( return reverse(self.copy_url_name, args=(quote(instance.pk),)) def get_inspect_url(self, instance): - if self.inspect_url_name: + if self.inspect_url_name and self.user_has_any_permission( + {"add", "change", "delete", "view"} + ): return reverse(self.inspect_url_name, args=(quote(instance.pk),)) def get_delete_url(self, instance):