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 2019/12/12 23:18:46 UTC

[airavata-django-portal] 06/07: AIRAVATA-3243 Send one email when user added to multiple groups at once

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

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

commit a7452b4261effc99005cfa7990a636c6e8397493
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Thu Dec 12 16:58:06 2019 -0500

    AIRAVATA-3243 Send one email when user added to multiple groups at once
---
 django_airavata/apps/api/signals.py                |   2 +-
 django_airavata/apps/api/tests.py                  | 119 ++++++++++++++++++++-
 django_airavata/apps/api/views.py                  |  21 ++--
 .../auth/migrations/0005_auto_20191211_2011.py     |  12 +--
 django_airavata/apps/auth/signals.py               |   4 +-
 django_airavata/apps/auth/tests.py                 |  42 +++++++-
 6 files changed, 177 insertions(+), 23 deletions(-)

diff --git a/django_airavata/apps/api/signals.py b/django_airavata/apps/api/signals.py
index e9abfee..f01df92 100644
--- a/django_airavata/apps/api/signals.py
+++ b/django_airavata/apps/api/signals.py
@@ -11,7 +11,7 @@ log = logging.getLogger(__name__)
 
 
 # Signals
-user_added_to_group = Signal(providing_args=["user", "group", "request"])
+user_added_to_group = Signal(providing_args=["user", "groups", "request"])
 
 
 # Receivers
diff --git a/django_airavata/apps/api/tests.py b/django_airavata/apps/api/tests.py
index b682ddb..bb52a9f 100644
--- a/django_airavata/apps/api/tests.py
+++ b/django_airavata/apps/api/tests.py
@@ -1,4 +1,4 @@
-from unittest.mock import MagicMock, patch
+from unittest.mock import MagicMock, call, patch
 
 from django.contrib.auth.models import User
 from django.test import TestCase, override_settings
@@ -76,7 +76,7 @@ class GroupViewSetTests(TestCase):
         self.assertEquals("abc123", response.data['id'])
         user_added_to_group_handler.assert_called_once()
         args, kwargs = user_added_to_group_handler.call_args
-        self.assertEquals("abc123", kwargs["group"].id)
+        self.assertEquals("abc123", kwargs["groups"][0].id)
         self.assertIs(user_profile, kwargs["user"])
 
     def test_update_group_sends_user_added_to_group_signal(self):
@@ -159,7 +159,7 @@ class GroupViewSetTests(TestCase):
 
         user_added_to_group_handler.assert_called_once()
         args, kwargs = user_added_to_group_handler.call_args
-        self.assertEquals("abc123", kwargs["group"].id)
+        self.assertEquals("abc123", kwargs["groups"][0].id)
         self.assertIs(user_profile, kwargs["user"])
 
 
@@ -271,4 +271,115 @@ class IAMUserViewSetTests(TestCase):
         args, kwargs = user_added_to_group_handler.call_args
         self.assertEqual(kwargs["sender"], views.IAMUserViewSet)
         self.assertEqual(kwargs["user"], user_profile)
-        self.assertEqual(kwargs["group"], group)
+        self.assertEqual(kwargs["groups"][0], group)
+
+    @patch("django_airavata.apps.api.views.iam_admin_client")
+    def test_update_that_adds_user_to_multiple_groups(
+            self, iam_admin_client):
+
+        username = "testuser1"
+        url = reverse(
+            'django_airavata_api:iam-user-profile-detail',
+            kwargs={'user_id': username})
+        data = {
+            "airavataInternalUserId": f"{username}@{GATEWAY_ID}",
+            "userId": username,
+            "gatewayId": GATEWAY_ID,
+            "email": "testuser1@example.com",
+            "firstName": "Test",
+            "lastName": "User1",
+            "airavataUserProfileExists": True,
+            "enabled": True,
+            "emailVerified": True,
+            "groups": [
+                {"id": "group1", "name": "Group 1"},
+                {"id": "group2", "name": "Group 2"},
+                {"id": "group3", "name": "Group 3"},
+            ]
+        }
+        request = self.factory.put(url, data)
+        force_authenticate(request, self.user)
+        request.is_gateway_admin = True
+
+        # Mock api clients
+        iam_user_profile = UserProfile(
+            airavataInternalUserId=f"testuser1@{GATEWAY_ID}",
+            userId="testuser1",
+            firstName="Test",
+            lastName="User1",
+            emails=["testuser1@example.com"]
+        )
+        iam_admin_client.get_user.return_value = iam_user_profile
+        group_manager_mock = MagicMock(name='group_manager')
+        user_profile_mock = MagicMock(name='user_profile')
+        request.profile_service = {
+            'group_manager': group_manager_mock,
+            'user_profile': user_profile_mock,
+        }
+        request.authz_token = "dummy"
+        user_profile_mock.doesUserExist.return_value = True
+        user_profile = UserProfile(
+            airavataInternalUserId=f"testuser1@{GATEWAY_ID}",
+            userId="testuser1",
+            firstName="Test",
+            lastName="User1",
+            emails=["testuser1@example.com"]
+        )
+        user_profile_mock.getUserProfileById.return_value = user_profile
+        group_manager_mock.getAllGroupsUserBelongs.return_value = [
+            GroupModel(id="group1")]
+
+        def side_effect(authz_token, group_id):
+            if group_id == "group2":
+                return GroupModel(id="group2", name="Group 2")
+            elif group_id == "group3":
+                return GroupModel(id="group3", name="Group 3")
+            else:
+                raise Exception("Unexpected group id: " + group_id)
+
+        group_manager_mock.getGroup.side_effect = side_effect
+        request.airavata_client = MagicMock(name="airavata_client")
+        request.airavata_client.getGatewayGroups.return_value = GatewayGroups(
+            gatewayId=GATEWAY_ID,
+            adminsGroupId="adminsGroupId",
+            readOnlyAdminsGroupId="readOnlyAdminsGroupId",
+            defaultGatewayUsersGroupId="defaultGatewayUsersGroupId"
+        )
+        request.session = {}
+
+        # Mock signal handler to verify 'user_added_to_group' signal is sent
+        user_added_to_group_handler = MagicMock(
+            name="user_added_to_group_handler")
+        signals.user_added_to_group.connect(
+            user_added_to_group_handler,
+            sender=views.IAMUserViewSet)
+        iam_user_update = views.IAMUserViewSet.as_view({'put': 'update'})
+        response = iam_user_update(request, user_id=username)
+        self.assertEquals(200, response.status_code)
+
+        user_profile_mock.doesUserExist.assert_called_once()
+        group_manager_mock.getAllGroupsUserBelongs.assert_called_once()
+
+        user_profile_mock.getUserProfileById.assert_called_once()
+        args, kwargs = user_profile_mock.getUserProfileById.call_args
+        self.assertSequenceEqual(
+            args, [request.authz_token, "testuser1", GATEWAY_ID])
+
+        group_manager_mock.getGroup.assert_has_calls([
+            call(request.authz_token, "group2"),
+            call(request.authz_token, "group3")
+        ], any_order=True)
+
+        group_manager_mock.addUsersToGroup.assert_has_calls([
+            call(request.authz_token, [f"testuser1@{GATEWAY_ID}"], "group2"),
+            call(request.authz_token, [f"testuser1@{GATEWAY_ID}"], "group3"),
+        ], any_order=True)
+
+        # user_added_to_group signal should only be called once, with both
+        # groups passed to it
+        user_added_to_group_handler.assert_called_once()
+        args, kwargs = user_added_to_group_handler.call_args
+        self.assertEqual(kwargs["sender"], views.IAMUserViewSet)
+        self.assertEqual(kwargs["user"], user_profile)
+        self.assertSetEqual({"group2", "group3"},
+                            {g.id for g in kwargs["groups"]})
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index f674139..02d6701 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -122,7 +122,7 @@ class GroupViewSet(APIBackedViewSet):
             signals.user_added_to_group.send(
                 sender=self.__class__,
                 user=user_profile,
-                group=group,
+                groups=[group],
                 request=self.request)
 
 
@@ -1613,18 +1613,21 @@ class IAMUserViewSet(mixins.RetrieveModelMixin,
         group_manager_client = self.request.profile_service['group_manager']
         user_profile_client = self.request.profile_service['user_profile']
         user_id = managed_user_profile['airavataInternalUserId']
-        username = managed_user_profile['userId']
+        user_profile = user_profile_client.getUserProfileById(
+            self.authz_token,
+            managed_user_profile['userId'],
+            settings.GATEWAY_ID)
+        added_groups = []
         for group_id in managed_user_profile['_added_group_ids']:
-            user_profile = user_profile_client.getUserProfileById(
-                self.authz_token, username, settings.GATEWAY_ID)
             group = group_manager_client.getGroup(self.authz_token, group_id)
             group_manager_client.addUsersToGroup(
                 self.authz_token, [user_id], group_id)
-            signals.user_added_to_group.send(
-                sender=self.__class__,
-                user=user_profile,
-                group=group,
-                request=self.request)
+            added_groups.append(group)
+        signals.user_added_to_group.send(
+            sender=self.__class__,
+            user=user_profile,
+            groups=added_groups,
+            request=self.request)
         for group_id in managed_user_profile['_removed_group_ids']:
             group_manager_client.removeUsersFromGroup(
                 self.authz_token, [user_id], group_id)
diff --git a/django_airavata/apps/auth/migrations/0005_auto_20191211_2011.py b/django_airavata/apps/auth/migrations/0005_auto_20191211_2011.py
index c6533dc..eeb4b99 100644
--- a/django_airavata/apps/auth/migrations/0005_auto_20191211_2011.py
+++ b/django_airavata/apps/auth/migrations/0005_auto_20191211_2011.py
@@ -12,22 +12,22 @@ def default_templates(apps, schema_editor):
     EmailTemplate = apps.get_model("django_airavata_auth", "EmailTemplate")
     user_added_to_group_template = EmailTemplate(
         template_type=USER_ADDED_TO_GROUP_TEMPLATE,
-        subject="You've been added to group [{{group_name}}] in {{portal_title}}",
+        subject="You've been added to group{{ group_names|length|pluralize }} [{{group_names|join:'] and ['}}] in {{portal_title}}",
         body="""
         <p>
         Dear {{first_name}} {{last_name}},
         </p>
 
         <p>
-        Your user account (username {{username}}) has been added to the group
-        {{group_name}}. {{portal_title}} uses groups to share applications
-        and experiments.
+        Your user account (username {{username}}) has been added to the
+        group{{ group_names|length|pluralize }} {{group_names|join:' and '}}.
+        {{portal_title}} uses groups to share applications and experiments.
         </p>
 
         <p>
         You may have access to additional applications now that you are a
-        member of {{group_name}}. To check what applications you have access
-        to, please check: <a href="{{dashboard_url}}">{{dashboard_url}}</a>.
+        member of {{group_names|join:' and '}}. To check what applications you
+        have access to, please check: <a href="{{dashboard_url}}">{{dashboard_url}}</a>.
         </p>
 
         <p>
diff --git a/django_airavata/apps/auth/signals.py b/django_airavata/apps/auth/signals.py
index 9efe76a..32f3cb0 100644
--- a/django_airavata/apps/auth/signals.py
+++ b/django_airavata/apps/auth/signals.py
@@ -9,7 +9,7 @@ from . import models, utils
 
 
 @receiver(user_added_to_group, dispatch_uid="auth_email_user_added_to_group")
-def email_user_added_to_group(sender, user, group, request, **kwargs):
+def email_user_added_to_group(sender, user, groups, request, **kwargs):
     context = Context({
         "email": user.emails[0],
         "first_name": user.firstName,
@@ -20,6 +20,6 @@ def email_user_added_to_group(sender, user, group, request, **kwargs):
             reverse("django_airavata_workspace:dashboard")),
         "experiments_url": request.build_absolute_uri(
             reverse("django_airavata_workspace:experiments")),
-        "group_name": group.name
+        "group_names": [g.name for g in groups]
     })
     utils.send_email_to_user(models.USER_ADDED_TO_GROUP_TEMPLATE, context)
diff --git a/django_airavata/apps/auth/tests.py b/django_airavata/apps/auth/tests.py
index 6d7a033..50d4faa 100644
--- a/django_airavata/apps/auth/tests.py
+++ b/django_airavata/apps/auth/tests.py
@@ -31,7 +31,10 @@ class EmailUserAddedToGroupSignalReceiverTests(TestCase):
             firstName="Test",
             lastName="User")
         group = GroupModel(id="abc123", name="Test Group")
-        user_added_to_group.send(None, user=user, group=group, request=request)
+        user_added_to_group.send(None,
+                                 user=user,
+                                 groups=[group],
+                                 request=request)
         self.assertEqual(len(mail.outbox), 1)
         msg = mail.outbox[0]
         self.assertEqual(msg.subject,
@@ -50,3 +53,40 @@ class EmailUserAddedToGroupSignalReceiverTests(TestCase):
                 reverse("django_airavata_workspace:experiments")),
             msg.body)
         self.assertIn(user.userId, msg.body)
+
+    def test_multiple_groups(self):
+        factory = RequestFactory()
+        request = factory.get("/")
+        user = UserProfile(
+            airavataInternalUserId=f"testuser@{GATEWAY_ID}",
+            userId="testuser",
+            gatewayId=GATEWAY_ID,
+            emails=["testuser@example.com"],
+            firstName="Test",
+            lastName="User")
+        group1 = GroupModel(id="abc123", name="Test Group")
+        group2 = GroupModel(id="group2", name="Group 2")
+        user_added_to_group.send(None,
+                                 user=user,
+                                 groups=[group1, group2],
+                                 request=request)
+        self.assertEqual(len(mail.outbox), 1)
+        msg = mail.outbox[0]
+        self.assertEqual(msg.subject,
+                         f"You've been added to groups "
+                         f"[{group1.name}] and [{group2.name}] "
+                         f"in {PORTAL_TITLE}")
+        self.assertEqual(msg.from_email,
+                         f"{PORTAL_TITLE} <{SERVER_EMAIL}>")
+        self.assertSequenceEqual(
+            msg.to, [f"{user.firstName} {user.lastName} <{user.emails[0]}>"])
+        self.assertIn(
+            request.build_absolute_uri(
+                reverse("django_airavata_workspace:dashboard")),
+            msg.body)
+        self.assertIn(
+            request.build_absolute_uri(
+                reverse("django_airavata_workspace:experiments")),
+            msg.body)
+        self.assertIn(user.userId, msg.body)
+        self.assertIn("groups Test Group and Group 2", msg.body)