Skip to content

Commit

Permalink
Include invite object in the organization members endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
rajpatel24 committed Jan 7, 2025
1 parent ea9a6bd commit 5394358
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 4 deletions.
38 changes: 37 additions & 1 deletion kobo/apps/organizations/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@


class OrganizationUserSerializer(serializers.ModelSerializer):
invite = serializers.SerializerMethodField()
user = serializers.HyperlinkedRelatedField(
queryset=get_user_model().objects.all(),
lookup_field='username',
Expand Down Expand Up @@ -62,7 +63,8 @@ class Meta:
'role',
'user__has_mfa_enabled',
'date_joined',
'user__is_active'
'user__is_active',
'invite'
]

def get_url(self, obj):
Expand All @@ -76,6 +78,40 @@ def get_url(self, obj):
request=request
)

def get_invite(self, obj):
"""
Get the latest invite for the user if it exists
"""
invite = OrganizationInvitation.objects.filter(
invitee=obj.user
).order_by('-created').first()

if invite:
return OrgMembershipInviteSerializer(
invite, context=self.context
).data
return {}

def to_representation(self, instance):
"""
Handle representation of invite objects.
For users who have been invited to an organization but have not yet
registered, we include the invite object and show user object data as null.
"""
if isinstance(instance, OrganizationInvitation):
invite_serializer = OrgMembershipInviteSerializer(
instance, context=self.context
)
response = {field: None for field in self.Meta.fields}
response.update({
'invite': invite_serializer.data,
})
return response
else:
representation = super().to_representation(instance)
return representation

def update(self, instance, validated_data):
if role := validated_data.get('role', None):
validated_data['is_admin'] = role == 'admin'
Expand Down
69 changes: 66 additions & 3 deletions kobo/apps/organizations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ class OrganizationMemberViewSet(viewsets.ModelViewSet):
> "role": "owner",
> "user__has_mfa_enabled": true,
> "date_joined": "2024-08-11T12:36:32Z",
> "user__is_active": true
> "user__is_active": true,
> "invite": {}
> },
> {
> "url": "http://[kpi]/api/v2/organizations/org_12345/ \
Expand All @@ -305,8 +306,39 @@ class OrganizationMemberViewSet(viewsets.ModelViewSet):
> "role": "admin",
> "user__has_mfa_enabled": false,
> "date_joined": "2024-10-21T06:38:45Z",
> "user__is_active": true
> }
> "user__is_active": true,
> "invite": {
> "url": "http://[kpi]/api/v2/organizations/org_12345/
> invites/83c725f1-3f41-4f72-9657-9e6250e130e1/",
> "invited_by": "http://[kpi]/api/v2/users/raj_patel/",
> "status": "accepted",
> "invitee_role": "admin",
> "created": "2024-10-21T05:38:45Z",
> "modified": "2024-10-21T05:40:45Z",
> "invitee": "john_doe"
> }
> },
> {
> "url": null,
> "user": null,
> "user__username": null,
> "user__email": "null,
> "user__extra_details__name": "null,
> "role": null,
> "user__has_mfa_enabled": null,
> "date_joined": null,
> "user__is_active": null,
> "invite": {
> "url": "http://[kpi]/api/v2/organizations/org_12345/
> invites/83c725f1-3f41-4f72-9657-9e6250e130e1/",
> "invited_by": "http://[kpi]/api/v2/users/raj_patel/",
> "status": "pending",
> "invitee_role": "admin",
> "created": "2025-01-07T09:03:50Z",
> "modified": "2025-01-07T09:03:50Z",
> "invitee": "demo"
> }
> },
> ]
> }
Expand Down Expand Up @@ -429,6 +461,37 @@ def get_queryset(self):
),
has_mfa_enabled=Exists(mfa_subquery)
)

if self.action == 'list':
# Include invited users who are not yet part of this organization
invitation_queryset = OrganizationInvitation.objects.filter(
organization_id=organization_id, status='pending'
)

# Queryset for invited users who have registered
registered_invitees = OrganizationUser.objects.filter(
user_id__in=invitation_queryset.values('invitee_id')
).select_related('user__extra_details').annotate(
role=Case(
When(Exists(owner_subquery), then=Value('owner')),
When(is_admin=True, then=Value('admin')),
default=Value('member'),
output_field=CharField()
),
has_mfa_enabled=Exists(mfa_subquery)
)

# Queryset for invited users who have not yet registered
unregistered_invitees = invitation_queryset.filter(
invitee_id__isnull=True
)

combined_queryset = (
list(queryset) +
list(registered_invitees) +
list(unregistered_invitees)
)
return combined_queryset
return queryset


Expand Down

0 comments on commit 5394358

Please sign in to comment.