From c059b6408622748082f6c89e98f5b72ed0b8a335 Mon Sep 17 00:00:00 2001 From: Gagan Deep Date: Tue, 18 Jun 2024 20:48:44 +0530 Subject: [PATCH] [fix] Admin actions require model permissions --- openwisp_network_topology/admin.py | 14 +++-- openwisp_network_topology/tests/test_admin.py | 52 ++++++++++++++++++- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/openwisp_network_topology/admin.py b/openwisp_network_topology/admin.py index 1b81ad46..87174706 100644 --- a/openwisp_network_topology/admin.py +++ b/openwisp_network_topology/admin.py @@ -166,6 +166,10 @@ def _message(self, request, rows, suffix, level=messages.SUCCESS): ) self.message_user(request, '{0} {1}'.format(prefix, suffix), level=level) + @admin.action( + description=_('Update selected topologies (FETCH strategy only)'), + permissions=['change'], + ) def update_selected(self, request, queryset): items = list(queryset) failed = [] @@ -196,22 +200,16 @@ def update_selected(self, request, queryset): message = _("ignored (not using FETCH strategy)") self._message(request, total_ignored, message, level=messages.WARNING) - update_selected.short_description = _( - 'Update selected topologies (FETCH strategy only)' - ) - + @admin.action(description=_('Publish selected topologies'), permissions=['change']) def publish_selected(self, request, queryset): rows_updated = queryset.update(published=True) self._message(request, rows_updated, _('successfully published')) - publish_selected.short_description = _('Publish selected topologies') - + @admin.action(description=_('Unpublish selected items'), permissions=['change']) def unpublish_selected(self, request, queryset): rows_updated = queryset.update(published=False) self._message(request, rows_updated, _('successfully unpublished')) - unpublish_selected.short_description = _('Unpublish selected items') - def visualize_view(self, request, pk): graph_url, history_url = self.get_graph_urls(request, pk) context = self.admin_site.each_context(request) diff --git a/openwisp_network_topology/tests/test_admin.py b/openwisp_network_topology/tests/test_admin.py index bd95dff5..7a03ad02 100644 --- a/openwisp_network_topology/tests/test_admin.py +++ b/openwisp_network_topology/tests/test_admin.py @@ -1,4 +1,5 @@ import re +from unittest.mock import patch import responses import swapper @@ -8,7 +9,7 @@ from django.urls import reverse from openwisp_users.tests.utils import TestMultitenantAdminMixin, TestOrganizationMixin -from openwisp_utils.tests import capture_any_output +from openwisp_utils.tests import AdminActionPermTestMixin, capture_any_output from ..admin import TopologyAdmin from .utils import CreateGraphObjectsMixin, CreateOrgMixin, LoadMixin @@ -280,7 +281,11 @@ def test_admin_menu_groups(self): class TestMultitenantAdmin( - CreateGraphObjectsMixin, TestMultitenantAdminMixin, TestOrganizationMixin, TestCase + AdminActionPermTestMixin, + CreateGraphObjectsMixin, + TestMultitenantAdminMixin, + TestOrganizationMixin, + TestCase, ): app_label = 'topology' topology_model = Topology @@ -435,3 +440,46 @@ def test_link_topology_autocomplete_filter(self): visible=[data['t1'].label, t_special.label], hidden=[data['t2'].label, data['t3_inactive'].label], ) + + @patch.object(Topology, 'update') + def test_update_selected_action_perms(self, *args): + org = self._get_org() + user = self._create_user(is_staff=True) + self._create_org_user(user=user, organization=org, is_admin=True) + topology = self._create_topology(organization=org) + self._test_action_permission( + path=reverse(f'admin:{self.app_label}_topology_changelist'), + action='update_selected', + user=user, + obj=topology, + message='1 topology was successfully updated', + required_perms=['change'], + ) + + def test_publish_selected_action_perms(self): + org = self._get_org() + user = self._create_user(is_staff=True) + self._create_org_user(user=user, organization=org, is_admin=True) + topology = self._create_topology(organization=org) + self._test_action_permission( + path=reverse(f'admin:{self.app_label}_topology_changelist'), + action='publish_selected', + user=user, + obj=topology, + message='1 topology was successfully published', + required_perms=['change'], + ) + + def test_unpublish_selected_action_perms(self): + org = self._get_org() + user = self._create_user(is_staff=True) + self._create_org_user(user=user, organization=org, is_admin=True) + topology = self._create_topology(organization=org) + self._test_action_permission( + path=reverse(f'admin:{self.app_label}_topology_changelist'), + action='unpublish_selected', + user=user, + obj=topology, + message='1 topology was successfully unpublished', + required_perms=['change'], + )