diff --git a/lms/djangoapps/verify_student/tests/test_views.py b/lms/djangoapps/verify_student/tests/test_views.py index f7fb6870e0e38979fd3ea596e8f008c94dd24a91..e8b6816e71d0da1bac8a9fd823d384c8d262ba38 100644 --- a/lms/djangoapps/verify_student/tests/test_views.py +++ b/lms/djangoapps/verify_student/tests/test_views.py @@ -1783,6 +1783,7 @@ class TestPhotoVerificationResultsCallback(ModuleStoreTestCase): attempt = SoftwareSecurePhotoVerification.objects.get(receipt_id=self.receipt_id) self.assertEqual(attempt.status, u'approved') self.assertEquals(response.content, 'OK!') + self.assertEqual(len(mail.outbox), 1) @mock.patch( 'lms.djangoapps.verify_student.ssencrypt.has_valid_signature', @@ -1862,6 +1863,29 @@ class TestPhotoVerificationResultsCallback(ModuleStoreTestCase): ) self.assertIn('Result Unknown not understood', response.content) + @mock.patch( + 'lms.djangoapps.verify_student.utils.send_mail', + mock.Mock(side_effect=Exception()) + ) + def test_verification_status_email_not_sent(self): + """ + Test email is not sent in case of exception + """ + data = { + "EdX-ID": self.receipt_id, + "Result": "PASS", + "Reason": "", + "MessageType": "You have been verified." + } + json_data = json.dumps(data) + self.client.post( + reverse('verify_student_results_callback'), data=json_data, + content_type='application/json', + HTTP_AUTHORIZATION='test BBBBBBBBBBBBBBBBBBBB:testing', + HTTP_DATE='testdate' + ) + self.assertEqual(len(mail.outbox), 0) + @attr(shard=2) class TestReverifyView(TestCase): diff --git a/lms/djangoapps/verify_student/utils.py b/lms/djangoapps/verify_student/utils.py index 9c4ca8a8fdc6812f2559e2eef0a97fcd42c2c149..943f761ce906b708bd94daf66bfaa2413fbd4272 100644 --- a/lms/djangoapps/verify_student/utils.py +++ b/lms/djangoapps/verify_student/utils.py @@ -8,6 +8,11 @@ import logging import pytz from django.conf import settings +from django.core.mail import send_mail +from django.utils.translation import ugettext as _ + +from edxmako.shortcuts import render_to_string +from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers log = logging.getLogger(__name__) @@ -68,3 +73,25 @@ def verification_for_datetime(deadline, candidates): for verification in candidates: if verification.active_at_datetime(deadline): return verification + + +def send_verification_status_email(context): + """ + Send an email to inform learners about their verification status + """ + subject = context['subject'] + message = render_to_string(context['message'], context['email_template_context']) + from_address = configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL) + to_address = context['email'] + + try: + send_mail(subject, message, from_address, [to_address], fail_silently=False) + except: # pylint: disable=bare-except + # We catch all exceptions and log them. + # It would be much, much worse to roll back the transaction due to an uncaught + # exception than to skip sending the notification email. + log.exception( + _("Could not send verification status email having subject: {subject} and email of user: {email}").format( + subject=context['subject'], + email=context['email'] + )) diff --git a/lms/djangoapps/verify_student/views.py b/lms/djangoapps/verify_student/views.py index 0c836b736747cf7292c250a2c64b6ef2f1af33a6..d855eab69a535875074e27e0803e1a7037f1723b 100644 --- a/lms/djangoapps/verify_student/views.py +++ b/lms/djangoapps/verify_student/views.py @@ -37,7 +37,7 @@ from lms.djangoapps.verify_student.image import InvalidImageData, decode_image_d from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification, VerificationDeadline from lms.djangoapps.verify_student.services import IDVerificationService from lms.djangoapps.verify_student.ssencrypt import has_valid_signature -from lms.djangoapps.verify_student.utils import is_verification_expiring_soon +from lms.djangoapps.verify_student.utils import is_verification_expiring_soon, send_verification_status_email from openedx.core.djangoapps.commerce.utils import ecommerce_api_client from openedx.core.djangoapps.embargo import api as embargo_api from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers @@ -1154,10 +1154,26 @@ def results_callback(request): except SoftwareSecurePhotoVerification.DoesNotExist: log.error("Software Secure posted back for receipt_id %s, but not found", receipt_id) return HttpResponseBadRequest("edX ID {} not found".format(receipt_id)) + user = attempt.user + context = { + 'email': user.email + } + email_template_context = {'platform_name': settings.PLATFORM_NAME} if result == "PASS": log.debug("Approving verification for %s", receipt_id) attempt.approve() status = "approved" + expiry_date = datetime.date.today() + datetime.timedelta( + days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"] + ) + email_template_context['full_name'] = user.profile.name + email_template_context['expiry_date'] = expiry_date.strftime("%m/%d/%Y") + context['email_template_context'] = email_template_context + context['subject'] = _("Your {platform_name} ID Verification Approved").format( + platform_name=settings.PLATFORM_NAME + ) + context['message'] = 'emails/successfull_verification_email.txt' + send_verification_status_email(context) elif result == "FAIL": log.debug("Denying verification for %s", receipt_id) diff --git a/lms/templates/emails/successfull_verification_email.txt b/lms/templates/emails/successfull_verification_email.txt new file mode 100644 index 0000000000000000000000000000000000000000..154cde70743022fe8e29233a4038d6a35ea19cfe --- /dev/null +++ b/lms/templates/emails/successfull_verification_email.txt @@ -0,0 +1,11 @@ +<%! from django.utils.translation import ugettext as _ %> + +${_("Hi {full_name},").format(full_name=full_name)} + +${_("Congratulations! Your ID verification process was successful.")} + +${_("Your verification is effective for one year. It will expire on {expiry_date}").format(expiry_date=expiry_date)} + +${_("Thank you,")} + +${_("The {platform_name} team").format(platform_name=platform_name)}