diff --git a/posthog/api/organization_member.py b/posthog/api/organization_member.py index 5f6b899690ade..cac97636cfb98 100644 --- a/posthog/api/organization_member.py +++ b/posthog/api/organization_member.py @@ -15,6 +15,8 @@ from posthog.models import OrganizationMembership from posthog.models.user import User from posthog.permissions import TimeSensitiveActionPermission, extract_organization +from posthog.utils import posthoganalytics +from posthog.event_usage import groups class OrganizationMemberObjectPermissions(BasePermission): @@ -138,5 +140,21 @@ def safely_get_queryset(self, queryset) -> QuerySet: return queryset def perform_destroy(self, instance: Model): + instance = cast(OrganizationMembership, instance) + requesting_user = cast(User, self.request.user) + removed_user = cast(User, instance.user) + + posthoganalytics.capture( + str(requesting_user.distinct_id), + "organization member removed", + properties={ + "removed_member_id": removed_user.distinct_id, + "removed_by_id": requesting_user.distinct_id, + "organization_id": instance.organization_id, + "organization_name": instance.organization.name, + }, + groups=groups(instance.organization), + ) + instance = cast(OrganizationMembership, instance) instance.user.leave(organization=instance.organization) diff --git a/posthog/api/test/test_organization_members.py b/posthog/api/test/test_organization_members.py index 9c96a3375b13f..fc9dbb667294b 100644 --- a/posthog/api/test/test_organization_members.py +++ b/posthog/api/test/test_organization_members.py @@ -50,8 +50,9 @@ def test_cant_list_members_for_an_alien_organization(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.json(), self.permission_denied_response()) + @patch("posthoganalytics.capture") @patch("posthog.models.user.User.update_billing_organization_users") - def test_delete_organization_member(self, mock_update_billing_organization_users): + def test_delete_organization_member(self, mock_update_billing_organization_users, mock_capture): user = User.objects.create_and_join(self.organization, "test@x.com", None, "X") membership_queryset = OrganizationMembership.objects.filter(user=user, organization=self.organization) self.assertTrue(membership_queryset.exists()) @@ -66,20 +67,44 @@ def test_delete_organization_member(self, mock_update_billing_organization_users self.assertEqual(response.status_code, 204) self.assertFalse(membership_queryset.exists(), False) + mock_capture.assert_called_with( + self.user.distinct_id, # requesting user + "organization member removed", + properties={ + "removed_member_id": user.distinct_id, + "removed_by_id": self.user.distinct_id, + "organization_id": self.organization.id, + "organization_name": self.organization.name, + }, + groups={"instance": "http://localhost:8010", "organization": str(self.organization.id)}, + ) assert mock_update_billing_organization_users.call_count == 2 assert mock_update_billing_organization_users.call_args_list == [ call(self.organization), call(self.organization), ] + @patch("posthoganalytics.capture") @patch("posthog.models.user.User.update_billing_organization_users") - def test_leave_organization(self, mock_update_billing_organization_users): + def test_leave_organization(self, mock_update_billing_organization_users, mock_capture): membership_queryset = OrganizationMembership.objects.filter(user=self.user, organization=self.organization) self.assertEqual(membership_queryset.count(), 1) response = self.client.delete(f"/api/organizations/@current/members/{self.user.uuid}/") self.assertEqual(response.status_code, 204) self.assertEqual(membership_queryset.count(), 0) + mock_capture.assert_called_with( + self.user.distinct_id, + "organization member removed", + properties={ + "removed_member_id": self.user.distinct_id, + "removed_by_id": self.user.distinct_id, + "organization_id": self.organization.id, + "organization_name": self.organization.name, + }, + groups={"instance": "http://localhost:8010", "organization": str(self.organization.id)}, + ) + assert mock_update_billing_organization_users.call_count == 1 assert mock_update_billing_organization_users.call_args_list == [ call(self.organization),