diff --git a/openedx/core/djangoapps/ace_common/template_context.py b/openedx/core/djangoapps/ace_common/template_context.py index b86658fb1f..7ae2769823 100644 --- a/openedx/core/djangoapps/ace_common/template_context.py +++ b/openedx/core/djangoapps/ace_common/template_context.py @@ -22,6 +22,8 @@ def get_base_template_context(site): site=site, site_config_name='platform_name', ), + 'contact_email': get_config_value_from_site_or_settings( + 'CONTACT_EMAIL', site=site, site_config_name='contact_email'), 'contact_mailing_address': get_config_value_from_site_or_settings( 'CONTACT_MAILING_ADDRESS', site=site, site_config_name='contact_mailing_address'), 'social_media_urls': get_config_value_from_site_or_settings('SOCIAL_MEDIA_FOOTER_URLS', site=site), diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_views.py b/openedx/core/djangoapps/user_api/accounts/tests/test_views.py index 16c2d98c36..4f99e5a1d5 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_views.py @@ -13,6 +13,7 @@ import ddt from django.conf import settings from django.contrib.auth.models import User from django.contrib.sites.models import Site +from django.core import mail from django.core.cache import cache from django.core.urlresolvers import reverse from django.test import TestCase @@ -1148,6 +1149,10 @@ class TestDeactivateLogout(RetirementTestCase): retirement_utils_mock.retire_dot_oauth2_models.assertCalledWith(self.test_user) # make sure the user cannot log in self.assertFalse(self.client.login(username=self.test_user.username, password=self.test_password)) + # make sure that an email has been sent + self.assertEqual(len(mail.outbox), 1) + # ensure that it's been sent to the correct email address + self.assertIn(self.test_user.email, mail.outbox[0].to) def test_password_mismatch(self): """ diff --git a/openedx/core/djangoapps/user_api/accounts/views.py b/openedx/core/djangoapps/user_api/accounts/views.py index e2404481dc..a1c8df71bf 100644 --- a/openedx/core/djangoapps/user_api/accounts/views.py +++ b/openedx/core/djangoapps/user_api/accounts/views.py @@ -11,9 +11,12 @@ from functools import wraps import pytz from consent.models import DataSharingConsent from django.contrib.auth import authenticate, get_user_model, logout +from django.contrib.sites.models import Site from django.core.cache import cache from django.db import transaction from django.utils.translation import ugettext as _ +from edx_ace import ace +from edx_ace.recipient import Recipient from edx_rest_framework_extensions.authentication import JwtAuthentication from enterprise.models import EnterpriseCourseEnrollment, EnterpriseCustomerUser, PendingEnterpriseCustomerUser from integrated_channels.degreed.models import DegreedLearnerDataTransmissionAudit @@ -31,6 +34,7 @@ from wiki.models.pluginbase import RevisionPluginRevision from entitlements.models import CourseEntitlement from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification +from openedx.core.djangoapps.ace_common.template_context import get_base_template_context from openedx.core.djangoapps.api_admin.models import ApiAccessRequest from openedx.core.djangoapps.credit.models import CreditRequirementStatus, CreditRequest from openedx.core.djangoapps.course_groups.models import UnregisteredLearnerCohortAssignments @@ -67,6 +71,7 @@ from .api import get_account_settings, update_account_settings from .permissions import CanDeactivateUser, CanRetireUser from .serializers import UserRetirementStatusSerializer from .signals import USER_RETIRE_MAILINGS +from ..message_types import DeletionNotificationMessage log = logging.getLogger(__name__) @@ -421,6 +426,7 @@ class DeactivateLogoutView(APIView): # Unlink LMS social auth accounts UserSocialAuth.objects.filter(user_id=request.user.id).delete() # Change LMS password & email + user_email = request.user.email request.user.email = get_retired_email_by_email(request.user.email) request.user.save() _set_unusable_password(request.user) @@ -431,6 +437,22 @@ class DeactivateLogoutView(APIView): # Delete OAuth tokens associated with the user. retire_dop_oauth2_models(request.user) retire_dot_oauth2_models(request.user) + + try: + # Send notification email to user + site = Site.objects.get_current() + notification_context = get_base_template_context(site) + notification_context.update({'full_name': request.user.profile.name}) + notification = DeletionNotificationMessage().personalize( + recipient=Recipient(username='', email_address=user_email), + language=request.user.profile.language, + user_context=notification_context, + ) + ace.send(notification) + except Exception as exc: + log.exception('Error sending out deletion notification email') + raise + # Log the user out. logout(request) return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/openedx/core/djangoapps/user_api/message_types.py b/openedx/core/djangoapps/user_api/message_types.py new file mode 100644 index 0000000000..0249ceca10 --- /dev/null +++ b/openedx/core/djangoapps/user_api/message_types.py @@ -0,0 +1,21 @@ +""" +Message Types for user_api emails +""" + +from django.conf import settings + +from edx_ace import message +from openedx.core.djangoapps.site_configuration import helpers + + +class DeletionNotificationMessage(message.MessageType): + """ + Message to notify learners that their account is queued for deletion. + """ + def __init__(self, *args, **kwargs): + super(DeletionNotificationMessage, self).__init__(*args, **kwargs) + + self.options['transactional'] = True # pylint: disable=unsupported-assignment-operation + self.options['from_address'] = helpers.get_value( # pylint: disable=unsupported-assignment-operation + 'email_from_address', settings.DEFAULT_FROM_EMAIL + ) diff --git a/openedx/core/djangoapps/user_api/templates/user_api/edx_ace/deletionnotificationmessage/email/body.html b/openedx/core/djangoapps/user_api/templates/user_api/edx_ace/deletionnotificationmessage/email/body.html new file mode 100644 index 0000000000..1ad6cb6aaa --- /dev/null +++ b/openedx/core/djangoapps/user_api/templates/user_api/edx_ace/deletionnotificationmessage/email/body.html @@ -0,0 +1,37 @@ +{% extends 'ace_common/edx_ace/common/base_body.html' %} +{% load i18n %} + +{% block content %} +
|
+ + {% blocktrans trimmed %} + Hello {{full_name}}, + {% endblocktrans %} + ++ {% blocktrans trimmed %} + We received a deletion request for your account on {{platform_name}}. We're sorry to see you go! + {% endblocktrans %} + ++ {% blocktrans trimmed %} + Your account will be deleted shortly. Account deletion, including removal from email lists, may take a few weeks to fully process through our system. If you want to opt-out of emails before then, please unsubscribe from the footer of any email. + {% endblocktrans %} + ++ {% blocktrans trimmed %} + This is an informational email only. If you did not initiate this request, please contact {{contact_email}}. + {% endblocktrans %} + ++ {% blocktrans trimmed %} + Best, + {{ platform_name }} + {% endblocktrans %} + + |
+