airavata-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From machris...@apache.org
Subject [airavata-django-portal] 02/02: AIRAVATA-2835 SharedEntity viewset and serializer
Date Tue, 03 Jul 2018 21:58:30 GMT
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 7b8b34358b72d2a49131d6202d8493841cc15d7c
Author: Marcus Christie <machrist@iu.edu>
AuthorDate: Tue Jul 3 17:58:12 2018 -0400

    AIRAVATA-2835 SharedEntity viewset and serializer
---
 django_airavata/apps/api/serializers.py | 105 ++++++++++++++++++++++++++++-
 django_airavata/apps/api/urls.py        |   2 +
 django_airavata/apps/api/views.py       | 115 ++++++++++++++++++++++++++++++++
 3 files changed, 221 insertions(+), 1 deletion(-)

diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index a6b986a..1aeba7a 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -24,7 +24,7 @@ from airavata.model.data.replica.ttypes import (DataProductModel,
                                                 DataReplicaLocationModel)
 from airavata.model.experiment.ttypes import (ExperimentModel,
                                               ExperimentSummaryModel)
-from airavata.model.group.ttypes import GroupModel
+from airavata.model.group.ttypes import GroupModel, ResourcePermissionType
 from airavata.model.job.ttypes import JobModel
 from airavata.model.status.ttypes import ExperimentStatus
 from airavata.model.user.ttypes import UserProfile
@@ -357,6 +357,7 @@ class ExperimentSerializer(
     full_experiment = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:full-experiment-detail',
lookup_field='experimentId', lookup_url_kwarg='experiment_id')
     project = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:project-detail',
lookup_field='projectId', lookup_url_kwarg='project_id')
     jobs = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:experiment-jobs',
lookup_field='experimentId', lookup_url_kwarg='experiment_id')
+    shared_entity = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:shared-entity-detail',
lookup_field='experimentId', lookup_url_kwarg='entity_id')
     userName = GatewayUsernameDefaultField()
     gatewayId = GatewayIdDefaultField()
     creationTime = UTCPosixTimestampDateTimeField(allow_null=True)
@@ -456,3 +457,105 @@ class SharedGroups(serializers.Serializer):
     def update(self, instance, validated_data):
         instance["groupList"]=validated_data["groupList"]
         return instance
+
+
+class UserPermissionSerializer(serializers.Serializer):
+    user = UserProfileSerializer()
+    permissionType = serializers.IntegerField()
+
+
+class GroupPermissionSerializer(serializers.Serializer):
+    group = GroupSerializer()
+    permissionType = serializers.IntegerField()
+
+
+class SharedEntitySerializer(serializers.Serializer):
+
+    entityId = serializers.CharField(read_only=True)
+    users = UserPermissionSerializer(many=True)
+    groups = GroupPermissionSerializer(many=True)
+    owner = UserProfileSerializer(read_only=True)
+    isOwner = serializers.SerializerMethodField()
+
+    def create(self, validated_data):
+        raise Exception("Not implemented")
+
+    def update(self, instance, validated_data):
+        # Compute lists of ids to grant/revoke READ/WRITE
+        existing_user_permissions = {user.user.userId: user.permissionType
+                                     for user in instance.users}
+        new_user_permissions = {user.user.userId: user.permissionType
+                                for user in validated_data.users}
+
+        (user_grant_read_permission, user_grant_write_permission,
+         user_revoke_read_permission, user_revoke_write_permission) = \
+            self._compute_all_revokes_and_grants(existing_user_permissions,
+                                                 new_user_permissions)
+
+        existing_group_permissions = {group.group.groupId: group.permissionType
+                                      for group in instance.groups}
+        new_group_permissions = {group.group.groupId: group.permissionType
+                                 for group in validated_data.groups}
+
+        (group_grant_read_permission, group_grant_write_permission,
+         group_revoke_read_permission, group_revoke_write_permission) = \
+            self._compute_all_revokes_and_grants(existing_group_permissions,
+                                                 new_group_permissions)
+
+        instance._user_grant_read_permission = user_grant_read_permission
+        instance._user_grant_write_permission = user_grant_write_permission
+        instance._user_revoke_read_permission = user_revoke_read_permission
+        instance._user_revoke_write_permission = user_revoke_write_permission
+        instance._group_grant_read_permission = group_grant_read_permission
+        instance._group_grant_write_permission = group_grant_write_permission
+        instance._group_revoke_read_permission = group_revoke_read_permission
+        instance._group_revoke_write_permission = group_revoke_write_permission
+        return instance
+
+    def _compute_all_revokes_and_grants(self, existing_permissions,
+                                        new_permissions):
+        grant_read_permission = []
+        grant_write_permission = []
+        revoke_read_permission = []
+        revoke_write_permission = []
+        # Union the two sets of user/group ids
+        all_ids = existing_permissions.keys() | new_permissions.keys()
+        for id in all_ids:
+            revokes, grants = self._compute_revokes_and_grants(
+                existing_permissions.get(id),
+                new_permissions.get(id)
+            )
+            if ResourcePermissionType.READ in revokes:
+                revoke_read_permission.append(id)
+            if ResourcePermissionType.WRITE in revokes:
+                revoke_write_permission.append(id)
+            if ResourcePermissionType.READ in grants:
+                grant_read_permission.append(id)
+            if ResourcePermissionType.WRITE in grants:
+                grant_write_permission.append(id)
+        return (grant_read_permission, grant_write_permission,
+                revoke_read_permission, revoke_write_permission)
+
+    def _compute_revokes_and_grants(self, current_permission=None,
+                                    new_permission=None):
+        read_permissions = set(ResourcePermissionType.READ)
+        write_permissions = set(ResourcePermissionType.READ,
+                                ResourcePermissionType.WRITE)
+        current_permissions_set = set()
+        new_permissions_set = set()
+        if current_permission == ResourcePermissionType.READ:
+            current_permissions_set = read_permissions
+        elif current_permission == ResourcePermissionType.WRITE:
+            current_permissions_set = write_permissions
+        if new_permission == ResourcePermissionType.READ:
+            new_permissions_set = read_permissions
+        elif new_permission == ResourcePermissionType.WRITE:
+            new_permissions_set = write_permissions
+
+        # return tuple: permissions to revoke and permissions to grant
+        return (current_permissions_set - new_permissions_set,
+                new_permissions_set - current_permissions_set)
+
+    def get_isOwner(self, shared_entity):
+        request = self.context['request']
+        return shared_entity['owner'].userId == request.user.username
diff --git a/django_airavata/apps/api/urls.py b/django_airavata/apps/api/urls.py
index 8320846..8a2134c 100644
--- a/django_airavata/apps/api/urls.py
+++ b/django_airavata/apps/api/urls.py
@@ -22,6 +22,8 @@ router.register(r'user-profiles', views.UserProfileViewSet,
 router.register(r'group-resource-profiles', views.GroupResourceProfileViewSet,
                 base_name='group-resource-profile')
 router.register(r'shared/group/entities',views.SharedEntityGroups,base_name="shared_entities_with_groups")
+router.register(r'shared-entities', views.SharedEntityViewSet,
+                base_name='shared-entity')
 
 app_name = 'django_airavata_api'
 urlpatterns = [
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index c361a3a..7df39bb 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -21,6 +21,7 @@ from airavata.model.application.io.ttypes import DataType
 from airavata.model.credential.store.ttypes import CredentialOwnerType, SummaryType, CredentialSummary
 from airavata.model.data.movement.ttypes import GridFTPDataMovement, LOCALDataMovement, SCPDataMovement,
\
     UnicoreDataMovement
+from airavata.model.group.ttypes import ResourcePermissionType
 from django_airavata.apps.api.view_utils import GenericAPIBackedViewSet, APIBackedViewSet,
APIResultIterator, \
     APIResultPagination
 from . import datastore
@@ -741,3 +742,117 @@ class SharedEntityGroups(APIBackedViewSet):
             group_list = map(lambda val: val.groupId, group_list)
         groups['groupList'] = group_list
         return groups
+
+
+class SharedEntityViewSet(mixins.RetrieveModelMixin,
+                          mixins.UpdateModelMixin,
+                          GenericAPIBackedViewSet):
+    serializer_class = serializers.SharedEntitySerializer
+    lookup_field = 'entity_id'
+
+    def get_instance(self, lookup_value):
+        users = {}
+        # Load accessible users in order of permission precedence: users that
+        # have WRITE permission should also have READ
+        users.update(self._load_accessible_users(
+            lookup_value, ResourcePermissionType.READ))
+        users.update(self._load_accessible_users(
+            lookup_value, ResourcePermissionType.WRITE))
+        owner_ids = self._load_accessible_users(lookup_value,
+                                                ResourcePermissionType.OWNER)
+        # Assume that there is one and only one owner
+        owner_id = list(owner_ids.keys())[0]
+        # Remove owner from the users list
+        del users[owner_id]
+        user_list = []
+        for user_id in users:
+            user_list.append({'user': self._load_user_profile(user_id),
+                              'permissionType': users[user_id]})
+        groups = {}
+        groups.update(self._load_accessible_groups(
+            lookup_value, ResourcePermissionType.READ))
+        groups.update(self._load_accessible_groups(
+            lookup_value, ResourcePermissionType.WRITE))
+        group_list = []
+        for group_id in groups:
+            group_list.append({'group': self._load_group(group_id),
+                               'permissionType': groups[group_id]})
+        return {'entityId': lookup_value,
+                'users': user_list,
+                'groups': group_list,
+                'owner': self._load_user_profile(owner_id)}
+
+    def _load_accessible_users(self, entity_id, permission_type):
+        users = self.request.airavata_client.getAllAccessibleUsers(self.authz_token, entity_id,
permission_type)
+        return {user_id: permission_type for user_id in users}
+
+    def _load_user_profile(self, user_id):
+        user_profile_client = self.request.profile_service['user_profile']
+        username = user_id[0:user_id.rindex('@')]
+        return user_profile_client.getUserProfileById(self.authz_token,
+                                                      username,
+                                                      settings.GATEWAY_ID)
+
+    def _load_accessible_groups(self, entity_id, permission_type):
+        groups = self.request.airavata_client.getAllAccessibleGroups(self.authz_token, entity_id,
permission_type)
+        return {group_id: permission_type for group_id in groups}
+
+    def _load_group(self, group_id):
+        group_manager_client = self.request.profile_service['group_manager']
+        return group_manager_client.getGroup(self.authz_token, group_id)
+
+    def perform_update(self, serializer):
+        shared_entity = serializer.save()
+        entity_id = shared_entity.entityId
+        if len(shared_entity._user_grant_read_permission) > 0:
+            self._share_with_users(
+                entity_id, ResourcePermissionType.READ,
+                shared_entity._user_grant_read_permission)
+        if len(shared_entity._user_grant_write_permission) > 0:
+            self._share_with_users(
+                entity_id, ResourcePermissionType.WRITE,
+                shared_entity._user_grant_write_permission)
+        if len(shared_entity._user_revoke_read_permission) > 0:
+            self._revoke_from_users(
+                entity_id, ResourcePermissionType.READ,
+                shared_entity._user_revoke_read_permission)
+        if len(shared_entity._user_revoke_write_permission) > 0:
+            self._revoke_from_users(
+                entity_id, ResourcePermissionType.WRITE,
+                shared_entity._user_revoke_write_permission)
+        if len(shared_entity._group_grant_read_permission) > 0:
+            self._share_with_groups(
+                entity_id, ResourcePermissionType.READ,
+                shared_entity._group_grant_read_permission)
+        if len(shared_entity._group_grant_write_permission) > 0:
+            self._share_with_groups(
+                entity_id, ResourcePermissionType.WRITE,
+                shared_entity._group_grant_write_permission)
+        if len(shared_entity._group_revoke_read_permission) > 0:
+            self._revoke_from_groups(
+                entity_id, ResourcePermissionType.READ,
+                shared_entity._group_revoke_read_permission)
+        if len(shared_entity._group_revoke_write_permission) > 0:
+            self._revoke_from_groups(
+                entity_id, ResourcePermissionType.WRITE,
+                shared_entity._group_revoke_write_permission)
+
+    def _share_with_users(self, entity_id, permission_type, user_ids):
+        self.request.airavata_client.shareResourceWithUsers(
+            self.authz_token, entity_id,
+            {user_id: permission_type for user_id in user_ids})
+
+    def _revoke_from_users(self, entity_id, permission_type, user_ids):
+        self.request.airavata_client.revokeSharingOfResourceFromUsers(
+            self.authz_token, entity_id,
+            {user_id: permission_type for user_id in user_ids})
+
+    def _share_with_groups(self, entity_id, permission_type, group_ids):
+        self.request.airavata_client.shareResourceWithGroups(
+            self.authz_token, entity_id,
+            {group_id: permission_type for group_id in group_ids})
+
+    def _revoke_from_groups(self, entity_id, permission_type, group_ids):
+        self.request.airavata_client.revokeSharingOfResourceFromGroups(
+            self.authz_token, entity_id,
+            {group_id: permission_type for group_id in group_ids})


Mime
View raw message