feat: add signal emitters for IDV (#28511)

MST-805. A signal should be emitted upon an IDV attempt being submitted or reviewed for consumption by other applications.
This commit is contained in:
alangsto
2021-08-26 15:29:48 -04:00
committed by GitHub
parent 0b4aaa90c7
commit b6cb629849
2 changed files with 68 additions and 0 deletions

View File

@@ -3,7 +3,9 @@ Signal handler for setting default course verification dates
"""
from django.db.models.signals import post_save
from django.core.exceptions import ObjectDoesNotExist
from django.dispatch import Signal
from django.dispatch.dispatcher import receiver
from openedx.core.djangoapps.user_api.accounts.signals import USER_RETIRE_LMS_CRITICAL
@@ -12,6 +14,10 @@ from xmodule.modulestore.django import SignalHandler, modulestore
from .models import SoftwareSecurePhotoVerification, VerificationDeadline
# Signal for emitting IDV submission and review updates
idv_update_signal = Signal(providing_args=["attempt_id", "user_id", "status", "full_name", "profile_name"])
@receiver(SignalHandler.course_published)
def _listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument
"""
@@ -32,3 +38,21 @@ def _listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable
def _listen_for_lms_retire(sender, **kwargs): # pylint: disable=unused-argument
user = kwargs.get('user')
SoftwareSecurePhotoVerification.retire_user(user.id)
@receiver(post_save, sender=SoftwareSecurePhotoVerification)
def send_idv_update(sender, instance, **kwargs): # pylint: disable=unused-argument
"""
Catches the post save signal from the SoftwareSecurePhotoVerification model, and emits
another signal with limited information from the model. We are choosing to re-emit a signal
as opposed to relying only on the post_save signal to avoid the chance that other apps
import the SoftwareSecurePhotoVerification model.
"""
idv_update_signal.send(
sender='idv_update',
attempt_id=instance.id,
user_id=instance.user.id,
status=instance.status,
full_name=instance.name,
profile_name=instance.user.profile.name
)

View File

@@ -6,6 +6,7 @@ Unit tests for the VerificationDeadline signals
from datetime import timedelta
from django.utils.timezone import now
from unittest.mock import patch
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification, VerificationDeadline
@@ -102,3 +103,46 @@ class RetirementSignalTest(ModuleStoreTestCase):
# All values for this user should now be empty string
for field in ('name', 'face_image_url', 'photo_id_image_url', 'photo_id_key'):
assert '' == getattr(ver_obj, field)
class PostSavePhotoVerificationTest(ModuleStoreTestCase):
"""
Tests for the post_save signal on the SoftwareSecurePhotoVerification model.
This receiver should emit another signal that contains limited data about
the verification attempt that was updated.
"""
@patch('lms.djangoapps.verify_student.signals.idv_update_signal.send')
def test_post_save_signal(self, mock_signal):
user = UserFactory.create()
# create new softwaresecureverification
attempt = SoftwareSecurePhotoVerification.objects.create(
user=user,
name='Bob Doe',
face_image_url='https://test.face',
photo_id_image_url='https://test.photo',
photo_id_key='test+key'
)
self.assertTrue(mock_signal.called)
mock_signal.assert_called_with(
sender='idv_update',
attempt_id=attempt.id,
user_id=attempt.user.id,
status=attempt.status,
full_name=attempt.name,
profile_name=attempt.user.profile.name
)
mock_signal.reset_mock()
attempt.mark_ready()
self.assertTrue(mock_signal.called)
mock_signal.assert_called_with(
sender='idv_update',
attempt_id=attempt.id,
user_id=attempt.user.id,
status=attempt.status,
full_name=attempt.name,
profile_name=attempt.user.profile.name
)