From a438b3fb371c101cafbc53d1f3ddbce26a72917d Mon Sep 17 00:00:00 2001 From: Cloorc Date: Thu, 25 Jun 2026 18:16:24 +0800 Subject: [PATCH] fix: include role in organisation invite list/retrieve responses InviteSerializer (used on create) exposes the invite's organisation role, but InviteListSerializer (used for the list and retrieve actions of /organisations/{id}/invites/) omits it. As a result an invite created with role USER is returned with no role at all when listed, so API consumers and the dashboard fall back to a default (ADMIN), making the pending invite appear to have a different role than it was created with. Add role to InviteListSerializer.fields so list/retrieve responses report the persisted role, and cover it with unit tests. Signed-off-by: Cloorc --- api/organisations/invites/serializers.py | 9 ++++- .../invites/test_unit_invites_views.py | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/api/organisations/invites/serializers.py b/api/organisations/invites/serializers.py index 44dfdde7ecfb..530a9bf3a9df 100644 --- a/api/organisations/invites/serializers.py +++ b/api/organisations/invites/serializers.py @@ -16,4 +16,11 @@ class InviteListSerializer(serializers.ModelSerializer): # type: ignore[type-ar class Meta: model = Invite - fields = ("id", "email", "date_created", "invited_by", "permission_groups") + fields = ( + "id", + "email", + "date_created", + "invited_by", + "permission_groups", + "role", + ) diff --git a/api/tests/unit/organisations/invites/test_unit_invites_views.py b/api/tests/unit/organisations/invites/test_unit_invites_views.py index 2f2547f065e6..614f0159d8d4 100644 --- a/api/tests/unit/organisations/invites/test_unit_invites_views.py +++ b/api/tests/unit/organisations/invites/test_unit_invites_views.py @@ -303,6 +303,41 @@ def test_retrieve_invite__valid_invite__returns_200( # type: ignore[no-untyped- response = admin_client.get(url) # Then assert response.status_code == status.HTTP_200_OK + assert response.json()["role"] == invite.role + + +def test_list_invites__returns_role_for_each_invite( + admin_client: APIClient, + organisation: Organisation, +) -> None: + # Given + Invite.objects.create( + organisation=organisation, + email="admin-invite@example.com", + role=OrganisationRole.ADMIN.name, + ) + Invite.objects.create( + organisation=organisation, + email="user-invite@example.com", + role=OrganisationRole.USER.name, + ) + url = reverse( + "api-v1:organisations:organisation-invites-list", + args=[organisation.id], + ) + + # When + response = admin_client.get(url) + + # Then + assert response.status_code == status.HTTP_200_OK + roles_by_email = { + invite["email"]: invite["role"] for invite in response.json()["results"] + } + assert roles_by_email == { + "admin-invite@example.com": OrganisationRole.ADMIN.name, + "user-invite@example.com": OrganisationRole.USER.name, + } def test_delete_invite__valid_invite__returns_204( # type: ignore[no-untyped-def]