From f04f82b6e2c88bcfa064c8c4511c554c87866264 Mon Sep 17 00:00:00 2001 From: wesleybl Date: Mon, 25 Sep 2023 15:59:51 -0300 Subject: [PATCH] Add can_delete key to the groups endpoint Used to backend hide remove group button if group cannot be removed by currently authenticated user --- src/plone/restapi/services/groups/get.py | 30 +++++++++++++++++-- .../restapi/tests/test_services_groups.py | 10 +++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/plone/restapi/services/groups/get.py b/src/plone/restapi/services/groups/get.py index 0906f56032..c32368dd67 100644 --- a/src/plone/restapi/services/groups/get.py +++ b/src/plone/restapi/services/groups/get.py @@ -1,6 +1,8 @@ +from AccessControl import getSecurityManager from plone.restapi.interfaces import ISerializeToJson from plone.restapi.interfaces import ISerializeToJsonSummary from plone.restapi.services import Service +from Products.CMFCore.permissions import ManagePortal from Products.CMFCore.utils import getToolByName from zExceptions import BadRequest from zope.component import queryMultiAdapter @@ -19,6 +21,10 @@ def __init__(self, context, request): self.params = [] self.query = self.request.form.copy() + @property + def is_zope_manager(self): + return getSecurityManager().checkPermission(ManagePortal, self.context) + def publishTraverse(self, request, name): # Consume any path segments after /@users as parameters self.params.append(name) @@ -46,7 +52,13 @@ def _get_filtered_groups(self, query, limit): results = portal_groups.searchGroups(id=query, max_results=limit) return [portal_groups.getGroupById(group["groupid"]) for group in results] + def can_delete(self, is_zope_manager, roles): + if is_zope_manager: + return True + return "Manager" not in roles + def reply(self): + is_zope_manager = self.is_zope_manager if len(self.query) > 0 and len(self.params) == 0: query = self.query.get("query", "") limit = self.query.get("limit", DEFAULT_SEARCH_RESULTS_LIMIT) @@ -57,7 +69,11 @@ def reply(self): serializer = queryMultiAdapter( (group, self.request), ISerializeToJsonSummary ) - result.append(serializer()) + group_serializer = serializer() + group_serializer["can_delete"] = self.can_delete( + is_zope_manager, group_serializer["roles"] + ) + result.append(group_serializer) return result else: raise BadRequest("Query string supplied is not valid") @@ -66,7 +82,11 @@ def reply(self): result = [] for group in self._get_groups(): serializer = queryMultiAdapter((group, self.request), ISerializeToJson) - result.append(serializer()) + group_serializer = serializer() + group_serializer["can_delete"] = self.can_delete( + is_zope_manager, group_serializer["roles"] + ) + result.append(group_serializer) return result # we retrieve the user on the user id not the username group = self._get_group(self._get_group_id) @@ -74,4 +94,8 @@ def reply(self): self.request.response.setStatus(404) return serializer = queryMultiAdapter((group, self.request), ISerializeToJson) - return serializer() + group_serializer = serializer() + group_serializer["can_delete"] = self.can_delete( + is_zope_manager, group_serializer["roles"] + ) + return group_serializer diff --git a/src/plone/restapi/tests/test_services_groups.py b/src/plone/restapi/tests/test_services_groups.py index 428069d845..6994f2348e 100644 --- a/src/plone/restapi/tests/test_services_groups.py +++ b/src/plone/restapi/tests/test_services_groups.py @@ -84,6 +84,16 @@ def test_list_groups(self): all(["members" in group for group in response.json()]), "Members key found in groups listing", ) + self.assertTrue(ptgroup.get("can_delete")) + + def test_siteadm_groups_can_delete(self): + self.set_siteadm() + response = self.api_session.get("/@groups") + + administrators = [ + x for x in response.json() if x.get("groupname") == "Administrators" + ][0] + self.assertFalse(administrators.get("can_delete")) def test_add_group(self): response = self.api_session.post(