From 302ddf55e5c440696d6c95c1ae0122880b240260 Mon Sep 17 00:00:00 2001 From: Josema Camacho Date: Fri, 7 Aug 2026 09:43:52 +0200 Subject: [PATCH] feat(api): identify active membership in current user response --- .../tests/integration/test_authentication.py | 25 +++++++++++++++++-- api/src/backend/api/v1/serializers.py | 15 +++++++++++ api/src/backend/api/v1/views.py | 5 +++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/api/src/backend/api/tests/integration/test_authentication.py b/api/src/backend/api/tests/integration/test_authentication.py index 923324564e..926ba3a133 100644 --- a/api/src/backend/api/tests/integration/test_authentication.py +++ b/api/src/backend/api/tests/integration/test_authentication.py @@ -1590,8 +1590,8 @@ class TestAPIKeyMultiTenantWorkflows: tenant1 = tenants_fixture[0] tenant2 = tenants_fixture[1] - Membership.objects.create(user=user, tenant=tenant1) - Membership.objects.create(user=user, tenant=tenant2) + membership1 = Membership.objects.create(user=user, tenant=tenant1) + membership2 = Membership.objects.create(user=user, tenant=tenant2) role1 = Role.objects.create( tenant_id=tenant1.id, @@ -1646,6 +1646,27 @@ class TestAPIKeyMultiTenantWorkflows: assert me_response1.json()["data"]["id"] == str(user.id) assert me_response2.json()["data"]["id"] == str(user.id) + memberships1 = { + item["id"]: item["meta"]["active"] + for item in me_response1.json()["data"]["relationships"]["memberships"][ + "data" + ] + } + memberships2 = { + item["id"]: item["meta"]["active"] + for item in me_response2.json()["data"]["relationships"]["memberships"][ + "data" + ] + } + assert memberships1 == { + str(membership1.id): True, + str(membership2.id): False, + } + assert memberships2 == { + str(membership1.id): False, + str(membership2.id): True, + } + def test_api_key_cannot_access_different_tenant_resources( self, tenants_fixture, aws_provider ): diff --git a/api/src/backend/api/v1/serializers.py b/api/src/backend/api/v1/serializers.py index e777d03fdb..5e1f2fa6d8 100644 --- a/api/src/backend/api/v1/serializers.py +++ b/api/src/backend/api/v1/serializers.py @@ -329,6 +329,15 @@ class TokenSwitchTenantSerializer(BaseSerializerV1): # Users +class ActiveMembershipRelatedField(SerializerMethodResourceRelatedField): + def to_representation(self, value): + representation = super().to_representation(value) + representation["meta"] = { + "active": str(value.tenant_id) == str(self.context["request"].tenant_id), + } + return representation + + class UserSerializer(BaseModelSerializerV1): """ Serializer for the User model. @@ -390,6 +399,12 @@ class UserSerializer(BaseModelSerializerV1): ) +class UserMeSerializer(UserSerializer): + memberships = ActiveMembershipRelatedField( + many=True, read_only=True, source="memberships", method_name="get_memberships" + ) + + class UserIncludeSerializer(UserSerializer): class Meta: model = User diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 71a5faa431..2717b523ac 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -238,6 +238,7 @@ from api.v1.serializers import ( TokenSocialLoginSerializer, TokenSwitchTenantSerializer, UserCreateSerializer, + UserMeSerializer, UserRoleRelationshipSerializer, UserSerializer, UserUpdateSerializer, @@ -1113,6 +1114,8 @@ class UserViewSet(BaseUserViewset): return UserCreateSerializer elif self.action == "partial_update": return UserUpdateSerializer + elif self.action == "me": + return UserMeSerializer else: return UserSerializer @@ -1130,7 +1133,7 @@ class UserViewSet(BaseUserViewset): @action(detail=False, methods=["get"], url_name="me") def me(self, request): user = self.request.user - serializer = UserSerializer(user, context=self.get_serializer_context()) + serializer = self.get_serializer(user) return Response( data=serializer.data, status=status.HTTP_200_OK,