Merge pull request #34875 from openedx/michaelroytman/COSMO-310-idv-approval-email-in-command

Send IDV approval email in approve_id_verifications management command
This commit is contained in:
Michael Roytman
2024-05-31 07:10:03 -04:00
committed by GitHub
5 changed files with 115 additions and 21 deletions

View File

@@ -0,0 +1,35 @@
"""
API module.
"""
from django.conf import settings
from django.utils.translation import gettext as _
from lms.djangoapps.verify_student.emails import send_verification_approved_email
from lms.djangoapps.verify_student.tasks import send_verification_status_email
def send_approval_email(attempt):
"""
Send an approval email to the learner associated with the IDV attempt.
"""
verification_status_email_vars = {
'platform_name': settings.PLATFORM_NAME,
}
expiration_datetime = attempt.expiration_datetime.date()
if settings.VERIFY_STUDENT.get('USE_DJANGO_MAIL'):
verification_status_email_vars['expiration_datetime'] = expiration_datetime.strftime("%m/%d/%Y")
verification_status_email_vars['full_name'] = attempt.user.profile.name
subject = _("Your {platform_name} ID verification was approved!").format(
platform_name=settings.PLATFORM_NAME
)
context = {
'subject': subject,
'template': 'emails/passed_verification_email.txt',
'email': attempt.user.email,
'email_vars': verification_status_email_vars
}
send_verification_status_email.delay(context)
else:
email_context = {'user': attempt.user, 'expiration_datetime': expiration_datetime.strftime("%m/%d/%Y")}
send_verification_approved_email(context=email_context)

View File

@@ -11,6 +11,7 @@ from pprint import pformat
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.management.base import BaseCommand, CommandError
from lms.djangoapps.verify_student.api import send_approval_email
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
from lms.djangoapps.verify_student.utils import earliest_allowed_verification_date
@@ -125,8 +126,8 @@ class Command(BaseCommand):
def _approve_id_verifications(self, user_ids):
"""
This command manually approves ID verification attempts for a provided set of learners whose ID verification
attempt is in the submitted or must_retry state.
This method manually approves ID verification attempts for a provided set of user IDs so long as the attempt
is in the submitted or must_retry state. This method also send an IDV approval email to the user.
Arguments:
user_ids (list): user IDs of the users whose ID verification attempt should be manually approved
@@ -148,5 +149,6 @@ class Command(BaseCommand):
for verification in existing_id_verifications:
verification.approve(service='idv_verifications command')
send_approval_email(verification)
return list(failed_user_ids)

View File

@@ -8,6 +8,7 @@ import os
import tempfile
import pytest
from django.core import mail
from django.core.management import CommandError, call_command
from django.test import TestCase
from testfixtures import LogCapture
@@ -70,6 +71,35 @@ class TestApproveIDVerificationsCommand(TestCase):
assert SoftwareSecurePhotoVerification.objects.filter(status='approved').count() == 3
@ddt.data('submitted', 'must_retry')
def test_approve_id_verifications_email(self, status):
"""
Tests that the approve_id_verifications management command correctly sends approval emails.
"""
# Create SoftwareSecurePhotoVerification instances for the users.
for user in [self.user1_profile, self.user2_profile]:
SoftwareSecurePhotoVerification.objects.create(
user=user.user,
name=user.name,
status=status,
)
SoftwareSecurePhotoVerification.objects.create(
user=self.user3_profile.user,
name=self.user3_profile.name,
status='denied',
)
call_command('approve_id_verifications', self.tmp_file_path)
assert len(mail.outbox) == 2
# All three emails should have equal expiration dates, so just pick one from an attempt.
expiration_date = SoftwareSecurePhotoVerification.objects.first().expiration_datetime
for email in mail.outbox:
assert email.subject == 'Your édX ID verification was approved!'
assert 'Your édX ID verification photos have been approved' in email.body
assert expiration_date.strftime("%m/%d/%Y") in email.body
def test_user_does_not_exist_log(self):
"""
Tests that the approve_id_verifications management command logs an error when an invalid user ID is

View File

@@ -0,0 +1,43 @@
"""
Tests of API module.
"""
from unittest.mock import patch
import ddt
from django.conf import settings
from django.core import mail
from django.test import TestCase
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.verify_student.api import send_approval_email
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
@ddt.ddt
class TestSendApprovalEmail(TestCase):
"""
Test cases for the send_approval_email API method.
"""
def setUp(self):
super().setUp()
self.user = UserFactory.create()
self.attempt = SoftwareSecurePhotoVerification(
status="submitted",
user=self.user
)
self.attempt.save()
def _assert_verification_approved_email(self, expiration_date):
"""Check that a verification approved email was sent."""
assert len(mail.outbox) == 1
email = mail.outbox[0]
assert email.subject == 'Your édX ID verification was approved!'
assert 'Your édX ID verification photos have been approved' in email.body
assert expiration_date.strftime("%m/%d/%Y") in email.body
@ddt.data(True, False)
def test_send_approval(self, use_ace):
with patch.dict(settings.VERIFY_STUDENT, {'USE_DJANGO_MAIL': use_ace}):
send_approval_email(self.attempt)
self._assert_verification_approved_email(self.attempt.expiration_datetime)

View File

@@ -36,7 +36,8 @@ from common.djangoapps.util.db import outer_atomic
from common.djangoapps.util.json_request import JsonResponse
from common.djangoapps.util.views import require_global_staff
from lms.djangoapps.commerce.utils import EcommerceService, is_account_activation_requirement_disabled
from lms.djangoapps.verify_student.emails import send_verification_approved_email, send_verification_confirmation_email
from lms.djangoapps.verify_student.api import send_approval_email
from lms.djangoapps.verify_student.emails import send_verification_confirmation_email
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.tasks import send_verification_status_email
@@ -1117,24 +1118,7 @@ def results_callback(request): # lint-amnesty, pylint: disable=too-many-stateme
log.info("[COSMO-184] Approved verification for receipt_id={receipt_id}.".format(receipt_id=receipt_id))
attempt.approve()
expiration_datetime = attempt.expiration_datetime.date()
if settings.VERIFY_STUDENT.get('USE_DJANGO_MAIL'):
verification_status_email_vars['expiration_datetime'] = expiration_datetime.strftime("%m/%d/%Y")
verification_status_email_vars['full_name'] = user.profile.name
subject = _("Your {platform_name} ID verification was 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)
else:
email_context = {'user': user, 'expiration_datetime': expiration_datetime.strftime("%m/%d/%Y")}
send_verification_approved_email(context=email_context)
send_approval_email(attempt)
elif result == "FAIL":
log.debug("Denying verification for %s", receipt_id)