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 1287b4906 feat(portal): repoint project writes to gRPC + de-Thrift 
workspace prefs (Track D, D3 start) (#174)
1287b4906 is described below

commit 1287b4906cada8ee6fd0a363a9f294fd09a58ab8
Author: Yasith Jayawardana <[email protected]>
AuthorDate: Mon Jun 8 20:26:39 2026 -0400

    feat(portal): repoint project writes to gRPC + de-Thrift workspace prefs 
(Track D, D3 start) (#174)
    
    Begin D3 (writes). Establish the write-direction adapter pattern: the DRF
    serializers were generated from Thrift, so serializer.save() yields a
    Thrift model instance; a new grpc_requests module converts that instance
    into the protobuf request message the facade expects (the write-direction
    mirror of grpc_adapters). proto3 scalars cannot hold None, so optional
    Thrift values coerce to the proto default.
    
    - New grpc_requests.project (Thrift Project -> proto Project).
    - ProjectViewSet.perform_create/perform_update -> research.create_project
      / update_project.
    
    Also migrate WorkspacePreferencesHelper off the Thrift client: its
    _get_most_recent_project / _get_first_group_resource_profile / _check /
    _can_write / _can_read used request.airavata_client (getUserProjects,
    getGroupResourceList, userHasAccess), which hung every project
    create/update because the legacy Thrift server read-times-out. They now
    use the gRPC facade (research.get_user_projects, compute.get_group_
    resource_list, sharing.user_has_access) and proto field names, and the
    None-project case is handled instead of dereferencing None.
    
    Verified: manage.py check clean; live POST create -> 201 (0.1s) and PUT
    update -> 200 (0.02s) against the backend, with the rename confirmed by a
    follow-up GET -- both fast (the Thrift-residue hang is gone).
---
 .../django_airavata/apps/api/grpc_requests.py      | 34 +++++++++++++++
 .../django_airavata/apps/api/helpers.py            | 49 ++++++++++------------
 .../django_airavata/apps/api/views.py              |  9 ++--
 3 files changed, 62 insertions(+), 30 deletions(-)

diff --git a/airavata-django-portal/django_airavata/apps/api/grpc_requests.py 
b/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
new file mode 100644
index 000000000..b9308a904
--- /dev/null
+++ b/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
@@ -0,0 +1,34 @@
+"""Adapters from the Thrift-shaped objects the DRF serializers produce to the
+gRPC protobuf request messages the facade expects.
+
+Track D (D3 writes): the ``apps/api`` serializers were generated from the 
Thrift
+models, so ``serializer.save()`` yields a Thrift model instance (Thrift 
attribute
+names: ``projectID``, ``gatewayId``, ...). These adapters convert that instance
+into the corresponding protobuf message (``project_id``, ``gateway_id``, ...) 
so
+the gRPC facade can send it. They are the write-direction mirror of
+``grpc_adapters`` and are removed once the serializers are made 
protobuf-native.
+
+proto3 scalar fields cannot hold ``None``, so optional Thrift values that may 
be
+``None`` are coerced to the proto default (``''``/``0``/``[]``).
+"""
+
+import importlib
+
+
+def _workspace_pb2():
+    return importlib.import_module(
+        
"airavata_sdk.generated.org.apache.airavata.model.workspace.workspace_pb2")
+
+
+def project(t):
+    """Thrift ``Project`` -> proto ``Project`` request message."""
+    return _workspace_pb2().Project(
+        project_id=t.projectID or '',
+        owner=t.owner or '',
+        gateway_id=t.gatewayId or '',
+        name=t.name or '',
+        description=t.description or '',
+        creation_time=t.creationTime or 0,
+        shared_users=list(t.sharedUsers or []),
+        shared_groups=list(t.sharedGroups or []),
+    )
diff --git a/airavata-django-portal/django_airavata/apps/api/helpers.py 
b/airavata-django-portal/django_airavata/apps/api/helpers.py
index bf5aca74d..ee19990e8 100644
--- a/airavata-django-portal/django_airavata/apps/api/helpers.py
+++ b/airavata-django-portal/django_airavata/apps/api/helpers.py
@@ -1,6 +1,5 @@
 import logging
 
-from airavata.model.group.ttypes import ResourcePermissionType
 from django.conf import settings
 from django.core.exceptions import ObjectDoesNotExist
 
@@ -25,29 +24,29 @@ class WorkspacePreferencesHelper:
         workspace_preferences = models.WorkspacePreferences.create(
             request.user.username)
         most_recent_project = self._get_most_recent_project(request)
-        workspace_preferences.most_recent_project_id = \
-            most_recent_project.projectID
+        workspace_preferences.most_recent_project_id = (
+            most_recent_project.project_id if most_recent_project else None)
         first_grp = \
             self._get_first_group_resource_profile(request)
         workspace_preferences.most_recent_group_resource_profile_id = \
-            first_grp.groupResourceProfileId if first_grp else None
+            first_grp.group_resource_profile_id if first_grp else None
         return workspace_preferences
 
     def _get_most_recent_project(self, request):
         "Return most recent writeable project."
-        projects = request.airavata_client.getUserProjects(
-            request.authz_token, settings.GATEWAY_ID, request.user.username,
-            -1, 0)
+        projects = request.airavata.research.get_user_projects(
+            gateway_id=settings.GATEWAY_ID, user_name=request.user.username,
+            limit=-1, offset=0)
         for project in projects:
-            if self._can_write(request, project.projectID):
+            if self._can_write(request, project.project_id):
                 return project
         return None
 
     def _get_first_group_resource_profile(self, request):
         "Return first accessible group resource profile"
 
-        group_resource_profiles = request.airavata_client.getGroupResourceList(
-            request.authz_token, settings.GATEWAY_ID)
+        group_resource_profiles = \
+            request.airavata.compute.get_group_resource_list()
         if len(group_resource_profiles) > 0:
             return group_resource_profiles[0]
         else:
@@ -59,35 +58,33 @@ class WorkspacePreferencesHelper:
                 not self._can_write(request, prefs.most_recent_project_id)):
             most_recent_project = self._get_most_recent_project(request)
             if most_recent_project is not None:
-                logger.info("_check: updating most_recent_project_id to 
{}".format(most_recent_project.projectID))
-                prefs.most_recent_project_id = most_recent_project.projectID
+                logger.info("_check: updating most_recent_project_id to 
{}".format(most_recent_project.project_id))
+                prefs.most_recent_project_id = most_recent_project.project_id
                 prefs.save()
             else:
                 logger.warning("_check: no writeable projects found, unsetting 
most_recent_project_id")
                 prefs.most_recent_project_id = None
                 prefs.save()
-        group_resource_profiles = request.airavata_client.getGroupResourceList(
-            request.authz_token, settings.GATEWAY_ID)
-        group_resource_profile_ids = list(map(lambda g: 
g.groupResourceProfileId, group_resource_profiles))
+        group_resource_profiles = \
+            request.airavata.compute.get_group_resource_list()
+        group_resource_profile_ids = [g.group_resource_profile_id for g in 
group_resource_profiles]
         if (not prefs.most_recent_group_resource_profile_id or
                 prefs.most_recent_group_resource_profile_id not in 
group_resource_profile_ids):
             first_grp_id = (group_resource_profile_ids[0]
                             if len(group_resource_profile_ids) > 0
                             else None)
-            logger.warn(f"_check: updating "
-                        f"most_recent_group_resource_profile_id to "
-                        f"{first_grp_id}")
+            logger.warning(f"_check: updating "
+                           f"most_recent_group_resource_profile_id to "
+                           f"{first_grp_id}")
             prefs.most_recent_group_resource_profile_id = first_grp_id
             prefs.save()
 
     def _can_write(self, request, entity_id):
-        return request.airavata_client.userHasAccess(
-            request.authz_token,
-            entity_id,
-            ResourcePermissionType.WRITE)
+        return request.airavata.sharing.user_has_access(
+            resource_id=entity_id, user_id=request.user.username,
+            permission_type="WRITE")
 
     def _can_read(self, request, entity_id):
-        return request.airavata_client.userHasAccess(
-            request.authz_token,
-            entity_id,
-            ResourcePermissionType.READ)
+        return request.airavata.sharing.user_has_access(
+            resource_id=entity_id, user_id=request.user.username,
+            permission_type="READ")
diff --git a/airavata-django-portal/django_airavata/apps/api/views.py 
b/airavata-django-portal/django_airavata/apps/api/views.py
index 4e7be0ac2..80c731978 100644
--- a/airavata-django-portal/django_airavata/apps/api/views.py
+++ b/airavata-django-portal/django_airavata/apps/api/views.py
@@ -66,6 +66,7 @@ from django_airavata.apps.auth.models import EmailVerification
 from . import (
     exceptions,
     grpc_adapters,
+    grpc_requests,
     helpers,
     models,
     output_views,
@@ -172,15 +173,15 @@ class ProjectViewSet(APIBackedViewSet):
         project = serializer.save(
             owner=self.username,
             gatewayId=self.gateway_id)
-        project_id = self.request.airavata_client.createProject(
-            self.authz_token, self.gateway_id, project)
+        project_id = self.request.airavata.research.create_project(
+            self.gateway_id, grpc_requests.project(project))
         project.projectID = project_id
         self._update_most_recent_project(project_id)
 
     def perform_update(self, serializer):
         project = serializer.save()
-        self.request.airavata_client.updateProject(
-            self.authz_token, project.projectID, project)
+        self.request.airavata.research.update_project(
+            project.projectID, grpc_requests.project(project))
         self._update_most_recent_project(project.projectID)
 
     @action(detail=False)

Reply via email to