diff --git a/arkindex/users/api.py b/arkindex/users/api.py index cd66a9b7abc7aae27f0f672b01832743fee73cd1..371567ec0fb8b87900ea7991330ab92ce504b9f2 100644 --- a/arkindex/users/api.py +++ b/arkindex/users/api.py @@ -595,7 +595,12 @@ class MembershipDetails(RetrieveUpdateDestroyAPIView): # The request user does not have a read acces raise NotFound - if self.request.method not in SAFE_METHODS and access_level < Role.Admin.value: + if ( + self.request.method not in SAFE_METHODS + # Allow an user to remove its own membership + and membership.user_id != self.request.user.id + and access_level < Role.Admin.value + ): raise PermissionDenied( detail='Only admins of the target membership group can perform this action.' ) diff --git a/arkindex/users/tests/test_generic_memberships.py b/arkindex/users/tests/test_generic_memberships.py index 338b5308370c7be463925267d234f014e97f2d0e..b533255e11c4c3c30f811e2f1c87cd94a0e6c967 100644 --- a/arkindex/users/tests/test_generic_memberships.py +++ b/arkindex/users/tests/test_generic_memberships.py @@ -701,3 +701,28 @@ class TestMembership(FixtureAPITestCase): response = self.client.delete(reverse('api:membership-details', kwargs={'pk': str(group_membership.id)})) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(admin_group.rights.count(), 0) + + def test_delete_non_admin(self): + """ + Non admin members are not allowed to remove another member + """ + self.client.force_login(self.non_admin) + with self.assertNumQueries(6): + response = self.client.delete(reverse('api:membership-details', kwargs={'pk': str(self.membership.id)})) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertDictEqual( + response.json(), + {'detail': 'Only admins of the target membership group can perform this action.'} + ) + + def test_delete_own_membership(self): + """ + Any member is able to remove its own membership + """ + non_admin_membership = self.group.memberships.get(user=self.non_admin) + self.client.force_login(self.non_admin) + with self.assertNumQueries(6): + response = self.client.delete(reverse('api:membership-details', kwargs={'pk': str(non_admin_membership.id)})) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + with self.assertRaises(Right.DoesNotExist): + non_admin_membership.refresh_from_db()