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 2021/06/09 17:03:29 UTC

[airavata-django-portal] 01/02: Merge branch 'AIRAVATA-3319-handle-missing-name-and-email-attributes-from-cilo' into develop

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

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

commit fef84db1dcc91a9b88d0f2c243ce8099157edf69
Merge: 304016b 125fd07
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Wed Jun 9 12:48:23 2021 -0400

    Merge branch 'AIRAVATA-3319-handle-missing-name-and-email-attributes-from-cilo' into develop

 .gitignore                                         |    1 +
 .../api/static/django_airavata_api/js/index.js     |    1 +
 .../static/django_airavata_api/js/models/User.js   |    9 +
 .../django_airavata_api/js/service_config.js       |   24 +
 django_airavata/apps/auth/.prettierignore          |    2 +
 django_airavata/apps/auth/babel.config.js          |    3 +
 django_airavata/apps/auth/backends.py              |   71 +-
 .../auth/migrations/0007_auto_20200917_1610.py     |   43 +
 .../auth/migrations/0008_auto_20210422_1838.py     |   59 +
 django_airavata/apps/auth/models.py                |   41 +
 django_airavata/apps/auth/package.json             |   56 +
 django_airavata/apps/auth/serializers.py           |   78 +
 .../js/components/UserProfileEditor.vue            |  100 +
 .../js/containers/UserProfileContainer.vue         |   89 +
 .../django_airavata_auth/js/entry-user-profile.js  |    8 +
 .../auth/templates/django_airavata_auth/base.html  |   23 +
 django_airavata/apps/auth/urls.py                  |    7 +-
 django_airavata/apps/auth/views.py                 |   78 +-
 django_airavata/apps/auth/vue.config.js            |   80 +
 django_airavata/apps/auth/yarn.lock                | 8717 ++++++++++++++++++++
 django_airavata/settings.py                        |   12 +
 .../static/common/js/errors/vuelidateHelpers.js    |    4 +
 django_airavata/static/common/js/index.js          |    4 +-
 django_airavata/templates/base.html                |    8 +-
 docs/dev/new_django_app.md                         |    6 +-
 25 files changed, 9499 insertions(+), 25 deletions(-)

diff --cc django_airavata/apps/auth/urls.py
index 51bb043,887ed74..5d1e631
--- a/django_airavata/apps/auth/urls.py
+++ b/django_airavata/apps/auth/urls.py
@@@ -28,5 -32,5 +32,6 @@@ urlpatterns = 
          views.login_desktop_success, name="login_desktop_success"),
      url(r'^refreshed-token-desktop$', views.refreshed_token_desktop,
          name="refreshed_token_desktop"),
 +    url(r'^access-token-redirect$', views.access_token_redirect, name="access_token_redirect"),
+     url(r'^user-profile/', views.user_profile, name="user_profile"),
  ]
diff --cc django_airavata/apps/auth/views.py
index 7eefd46,fb30761..914b632
--- a/django_airavata/apps/auth/views.py
+++ b/django_airavata/apps/auth/views.py
@@@ -5,15 -5,12 +5,16 @@@ from urllib.parse import quote, urlenco
  
  from django.conf import settings
  from django.contrib import messages
- from django.contrib.auth import authenticate, login, logout
+ from django.contrib.auth import authenticate, get_user_model, login, logout
  from django.contrib.auth.decorators import login_required
  from django.core.exceptions import ObjectDoesNotExist
+ from django.db.transaction import atomic
  from django.forms import ValidationError
 -from django.http import HttpResponseBadRequest, JsonResponse
 +from django.http import (
 +    HttpResponseBadRequest,
 +    HttpResponseForbidden,
 +    JsonResponse
 +)
  from django.shortcuts import redirect, render, resolve_url
  from django.template import Context
  from django.urls import reverse
@@@ -510,13 -512,71 +516,83 @@@ def _create_login_desktop_failed_respon
  
  
  @login_required
 +def access_token_redirect(request):
 +    redirect_uri = request.GET['redirect_uri']
 +    config = next(filter(lambda d: d.get('URI') == redirect_uri,
 +                         settings.ACCESS_TOKEN_REDIRECT_ALLOWED_URIS), None)
 +    if config is None:
 +        logger.warning(f"redirect_uri value '{redirect_uri}' is not configured "
 +                       "in ACCESS_TOKEN_REDIRECT_ALLOWED_URIS setting")
 +        return HttpResponseForbidden("Invalid redirect_uri value")
 +    return redirect(redirect_uri + f"{'&' if '?' in redirect_uri else '?'}{config.get('PARAM_NAME', 'access_token')}="
 +                    f"{quote(request.authz_token.accessToken)}")
++
++
+ def user_profile(request):
+     return render(request, "django_airavata_auth/base.html", {
+         'bundle_name': "user-profile"
+     })
+ 
+ 
+ class IsUserOrReadOnlyForAdmins(permissions.BasePermission):
+     def has_permission(self, request, view):
+         return request.user.is_authenticated
+ 
+     def has_object_permission(self, request, view, obj):
+         if (request.method in permissions.SAFE_METHODS and
+                 request.is_gateway_admin):
+             return True
+         return obj == request.user
+ 
+ 
+ # TODO: disable deleting and creating?
+ class UserViewSet(viewsets.ModelViewSet):
+     serializer_class = serializers.UserSerializer
+     queryset = get_user_model().objects.all()
+     permission_classes = [IsUserOrReadOnlyForAdmins]
+ 
+     def get_queryset(self):
+         user = self.request.user
+         if user.is_superuser:
+             return get_user_model().objects.all()
+         else:
+             return get_user_model().objects.get(pk=user.pk)
+ 
+     @action(detail=False)
+     def current(self, request):
+         return redirect(reverse('django_airavata_auth:user-detail', kwargs={'pk': request.user.id}))
+ 
+     @action(methods=['post'], detail=True)
+     def resend_email_verification(self, request, pk=None):
+         pending_email_change = models.PendingEmailChange.objects.get(user=request.user, verified=False)
+         if pending_email_change is not None:
+             serializer = serializers.UserSerializer()
+             serializer._send_email_verification_link(request, pending_email_change)
+         return JsonResponse({})
+ 
+     @action(methods=['post'], detail=True)
+     @atomic
+     def verify_email_change(self, request, pk=None):
+         user = self.get_object()
+         code = request.data['code']
+ 
+         try:
+             pending_email_change = models.PendingEmailChange.objects.get(user=user, verification_code=code)
+         except models.PendingEmailChange.DoesNotExist:
+             raise Exception('Verification code is invalid. Please try again.')
+         pending_email_change.verified = True
+         pending_email_change.save()
+         user.email = pending_email_change.email_address
+         user.save()
+         user.refresh_from_db()
+ 
+         try:
+             user_profile_client = request.profile_service['user_profile']
+             airavata_user_profile = user_profile_client.getUserProfileById(
+                 request.authz_token, user.username, settings.GATEWAY_ID)
+             airavata_user_profile.emails = [pending_email_change.email_address]
+             user_profile_client.updateUserProfile(request.authz_token, airavata_user_profile)
+         except Exception as e:
+             raise Exception(f"Failed to update Airavata User Profile with new email address: {e}") from e
+         serializer = self.get_serializer(user)
+         return Response(serializer.data)