Skip to content

Commit

Permalink
feat: add new endpoint to list summary objects of permission groups (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewelwell authored Nov 30, 2023
1 parent 661c42f commit 2880ef5
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 7 deletions.
2 changes: 1 addition & 1 deletion api/organisations/permissions/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def has_permission(self, request, view):
return False

return (
view.action in ("list", "my_groups")
view.action in ("list", "my_groups", "summaries")
and request.user.belongs_to(organisation.id)
or view.detail is True # delegate to has_object_permission / get_queryset
or request.user.has_organisation_permission(
Expand Down
55 changes: 55 additions & 0 deletions api/tests/unit/organisations/test_unit_organisations_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1640,3 +1640,58 @@ def test_list_organisations_shows_dunning(
_subscription = response.data["results"][0]["subscription"]
assert _subscription["id"] == subscription.id
assert _subscription["billing_status"] == SUBSCRIPTION_BILLING_STATUS_DUNNING


def test_list_group_summaries(
organisation: Organisation, staff_client: APIClient
) -> None:
# Given
user_permission_group_1 = UserPermissionGroup.objects.create(
organisation=organisation, name="group1"
)
user_permission_group_2 = UserPermissionGroup.objects.create(
organisation=organisation, name="group2"
)

url = reverse(
"api-v1:organisations:organisation-groups-summaries", args=[organisation.id]
)

# When
response = staff_client.get(url)

# Then
assert response.status_code == status.HTTP_200_OK

response_json = response.json()
assert response_json["count"] == 2
assert response_json["results"][0] == {
"id": user_permission_group_1.id,
"name": user_permission_group_1.name,
}
assert response_json["results"][1] == {
"id": user_permission_group_2.id,
"name": user_permission_group_2.name,
}


def test_user_from_another_organisation_cannot_list_group_summaries(
organisation: Organisation, api_client: APIClient
) -> None:
# Given
UserPermissionGroup.objects.create(organisation=organisation, name="group1")

organisation_2 = Organisation.objects.create(name="org2")
org2_user = FFAdminUser.objects.create(email="org2user@example.com")
org2_user.add_organisation(organisation_2)
api_client.force_authenticate(org2_user)

url = reverse(
"api-v1:organisations:organisation-groups-summaries", args=[organisation.id]
)

# When
response = api_client.get(url)

# Then
assert response.status_code == status.HTTP_403_FORBIDDEN
21 changes: 15 additions & 6 deletions api/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,16 @@ def get_queryset(self):
organisation = Organisation.objects.get(id=organisation_pk)

qs = UserPermissionGroup.objects.filter(organisation=organisation)
if not self.request.user.has_organisation_permission(
organisation, MANAGE_USER_GROUPS
if (
self.action != "summaries"
and not self.request.user.has_organisation_permission(
organisation, MANAGE_USER_GROUPS
)
):
# my_groups and summaries return a very cut down set of data, we can safely allow all users
# of the groups / organisation to retrieve them in this case, otherwise they must be a group admin.
q = Q(userpermissiongroupmembership__ffadminuser=self.request.user)
if self.action != "my_groups":
# my-groups returns a very cut down set of data, we can safely allow all users
# of the groups to retrieve them in this case, otherwise they must be a group
# admin.
q = q & Q(userpermissiongroupmembership__group_admin=True)
qs = qs.filter(q)

Expand All @@ -192,7 +194,7 @@ def get_queryset(self):
def get_serializer_class(self):
if self.action == "retrieve":
return UserPermissionGroupSerializerDetail
elif self.action == "my_groups":
elif self.action in ("my_groups", "summaries"):
return UserPermissionGroupSummarySerializer
return ListUserPermissionGroupSerializer

Expand Down Expand Up @@ -258,6 +260,13 @@ def my_groups(self, request: Request, organisation_pk: int) -> Response:
"""
return self.list(request, organisation_pk)

@action(detail=False, methods=["GET"])
def summaries(self, request: Request, organisation_pk: int) -> Response:
"""
Returns a list of summary group objects for all groups in the organisation.
"""
return self.list(request, organisation_pk)


@api_view(["POST"])
@permission_classes([IsAuthenticated, NestedIsOrganisationAdminPermission])
Expand Down

3 comments on commit 2880ef5

@vercel
Copy link

@vercel vercel bot commented on 2880ef5 Nov 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 2880ef5 Nov 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./docs

docs.flagsmith.com
docs-git-main-flagsmith.vercel.app
docs-flagsmith.vercel.app
docs.bullet-train.io

@vercel
Copy link

@vercel vercel bot commented on 2880ef5 Nov 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.