You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2022/07/08 19:19:45 UTC

[airavata-django-portal] 04/05: AIRAVATA-3568 Redirect to user profile editor and require completing ext user profile fields

This is an automated email from the ASF dual-hosted git repository.

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

commit 56a8fbc30c744222837844d415b39dc4b7a868b7
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Fri Jul 8 09:54:12 2022 -0400

    AIRAVATA-3568 Redirect to user profile editor and require completing ext user profile fields
---
 .../apps/api/static/django_airavata_api/js/models/User.js      |  3 ++-
 django_airavata/apps/api/view_utils.py                         |  5 +++++
 django_airavata/apps/auth/middleware.py                        | 10 ++++++++--
 django_airavata/apps/auth/serializers.py                       |  7 ++++++-
 .../js/containers/UserProfileContainer.vue                     |  9 +++++++--
 django_airavata/apps/auth/views.py                             |  9 ++++++---
 6 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/User.js b/django_airavata/apps/api/static/django_airavata_api/js/models/User.js
index e4144445..198a927d 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/User.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/User.js
@@ -8,7 +8,8 @@ const FIELDS = [
   "email",
   "pending_email_change",
   "complete",
-  "username_valid"
+  "username_valid",
+  "ext_user_profile_valid",
 ];
 
 export default class User extends BaseModel {
diff --git a/django_airavata/apps/api/view_utils.py b/django_airavata/apps/api/view_utils.py
index ddef7e30..3f06ad00 100644
--- a/django_airavata/apps/api/view_utils.py
+++ b/django_airavata/apps/api/view_utils.py
@@ -221,3 +221,8 @@ class IsInAdminsGroupPermission(permissions.BasePermission):
                     request.is_read_only_gateway_admin)
         else:
             return request.is_gateway_admin
+
+
+class ReadOnly(permissions.BasePermission):
+    def has_permission(self, request, view):
+        return request.method in permissions.SAFE_METHODS
diff --git a/django_airavata/apps/auth/middleware.py b/django_airavata/apps/auth/middleware.py
index 02269563..8e374051 100644
--- a/django_airavata/apps/auth/middleware.py
+++ b/django_airavata/apps/auth/middleware.py
@@ -90,8 +90,14 @@ def user_profile_completeness_check(get_response):
             reverse('django_airavata_auth:user_profile'),
             reverse('django_airavata_auth:logout'),
         ]
-        if (hasattr(request.user, "user_profile") and
-            not request.user.user_profile.is_complete and
+        incomplete_user_profile = (hasattr(request.user, "user_profile") and
+                                   not request.user.user_profile.is_complete)
+        # Exclude admin's from the ext user profile check since they will be
+        # creating/editing the ext user profile fields
+        invalid_ext_user_profile = (not getattr(request, "is_gateway_admin", False) and
+                                    hasattr(request.user, "user_profile") and
+                                    not request.user.user_profile.is_ext_user_profile_valid)
+        if ((incomplete_user_profile or invalid_ext_user_profile) and
             request.path not in allowed_paths and
                 'text/html' in request.META['HTTP_ACCEPT']):
             return redirect('django_airavata_auth:user_profile')
diff --git a/django_airavata/apps/auth/serializers.py b/django_airavata/apps/auth/serializers.py
index c02162ae..06d8def8 100644
--- a/django_airavata/apps/auth/serializers.py
+++ b/django_airavata/apps/auth/serializers.py
@@ -27,11 +27,13 @@ class UserSerializer(serializers.ModelSerializer):
     pending_email_change = serializers.SerializerMethodField()
     complete = serializers.SerializerMethodField()
     username_valid = serializers.SerializerMethodField()
+    ext_user_profile_valid = serializers.SerializerMethodField()
 
     class Meta:
         model = get_user_model()
         fields = ['id', 'username', 'first_name', 'last_name', 'email',
-                  'pending_email_change', 'complete', 'username_valid']
+                  'pending_email_change', 'complete', 'username_valid',
+                  'ext_user_profile_valid']
         read_only_fields = ('username',)
 
     def get_pending_email_change(self, instance):
@@ -49,6 +51,9 @@ class UserSerializer(serializers.ModelSerializer):
     def get_username_valid(self, instance):
         return instance.user_profile.is_username_valid
 
+    def get_ext_user_profile_valid(self, instance):
+        return instance.user_profile.is_ext_user_profile_valid
+
     @atomic
     def update(self, instance, validated_data):
         request = self.context['request']
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/containers/UserProfileContainer.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/containers/UserProfileContainer.vue
index 3e8d101f..c70772c4 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/containers/UserProfileContainer.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/containers/UserProfileContainer.vue
@@ -13,7 +13,7 @@
         In the meantime, please complete as much of your profile as possible.
       </p>
     </b-alert>
-    <b-alert v-else-if="user && !user.complete" show>
+    <b-alert v-else-if="mustComplete" show
       >Please complete your user profile before continuing.</b-alert
     >
     <b-card>
@@ -33,7 +33,7 @@
       <b-button variant="primary" @click="onSave">Save</b-button>
     </b-card>
     <b-link
-      v-if="user && user.complete"
+      v-if="!mustComplete"
       class="text-muted small"
       href="/workspace/dashboard"
       >Return to Dashboard</b-link
@@ -77,6 +77,11 @@ export default {
   computed: {
     ...mapGetters("userProfile", ["user"]),
     ...mapGetters("extendedUserProfile", ["extendedUserProfileFields"]),
+    mustComplete() {
+      return (
+        this.user && (!this.user.complete || !this.user.ext_user_profile_valid)
+      );
+    },
   },
   methods: {
     ...mapActions("userProfile", [
diff --git a/django_airavata/apps/auth/views.py b/django_airavata/apps/auth/views.py
index a2c0775f..0b4fdd93 100644
--- a/django_airavata/apps/auth/views.py
+++ b/django_airavata/apps/auth/views.py
@@ -28,7 +28,10 @@ from rest_framework import mixins, permissions, viewsets
 from rest_framework.decorators import action
 from rest_framework.response import Response
 
-from django_airavata.apps.api.view_utils import IsInAdminsGroupPermission
+from django_airavata.apps.api.view_utils import (
+    IsInAdminsGroupPermission,
+    ReadOnly
+)
 from django_airavata.apps.auth import serializers
 
 from . import forms, iam_admin_client, models, utils
@@ -707,7 +710,7 @@ def get_client_secret(access_token, client_endpoint):
 class ExtendedUserProfileFieldViewset(viewsets.ModelViewSet):
     serializer_class = serializers.ExtendedUserProfileFieldSerializer
     queryset = models.ExtendedUserProfileField.objects.all().order_by('order')
-    permission_classes = [IsInAdminsGroupPermission]
+    permission_classes = [permissions.IsAuthenticated, IsInAdminsGroupPermission | ReadOnly]
 
     def get_queryset(self):
         queryset = super().get_queryset()
@@ -747,7 +750,7 @@ class ExtendedUserProfileValueViewset(mixins.CreateModelMixin,
             if username is not None:
                 queryset = queryset.filter(user_profile__user__username=username)
         else:
-            queryset = user.user_profile.extended_profile.all()
+            queryset = user.user_profile.extended_profile_values.all()
         return queryset
 
     @action(methods=['POST'], detail=False, url_path="save-all")