Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new endpoint to list summary objects of permission groups #3064

Merged
merged 4 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1621,3 +1621,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="[email protected]")
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 @@ -173,14 +173,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 @@ -189,7 +191,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 @@ -255,6 +257,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