Merge pull request #18748 from edx/LEARNER-5931/update-learner-verification-emails
Update verification status emails
This commit is contained in:
40
lms/djangoapps/verify_student/tasks.py
Normal file
40
lms/djangoapps/verify_student/tasks.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
Django Celery tasks for service status app
|
||||
"""
|
||||
import logging
|
||||
from smtplib import SMTPException
|
||||
|
||||
from celery import task
|
||||
from django.conf import settings
|
||||
from django.core.mail import send_mail
|
||||
|
||||
from edxmako.shortcuts import render_to_string
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
|
||||
ACE_ROUTING_KEY = getattr(settings, 'ACE_ROUTING_KEY', None)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@task(routing_key=ACE_ROUTING_KEY)
|
||||
def send_verification_status_email(context):
|
||||
"""
|
||||
Spins a task to send verification status email to the learner
|
||||
"""
|
||||
subject = context.get('subject')
|
||||
message = render_to_string(context.get('template'), context.get('email_vars'))
|
||||
from_addr = configuration_helpers.get_value(
|
||||
'email_from_address',
|
||||
settings.DEFAULT_FROM_EMAIL
|
||||
)
|
||||
dest_addr = context.get('email')
|
||||
|
||||
try:
|
||||
send_mail(
|
||||
subject,
|
||||
message,
|
||||
from_addr,
|
||||
[dest_addr],
|
||||
fail_silently=False
|
||||
)
|
||||
except SMTPException:
|
||||
log.warning("Failure in sending verification status e-mail to %s", dest_addr)
|
||||
@@ -38,8 +38,7 @@ from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
|
||||
from lms.djangoapps.verify_student.views import (
|
||||
PayAndVerifyView,
|
||||
checkout_with_ecommerce_service,
|
||||
render_to_response,
|
||||
EmailMarketingConfiguration
|
||||
render_to_response
|
||||
)
|
||||
from openedx.core.djangoapps.embargo.test_utils import restrict_course
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme
|
||||
@@ -1775,7 +1774,6 @@ class TestPhotoVerificationResultsCallback(ModuleStoreTestCase):
|
||||
"""
|
||||
Test for verification passed.
|
||||
"""
|
||||
EmailMarketingConfiguration.objects.create(sailthru_verification_passed_template='test_template')
|
||||
data = {
|
||||
"EdX-ID": self.receipt_id,
|
||||
"Result": "PASS",
|
||||
@@ -1792,8 +1790,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.assertFalse(mock_log_error.called)
|
||||
self.assertTrue(mock_sailthru_send.call_args[1], 'test_template')
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
|
||||
@patch(
|
||||
'lms.djangoapps.verify_student.ssencrypt.has_valid_signature',
|
||||
@@ -1805,11 +1802,10 @@ class TestPhotoVerificationResultsCallback(ModuleStoreTestCase):
|
||||
"""
|
||||
Test for failed verification.
|
||||
"""
|
||||
EmailMarketingConfiguration.objects.create(sailthru_verification_failed_template='test_template')
|
||||
data = {
|
||||
"EdX-ID": self.receipt_id,
|
||||
"Result": 'FAIL',
|
||||
"Reason": 'Invalid photo',
|
||||
"Reason": [{"photoIdReasons": ["Not provided"]}],
|
||||
"MessageType": 'Your photo doesn\'t meet standards.'
|
||||
}
|
||||
json_data = json.dumps(data)
|
||||
@@ -1823,10 +1819,9 @@ class TestPhotoVerificationResultsCallback(ModuleStoreTestCase):
|
||||
attempt = SoftwareSecurePhotoVerification.objects.get(receipt_id=self.receipt_id)
|
||||
self.assertEqual(attempt.status, u'denied')
|
||||
self.assertEqual(attempt.error_code, u'Your photo doesn\'t meet standards.')
|
||||
self.assertEqual(attempt.error_msg, u'"Invalid photo"')
|
||||
self.assertEqual(attempt.error_msg, u'[{"photoIdReasons": ["Not provided"]}]')
|
||||
self.assertEquals(response.content, 'OK!')
|
||||
self.assertFalse(mock_log_error.called)
|
||||
self.assertTrue(mock_sailthru_send.call_args[1], 'test_template')
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
|
||||
@patch(
|
||||
'lms.djangoapps.verify_student.ssencrypt.has_valid_signature',
|
||||
|
||||
@@ -76,23 +76,6 @@ def verification_for_datetime(deadline, candidates):
|
||||
return verification
|
||||
|
||||
|
||||
def send_verification_status_email(context):
|
||||
"""
|
||||
Send an email to inform learners about their verification status
|
||||
using sailthru
|
||||
"""
|
||||
sailthru_client = SailthruClient(context['email_config'].sailthru_key, context['email_config'].sailthru_secret)
|
||||
sailthru_response = sailthru_client.send(
|
||||
email=context['email'], template=context['template'],
|
||||
_vars=context['template_vars']
|
||||
)
|
||||
if not sailthru_response.is_ok():
|
||||
error = sailthru_response.get_error()
|
||||
log.error("Error attempting to send verification status email to user: {} via Sailthru: {}".format(
|
||||
context['email'], error.get_message()
|
||||
))
|
||||
|
||||
|
||||
def most_recent_verification(photo_id_verifications, sso_id_verifications, manual_id_verifications, most_recent_key):
|
||||
"""
|
||||
Return the most recent verification given querysets for photo, sso and manual verifications.
|
||||
|
||||
@@ -13,10 +13,10 @@ from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||
from django.core.mail import send_mail
|
||||
from django.urls import reverse
|
||||
from django.db import transaction
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import ugettext_lazy
|
||||
@@ -32,13 +32,13 @@ from pytz import UTC
|
||||
|
||||
from course_modes.models import CourseMode
|
||||
from edxmako.shortcuts import render_to_response, render_to_string
|
||||
from email_marketing.models import EmailMarketingConfiguration
|
||||
from lms.djangoapps.commerce.utils import EcommerceService, is_account_activation_requirement_disabled
|
||||
from lms.djangoapps.verify_student.image import InvalidImageData, decode_image_data
|
||||
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, send_verification_status_email
|
||||
from lms.djangoapps.verify_student.tasks import send_verification_status_email
|
||||
from lms.djangoapps.verify_student.utils import is_verification_expiring_soon
|
||||
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
|
||||
@@ -1162,48 +1162,47 @@ def results_callback(request):
|
||||
return HttpResponseBadRequest("edX ID {} not found".format(receipt_id))
|
||||
|
||||
user = attempt.user
|
||||
email_config = EmailMarketingConfiguration.current()
|
||||
verification_status_email_vars = {
|
||||
'platform_name': settings.PLATFORM_NAME,
|
||||
}
|
||||
email_context = {
|
||||
'email_config': email_config,
|
||||
'email': user.email
|
||||
}
|
||||
if result == "PASS":
|
||||
log.debug("Approving verification for %s", receipt_id)
|
||||
attempt.approve()
|
||||
status = "approved"
|
||||
if email_config.sailthru_verification_passed_template:
|
||||
expiry_date = datetime.date.today() + datetime.timedelta(
|
||||
days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"]
|
||||
)
|
||||
verification_status_email_vars['expiry_date'] = expiry_date.strftime("%m/%d/%Y")
|
||||
verification_status_email_vars['subject'] = _("Your {platform_name} ID Verification Approved").format(
|
||||
platform_name=settings.PLATFORM_NAME
|
||||
)
|
||||
verification_status_email_vars['full_name'] = user.profile.name
|
||||
email_context['template'] = email_config.sailthru_verification_passed_template
|
||||
email_context['template_vars'] = verification_status_email_vars
|
||||
send_verification_status_email(email_context)
|
||||
expiry_date = datetime.date.today() + datetime.timedelta(
|
||||
days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"]
|
||||
)
|
||||
verification_status_email_vars['expiry_date'] = expiry_date.strftime("%m/%d/%Y")
|
||||
verification_status_email_vars['full_name'] = user.profile.name
|
||||
subject = _("Your {platform_name} ID Verification Approved").format(
|
||||
platform_name=settings.PLATFORM_NAME
|
||||
)
|
||||
context = {
|
||||
'subject': subject,
|
||||
'template': 'emails/passed_verification_email.txt',
|
||||
'email': user.email,
|
||||
'email_vars': verification_status_email_vars
|
||||
}
|
||||
send_verification_status_email.delay(context)
|
||||
|
||||
elif result == "FAIL":
|
||||
log.debug("Denying verification for %s", receipt_id)
|
||||
attempt.deny(json.dumps(reason), error_code=error_code)
|
||||
status = "denied"
|
||||
if email_config.sailthru_verification_failed_template:
|
||||
verification_status_email_vars['reason'] = reason
|
||||
verification_status_email_vars['reverify_url'] = reverse("verify_student_reverify")
|
||||
verification_status_email_vars['faq_url'] = configuration_helpers.get_value(
|
||||
'ID_VERIFICATION_SUPPORT_LINK',
|
||||
settings.SUPPORT_SITE_LINK
|
||||
)
|
||||
verification_status_email_vars['subject'] = _("Your {platform_name} Verification Has Been Denied").format(
|
||||
platform_name=settings.PLATFORM_NAME
|
||||
)
|
||||
email_context['template'] = email_config.sailthru_verification_failed_template
|
||||
email_context['template_vars'] = verification_status_email_vars
|
||||
send_verification_status_email(email_context)
|
||||
reverify_url = '{}{}'.format(settings.LMS_ROOT_URL, reverse("verify_student_reverify"))
|
||||
verification_status_email_vars['reasons'] = reason
|
||||
verification_status_email_vars['reverify_url'] = reverify_url
|
||||
verification_status_email_vars['faq_url'] = settings.ID_VERIFICATION_SUPPORT_LINK
|
||||
subject = _("Your {platform_name} Verification Has Been Denied").format(
|
||||
platform_name=settings.PLATFORM_NAME
|
||||
)
|
||||
context = {
|
||||
'subject': subject,
|
||||
'template': 'emails/failed_verification_email.txt',
|
||||
'email': user.email,
|
||||
'email_vars': verification_status_email_vars
|
||||
}
|
||||
send_verification_status_email.delay(context)
|
||||
|
||||
elif result == "SYSTEM FAIL":
|
||||
log.debug("System failure for %s -- resetting to must_retry", receipt_id)
|
||||
|
||||
38
lms/templates/emails/failed_verification_email.txt
Normal file
38
lms/templates/emails/failed_verification_email.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
|
||||
|
||||
${_("Sorry! The photos you submitted for ID verification were not accepted, for the following reason(s):")}
|
||||
${_("The photo(s) of you:")}
|
||||
|
||||
%for reason in reasons:
|
||||
%if reason.get('userPhotoReasons'):
|
||||
${_("The photo of you:")}
|
||||
<ul>
|
||||
%for item in reason.get('userPhotoReasons'):
|
||||
<li>${item}</li>
|
||||
%endfor
|
||||
</ul>
|
||||
%endif
|
||||
%if reason.get('photoIdReasons'):
|
||||
${_("The photo of your ID:")}
|
||||
<ul>
|
||||
%for item in reason.get('photoIdReasons'):
|
||||
<li>${item}</li>
|
||||
%endfor
|
||||
</ul>
|
||||
%endif
|
||||
%if reason.get('generalReasons'):
|
||||
${_("Other Reasons:")}
|
||||
<ul>
|
||||
%for item in reason.get('generalReasons'):
|
||||
<li>${item}</li>
|
||||
%endfor
|
||||
</ul>
|
||||
%endif
|
||||
%endfor
|
||||
|
||||
${_("Resubmit Verification: {reverify_url}").format(reverify_url=reverify_url)}
|
||||
${_("ID Verification FAQ: {faq_url}").format(faq_url=faq_url)}
|
||||
|
||||
${_("Thank you,")}
|
||||
${_("The {platform_name} team").format(platform_name=platform_name)}
|
||||
10
lms/templates/emails/passed_verification_email.txt
Normal file
10
lms/templates/emails/passed_verification_email.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
<%! 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)}
|
||||
Reference in New Issue
Block a user