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 46d6e11dc refactor(portal): make ApplicationModuleSerializer 
proto-native (Track D) (#194)
46d6e11dc is described below

commit 46d6e11dc43701f9dbdb4971724879c7ffc31575
Author: Yasith Jayawardana <[email protected]>
AuthorDate: Tue Jun 9 03:31:47 2026 -0400

    refactor(portal): make ApplicationModuleSerializer proto-native (Track D) 
(#194)
    
    Rewrite ApplicationModuleSerializer to read the gRPC ApplicationModule 
protobuf
    directly and emit the same Thrift-named JSON keys, keeping the REST contract
    byte-for-byte unchanged.
    
    - save() returns a proto ApplicationModule the view passes straight to the 
facade.
    - Repoint ApplicationModuleViewSet 
(list/instance/create/update/destroy/list_all)
      and FullExperimentViewSet's nested module to pass protobuf through 
directly,
      dropping the grpc_adapters.application_module / 
grpc_requests.application_module
      roundtrip.
    - Remove those adapter funcs + the Thrift ApplicationModule import.
    
    Validated byte-for-byte (full/empty) vs the old adapter+serializer path; 
write
    path (create/update) produces an equivalent proto. manage.py check green; 
api
    test failures unchanged vs origin/main.
---
 .../django_airavata/apps/api/grpc_adapters.py      | 10 -----
 .../django_airavata/apps/api/grpc_requests.py      | 10 -----
 .../django_airavata/apps/api/serializers.py        | 49 ++++++++++++++++++----
 .../django_airavata/apps/api/views.py              | 28 +++++--------
 4 files changed, 51 insertions(+), 46 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 0c54f8570..72bede0c8 100644
--- a/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
+++ b/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
@@ -256,16 +256,6 @@ def proto_summary_type(thrift_summary_type):
         _ThriftSummaryType(thrift_summary_type).name)
 
 
-def application_module(pb):
-    """gRPC ``ApplicationModule`` protobuf -> ``ApplicationModuleSerializer`` 
shape."""
-    return SimpleNamespace(
-        appModuleId=pb.app_module_id,
-        appModuleName=pb.app_module_name,
-        appModuleVersion=pb.app_module_version,
-        appModuleDescription=pb.app_module_description,
-    )
-
-
 def experiment_summary(pb):
     """gRPC ``ExperimentSummaryModel`` protobuf -> 
``ExperimentSummarySerializer`` 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 292ed88b3..f596dd65e 100644
--- a/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
+++ b/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
@@ -80,16 +80,6 @@ def password_credential(gateway_id, portal_user_name, 
login_user_name,
     )
 
 
-def application_module(t):
-    """Thrift ``ApplicationModule`` -> proto ``ApplicationModule``."""
-    return 
_pb2("appcatalog.appdeployment.app_deployment_pb2").ApplicationModule(
-        app_module_id=t.appModuleId or '',
-        app_module_name=t.appModuleName or '',
-        app_module_version=t.appModuleVersion or '',
-        app_module_description=t.appModuleDescription or '',
-    )
-
-
 def _input_data_object(t):
     io = _pb2("application.io.application_io_pb2")
     return io.InputDataObjectType(
diff --git a/airavata-django-portal/django_airavata/apps/api/serializers.py 
b/airavata-django-portal/django_airavata/apps/api/serializers.py
index ddc270c00..14b6cd3a8 100644
--- a/airavata-django-portal/django_airavata/apps/api/serializers.py
+++ b/airavata-django-portal/django_airavata/apps/api/serializers.py
@@ -9,7 +9,6 @@ from airavata.model.application.io.ttypes import DataType
 
 from airavata.model.appcatalog.appdeployment.ttypes import (
     ApplicationDeploymentDescription,
-    ApplicationModule,
     CommandObject,
     SetEnvPaths
 )
@@ -355,26 +354,58 @@ class ProjectSerializer(serializers.Serializer):
         return project.owner == request.user.username
 
 
-class ApplicationModuleSerializer(
-        thrift_utils.create_serializer_class(ApplicationModule)):
+class ApplicationModuleSerializer(serializers.Serializer):
+    """Proto-native serializer for the gRPC ``ApplicationModule`` message.
+
+    Reads the protobuf directly and emits the historical Thrift-named JSON 
keys.
+    ``save()`` returns a proto ``ApplicationModule`` the view passes to the 
facade.
+    """
+
+    appModuleId = serializers.CharField(source='app_module_id', read_only=True)
+    appModuleName = serializers.CharField(source='app_module_name')
+    appModuleVersion = serializers.CharField(
+        source='app_module_version', allow_blank=True, allow_null=True,
+        required=False)
+    appModuleDescription = serializers.CharField(
+        source='app_module_description', allow_blank=True, allow_null=True,
+        required=False)
     url = FullyEncodedHyperlinkedIdentityField(
         view_name='django_airavata_api:application-detail',
-        lookup_field='appModuleId',
+        lookup_field='app_module_id',
         lookup_url_kwarg='app_module_id')
     applicationInterface = FullyEncodedHyperlinkedIdentityField(
         view_name='django_airavata_api:application-application-interface',
-        lookup_field='appModuleId',
+        lookup_field='app_module_id',
         lookup_url_kwarg='app_module_id')
     applicationDeployments = FullyEncodedHyperlinkedIdentityField(
         view_name='django_airavata_api:application-application-deployments',
-        lookup_field='appModuleId',
+        lookup_field='app_module_id',
         lookup_url_kwarg='app_module_id')
     userHasWriteAccess = serializers.SerializerMethodField()
 
-    class Meta:
-        required = ('appModuleName',)
+    def create(self, validated_data):
+        from 
airavata_sdk.generated.org.apache.airavata.model.appcatalog.appdeployment 
import (  # noqa: E501
+            app_deployment_pb2,
+        )
+        return app_deployment_pb2.ApplicationModule(
+            app_module_name=validated_data.get('app_module_name', '') or '',
+            app_module_version=validated_data.get('app_module_version', '') or 
'',
+            app_module_description=validated_data.get(
+                'app_module_description', '') or '',
+        )
 
-    def get_userHasWriteAccess(self, appDeployment):
+    def update(self, instance, validated_data):
+        if 'app_module_name' in validated_data:
+            instance.app_module_name = validated_data['app_module_name'] or ''
+        if 'app_module_version' in validated_data:
+            instance.app_module_version = (
+                validated_data['app_module_version'] or '')
+        if 'app_module_description' in validated_data:
+            instance.app_module_description = (
+                validated_data['app_module_description'] or '')
+        return instance
+
+    def get_userHasWriteAccess(self, appModule):
         request = self.context['request']
         return request.is_gateway_admin
 
diff --git a/airavata-django-portal/django_airavata/apps/api/views.py 
b/airavata-django-portal/django_airavata/apps/api/views.py
index 5df6fc950..b59337bd4 100644
--- a/airavata-django-portal/django_airavata/apps/api/views.py
+++ b/airavata-django-portal/django_airavata/apps/api/views.py
@@ -434,7 +434,7 @@ class FullExperimentViewSet(mixins.RetrieveModelMixin,
         try:
             if applicationInterface is not None:
                 appModuleId = applicationInterface.applicationModules[0]
-                applicationModule = grpc_adapters.application_module(
+                applicationModule = (
                     self.request.airavata.research.get_application_module(
                         appModuleId))
             else:
@@ -484,30 +484,27 @@ class ApplicationModuleViewSet(APIBackedViewSet):
     lookup_field = 'app_module_id'
 
     def get_list(self):
-        return [
-            grpc_adapters.application_module(m)
-            for m in self.request.airavata.research.get_accessible_app_modules(
-                gateway_id=self.gateway_id)
-        ]
+        return list(self.request.airavata.research.get_accessible_app_modules(
+            gateway_id=self.gateway_id))
 
     def get_instance(self, lookup_value):
-        return grpc_adapters.application_module(
-            
self.request.airavata.research.get_application_module(lookup_value))
+        return self.request.airavata.research.get_application_module(
+            lookup_value)
 
     def perform_create(self, serializer):
         app_module = serializer.save()
         app_module_id = 
self.request.airavata.research.register_application_module(
-            self.gateway_id, grpc_requests.application_module(app_module))
-        app_module.appModuleId = app_module_id
+            self.gateway_id, app_module)
+        app_module.app_module_id = app_module_id
 
     def perform_update(self, serializer):
         app_module = serializer.save()
         self.request.airavata.research.update_application_module(
-            app_module.appModuleId, 
grpc_requests.application_module(app_module))
+            app_module.app_module_id, app_module)
 
     def perform_destroy(self, instance):
         self.request.airavata.research.delete_application_module(
-            instance.appModuleId)
+            instance.app_module_id)
 
     @action(detail=True)
     def application_interface(self, request, app_module_id):
@@ -587,11 +584,8 @@ class ApplicationModuleViewSet(APIBackedViewSet):
 
     @action(detail=False)
     def list_all(self, request, format=None):
-        all_modules = [
-            grpc_adapters.application_module(m)
-            for m in self.request.airavata.research.get_all_app_modules(
-                gateway_id=self.gateway_id)
-        ]
+        all_modules = list(self.request.airavata.research.get_all_app_modules(
+            gateway_id=self.gateway_id))
         serializer = self.serializer_class(
             all_modules, many=True, context={'request': request})
         return Response(serializer.data)

Reply via email to