This is an automated email from the ASF dual-hosted git repository.
yasithdev pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airavata-portals.git
The following commit(s) were added to refs/heads/main by this push:
new e86665c49 feat(portal): de-Thrift group management to the gRPC sharing
facade (Track D, D5) (#183)
e86665c49 is described below
commit e86665c492a8510d1e241a09f87f6f4b869b84a1
Author: Yasith Jayawardana <[email protected]>
AuthorDate: Mon Jun 8 22:10:24 2026 -0400
feat(portal): de-Thrift group management to the gRPC sharing facade (Track
D, D5) (#183)
`GroupViewSet` and `GroupSerializer` ran on the Thrift `group_manager`
profile-service client, so listing groups (and every page that loads the
sharing/group data) blocked on the dead Thrift server's read-timeout (~25s).
- `GroupViewSet` get_list/get_instance/perform_create/perform_update/
perform_destroy -> `request.airavata.sharing.gm_*` (gm_get_groups /
gm_get_group
/ gm_create_group / gm_add_users_to_group / gm_remove_users_from_group /
gm_add_group_admins / gm_remove_group_admins / gm_update_group /
gm_delete_group). `_send_users_added_to_group` loads the added user's
profile
via `request.airavata.iam.get_user_profile_by_id`.
- `GroupSerializer.get_isAdmin` -> `sharing.gm_has_admin_access`;
`_gateway_groups` -> `compute.get_gateway_groups` (now also carries
`defaultGatewayUsersGroupId`, which the serializer reads).
- `grpc_adapters.group` (proto GroupModel -> serializer shape) and
`grpc_requests.group` (reverse) added.
- `_gateway_groups_dict` middleware helper extended with the third group id
for
consistency with the cached session dict the serializer reads.
- The `user_added_to_group` signal now carries a protobuf `UserProfile`, so
`email_user_added_to_group` reads `first_name`/`last_name`/`user_id`.
Verified: `manage.py check` green; group adapter round-trips (proto ->
adapter ->
reverse-proto) field-for-field; live `/api/groups/` went from a 25s hang to
200 in ~0.02s. (Creating a group / initializing GatewayGroups isn't
seedable in
the ephemeral dev backend — the serializer's group-flag fields are migrated
1:1
from their Thrift equivalents.)
---
.../django_airavata/apps/api/grpc_adapters.py | 12 +++++++
.../django_airavata/apps/api/grpc_requests.py | 12 +++++++
.../django_airavata/apps/api/serializers.py | 12 ++++---
.../django_airavata/apps/api/views.py | 38 ++++++++++------------
.../django_airavata/apps/auth/middleware.py | 3 +-
.../django_airavata/apps/auth/signals.py | 6 ++--
6 files changed, 53 insertions(+), 30 deletions(-)
diff --git a/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
b/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
index 848b3614f..057c5a081 100644
--- a/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
+++ b/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
@@ -832,6 +832,18 @@ def experiment(pb):
)
+def group(pb):
+ """gRPC ``GroupModel`` -> ``GroupSerializer`` shape."""
+ return SimpleNamespace(
+ id=pb.id,
+ name=pb.name,
+ ownerId=pb.owner_id,
+ description=pb.description or None,
+ members=list(pb.members),
+ admins=list(pb.admins),
+ )
+
+
def notification(pb):
"""gRPC ``Notification`` -> ``NotificationSerializer`` shape."""
return SimpleNamespace(
diff --git a/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
b/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
index b5b40806e..3bc156d4c 100644
--- a/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
+++ b/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
@@ -543,3 +543,15 @@ def group_resource_profile(t):
updated_time=t.updatedTime or 0,
default_credential_store_token=t.defaultCredentialStoreToken or '',
)
+
+
+def group(t):
+ """Thrift ``GroupModel`` -> proto ``GroupModel`` request message."""
+ return _pb2("group.group_manager_pb2").GroupModel(
+ id=t.id or '',
+ name=t.name or '',
+ owner_id=t.ownerId or '',
+ description=t.description or '',
+ members=list(t.members or []),
+ admins=list(t.admins or []),
+ )
diff --git a/airavata-django-portal/django_airavata/apps/api/serializers.py
b/airavata-django-portal/django_airavata/apps/api/serializers.py
index c64471289..38e0630fb 100644
--- a/airavata-django-portal/django_airavata/apps/api/serializers.py
+++ b/airavata-django-portal/django_airavata/apps/api/serializers.py
@@ -232,8 +232,7 @@ class
GroupSerializer(thrift_utils.create_serializer_class(GroupModel)):
def get_isAdmin(self, group):
request = self.context['request']
- return request.profile_service['group_manager'].hasAdminAccess(
- request.authz_token,
+ return request.airavata.sharing.gm_has_admin_access(
group.id,
request.user.username + "@" + settings.GATEWAY_ID)
@@ -263,9 +262,12 @@ class
GroupSerializer(thrift_utils.create_serializer_class(GroupModel)):
if 'GATEWAY_GROUPS' in request.session:
return request.session['GATEWAY_GROUPS']
else:
- gateway_groups = request.airavata_client.getGatewayGroups(
- request.authz_token)
- return copy.deepcopy(gateway_groups.__dict__)
+ gg = request.airavata.compute.get_gateway_groups()
+ return {
+ 'adminsGroupId': gg.admins_group_id,
+ 'readOnlyAdminsGroupId': gg.read_only_admins_group_id,
+ 'defaultGatewayUsersGroupId':
gg.default_gateway_users_group_id,
+ }
class ProjectSerializer(
diff --git a/airavata-django-portal/django_airavata/apps/api/views.py
b/airavata-django-portal/django_airavata/apps/api/views.py
index 1bd7876fc..ca4ddea64 100644
--- a/airavata-django-portal/django_airavata/apps/api/views.py
+++ b/airavata-django-portal/django_airavata/apps/api/views.py
@@ -93,53 +93,49 @@ class GroupViewSet(APIBackedViewSet):
class GroupResultsIterator(APIResultIterator):
def get_results(self, limit=-1, offset=0):
- group_manager = view.request.profile_service['group_manager']
- groups = group_manager.getGroups(view.authz_token)
+ groups = [
+ grpc_adapters.group(g)
+ for g in view.request.airavata.sharing.gm_get_groups()
+ ]
end = offset + limit if limit > 0 else len(groups)
return groups[offset:end] if groups else []
return GroupResultsIterator()
def get_instance(self, lookup_value):
- return self.request.profile_service['group_manager'].getGroup(
- self.authz_token, lookup_value)
+ return grpc_adapters.group(
+ self.request.airavata.sharing.gm_get_group(lookup_value))
def perform_create(self, serializer):
group = serializer.save()
- group_id = self.request.profile_service['group_manager'].createGroup(
- self.authz_token, group)
+ group_id = self.request.airavata.sharing.gm_create_group(
+ grpc_requests.group(group))
group.id = group_id
users_added_to_group = set(group.members) - {group.ownerId}
self._send_users_added_to_group(users_added_to_group, group)
def perform_update(self, serializer):
group = serializer.save()
- group_manager_client = self.request.profile_service['group_manager']
+ sharing = self.request.airavata.sharing
if len(group._added_members) > 0:
- group_manager_client.addUsersToGroup(
- self.authz_token, group._added_members, group.id)
+ sharing.gm_add_users_to_group(group._added_members, group.id)
self._send_users_added_to_group(group._added_members, group)
if len(group._removed_members) > 0:
- group_manager_client.removeUsersFromGroup(
- self.authz_token, group._removed_members, group.id)
+ sharing.gm_remove_users_from_group(group._removed_members,
group.id)
if len(group._added_admins) > 0:
- group_manager_client.addGroupAdmins(
- self.authz_token, group.id, group._added_admins)
+ sharing.gm_add_group_admins(group.id, group._added_admins)
if len(group._removed_admins) > 0:
- group_manager_client.removeGroupAdmins(
- self.authz_token, group.id, group._removed_admins)
- group_manager_client.updateGroup(self.authz_token, group)
+ sharing.gm_remove_group_admins(group.id, group._removed_admins)
+ sharing.gm_update_group(grpc_requests.group(group))
def perform_destroy(self, group):
- group_manager_client = self.request.profile_service['group_manager']
- group_manager_client.deleteGroup(
- self.authz_token, group.id, group.ownerId)
+ self.request.airavata.sharing.gm_delete_group(group.id, group.ownerId)
def _send_users_added_to_group(self, internal_user_ids, group):
for internal_user_id in internal_user_ids:
user_id, gateway_id = internal_user_id.rsplit("@", maxsplit=1)
- user_profile =
self.request.profile_service['user_profile'].getUserProfileById(
- self.authz_token, user_id, gateway_id)
+ user_profile = self.request.airavata.iam.get_user_profile_by_id(
+ user_id, gateway_id)
signals.user_added_to_group.send(
sender=self.__class__,
user=user_profile,
diff --git a/airavata-django-portal/django_airavata/apps/auth/middleware.py
b/airavata-django-portal/django_airavata/apps/auth/middleware.py
index 319e5fa63..7c3f49d90 100644
--- a/airavata-django-portal/django_airavata/apps/auth/middleware.py
+++ b/airavata-django-portal/django_airavata/apps/auth/middleware.py
@@ -34,7 +34,8 @@ def _gateway_groups_dict(request):
"""Fetch the gateway's admin group ids via the gRPC compute facade."""
gg = request.airavata.compute.get_gateway_groups()
return {'adminsGroupId': gg.admins_group_id,
- 'readOnlyAdminsGroupId': gg.read_only_admins_group_id}
+ 'readOnlyAdminsGroupId': gg.read_only_admins_group_id,
+ 'defaultGatewayUsersGroupId': gg.default_gateway_users_group_id}
def set_admin_group_attributes(request, gateway_groups=None):
diff --git a/airavata-django-portal/django_airavata/apps/auth/signals.py
b/airavata-django-portal/django_airavata/apps/auth/signals.py
index 96d180d69..8c208f83a 100644
--- a/airavata-django-portal/django_airavata/apps/auth/signals.py
+++ b/airavata-django-portal/django_airavata/apps/auth/signals.py
@@ -17,9 +17,9 @@ log = logging.getLogger(__name__)
def email_user_added_to_group(sender, user, groups, request, **kwargs):
context = Context({
"email": user.emails[0],
- "first_name": user.firstName,
- "last_name": user.lastName,
- "username": user.userId,
+ "first_name": user.first_name,
+ "last_name": user.last_name,
+ "username": user.user_id,
"portal_title": settings.PORTAL_TITLE,
"dashboard_url": request.build_absolute_uri(
reverse("django_airavata_workspace:dashboard")),