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:44 UTC

[airavata-django-portal] 03/05: AIRAVATA-3567 email template for user profile complete admin email

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 87fe6cd60e5d7df819a9c3051656ad1825dd4a33
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Thu Jun 16 16:58:32 2022 -0400

    AIRAVATA-3567 email template for user profile complete admin email
---
 .../auth/migrations/0017_auto_20220616_1831.py     | 55 ++++++++++++++++++++++
 django_airavata/apps/auth/models.py                | 11 +++++
 django_airavata/apps/auth/serializers.py           |  4 +-
 django_airavata/apps/auth/utils.py                 | 36 ++++++++++----
 django_airavata/apps/auth/views.py                 |  3 +-
 5 files changed, 99 insertions(+), 10 deletions(-)

diff --git a/django_airavata/apps/auth/migrations/0017_auto_20220616_1831.py b/django_airavata/apps/auth/migrations/0017_auto_20220616_1831.py
new file mode 100644
index 00000000..47ed7952
--- /dev/null
+++ b/django_airavata/apps/auth/migrations/0017_auto_20220616_1831.py
@@ -0,0 +1,55 @@
+# Generated by Django 3.2.11 on 2022-06-16 18:31
+
+from django.db import migrations
+
+from django_airavata.apps.auth.models import (
+    USER_PROFILE_COMPLETED_TEMPLATE,
+)
+
+
+def default_templates(apps, schema_editor):
+
+    EmailTemplate = apps.get_model("django_airavata_auth", "EmailTemplate")
+    user_profile_completed_template = EmailTemplate(
+        template_type=USER_PROFILE_COMPLETED_TEMPLATE,
+        subject="User {{first_name}} {{last_name}} ({{username}}) has completed their profile",
+        body="""
+            <p>Gateway Portal: {{http_host}}</p>
+            <p>Tenant: {{gateway_id}}</p>
+            <h3>User Profile</h3>
+            <p>Username: {{username}}</p>
+            <p>Name: {{first_name}} {{last_name}}</p>
+            <p>Email: {{email}}</p>
+            {% if extended_profile_values %}
+            <h3>Extended User Profile</h3>
+            <table><tr><th>Name</th><th>Value</th></tr>
+            {% for value in extended_profile_values %}
+                <tr><td>{{ value.ext_user_profile_field.name }}</td>
+                {% if value.value_display_list and value.value_display_list|length > 1 %}
+                <td><ul>
+                    {% for display_item in value.value_display_list %}
+                    <li>{{ display_item }}</li>
+                    {% endfor %}
+                </ul></td>
+                {% elif value.value_display_list and value.value_display_list|length == 1 %}
+                <td>{{ value.value_display_list|first }}</td>
+                {% else %}
+                <td>{{ value.value_display_list }}</td>
+                {% endif %}
+                </tr>
+            {% endfor %}
+            </table>
+            {% endif %}
+        """.strip())
+    user_profile_completed_template.save()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('django_airavata_auth', '0016_extendeduserprofilefield_required'),
+    ]
+
+    operations = [
+        migrations.RunPython(default_templates)
+    ]
diff --git a/django_airavata/apps/auth/models.py b/django_airavata/apps/auth/models.py
index d4cd2695..6cc658ea 100644
--- a/django_airavata/apps/auth/models.py
+++ b/django_airavata/apps/auth/models.py
@@ -11,6 +11,7 @@ NEW_USER_EMAIL_TEMPLATE = 2
 PASSWORD_RESET_EMAIL_TEMPLATE = 3
 USER_ADDED_TO_GROUP_TEMPLATE = 4
 VERIFY_EMAIL_CHANGE_TEMPLATE = 5
+USER_PROFILE_COMPLETED_TEMPLATE = 6
 
 
 class EmailVerification(models.Model):
@@ -29,6 +30,7 @@ class EmailTemplate(models.Model):
         (PASSWORD_RESET_EMAIL_TEMPLATE, 'Password Reset Email Template'),
         (USER_ADDED_TO_GROUP_TEMPLATE, 'User Added to Group Template'),
         (VERIFY_EMAIL_CHANGE_TEMPLATE, 'Verify Email Change Template'),
+        (USER_PROFILE_COMPLETED_TEMPLATE, 'User Profile Completed Template'),
     )
     template_type = models.IntegerField(
         primary_key=True, choices=TEMPLATE_TYPE_CHOICES)
@@ -311,6 +313,15 @@ class ExtendedUserProfileValue(models.Model):
                 return "No"
         return None
 
+    @property
+    def value_display_list(self):
+        """Same as value_display except coerced always to a list."""
+        value_display = self.value_display
+        if value_display is not None and not isinstance(value_display, list):
+            return [value_display]
+        else:
+            return value_display
+
     @property
     def valid(self):
         # if the field is deleted, whatever the value, consider it valid
diff --git a/django_airavata/apps/auth/serializers.py b/django_airavata/apps/auth/serializers.py
index 70db769c..c02162ae 100644
--- a/django_airavata/apps/auth/serializers.py
+++ b/django_airavata/apps/auth/serializers.py
@@ -228,7 +228,9 @@ class ExtendedUserProfileFieldSerializer(serializers.ModelSerializer):
 class ExtendedUserProfileValueSerializer(serializers.ModelSerializer):
     id = serializers.IntegerField(label='ID', required=False)
     text_value = serializers.CharField(required=False, allow_blank=True)
-    choices = serializers.ListField(child=serializers.IntegerField(), required=False)
+    # choices must be write_only so that DRF ignores trying to deserialized this related field
+    # deserialization is handled explicitly in to_representation, see below
+    choices = serializers.ListField(child=serializers.IntegerField(), required=False, write_only=True)
     other_value = serializers.CharField(required=False, allow_blank=True)
     agreement_value = serializers.BooleanField(required=False)
 
diff --git a/django_airavata/apps/auth/utils.py b/django_airavata/apps/auth/utils.py
index d7ebda8b..cfa53c04 100644
--- a/django_airavata/apps/auth/utils.py
+++ b/django_airavata/apps/auth/utils.py
@@ -129,14 +129,7 @@ def send_new_user_email(request, username, email, first_name, last_name):
     })
     subject = Template(new_user_email_template.subject).render(context)
     body = Template(new_user_email_template.body).render(context)
-    msg = EmailMessage(subject=subject,
-                       body=body,
-                       from_email=f'"{settings.PORTAL_TITLE}" <{settings.SERVER_EMAIL}>',
-                       to=[f'"{a[0]}" <{a[1]}>' for a in getattr(settings,
-                                                                 'PORTAL_ADMINS',
-                                                                 settings.ADMINS)])
-    msg.content_subtype = 'html'
-    msg.send()
+    send_email_to_admins(subject, body)
 
 
 def send_admin_alert_about_uninitialized_username(request, username, email, first_name, last_name):
@@ -174,6 +167,33 @@ def send_admin_alert_about_uninitialized_username(request, username, email, firs
     portal.
     </p>
     """.strip()).render(context)
+    send_email_to_admins(subject, body)
+
+
+def send_admin_user_completed_profile(request, user_profile):
+    domain, port = split_domain_port(request.get_host())
+    user = user_profile.user
+    extended_profile_values = user_profile.extended_profile_values.filter(
+        ext_user_profile_field__deleted=False).order_by("ext_user_profile_field__order").all()
+    context = Context({
+        "username": user.username,
+        "email": user.email,
+        "first_name": user.first_name,
+        "last_name": user.last_name,
+        "portal_title": settings.PORTAL_TITLE,
+        "gateway_id": settings.GATEWAY_ID,
+        "http_host": domain,
+        "extended_profile_values": extended_profile_values
+    })
+
+    user_profile_completed_template = models.EmailTemplate.objects.get(
+        pk=models.USER_PROFILE_COMPLETED_TEMPLATE)
+    subject = Template(user_profile_completed_template.subject).render(context)
+    body = Template(user_profile_completed_template.body).render(context)
+    send_email_to_admins(subject, body)
+
+
+def send_email_to_admins(subject, body):
     msg = EmailMessage(subject=subject,
                        body=body,
                        from_email=f'"{settings.PORTAL_TITLE}" <{settings.SERVER_EMAIL}>',
diff --git a/django_airavata/apps/auth/views.py b/django_airavata/apps/auth/views.py
index eb016607..a2c0775f 100644
--- a/django_airavata/apps/auth/views.py
+++ b/django_airavata/apps/auth/views.py
@@ -751,6 +751,7 @@ class ExtendedUserProfileValueViewset(mixins.CreateModelMixin,
         return queryset
 
     @action(methods=['POST'], detail=False, url_path="save-all")
+    @atomic
     def save_all(self, request, format=None):
         user = request.user
         user_profile: models.UserProfile = user.user_profile
@@ -761,7 +762,7 @@ class ExtendedUserProfileValueViewset(mixins.CreateModelMixin,
 
         new_valid = user_profile.is_ext_user_profile_valid
         if not old_valid and new_valid:
-            logger.info("TODO: send email to admin")
+            utils.send_admin_user_completed_profile(request, user_profile)
 
         serializer = self.get_serializer(values, many=True)
         return Response(serializer.data)