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:
@@ -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.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.dispatch import Signal
|
||||||
from django.dispatch.dispatcher import receiver
|
from django.dispatch.dispatcher import receiver
|
||||||
|
|
||||||
from openedx.core.djangoapps.user_api.accounts.signals import USER_RETIRE_LMS_CRITICAL
|
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
|
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)
|
@receiver(SignalHandler.course_published)
|
||||||
def _listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument
|
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
|
def _listen_for_lms_retire(sender, **kwargs): # pylint: disable=unused-argument
|
||||||
user = kwargs.get('user')
|
user = kwargs.get('user')
|
||||||
SoftwareSecurePhotoVerification.retire_user(user.id)
|
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
|
||||||
|
)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Unit tests for the VerificationDeadline signals
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
from common.djangoapps.student.tests.factories import UserFactory
|
from common.djangoapps.student.tests.factories import UserFactory
|
||||||
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification, VerificationDeadline
|
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
|
# All values for this user should now be empty string
|
||||||
for field in ('name', 'face_image_url', 'photo_id_image_url', 'photo_id_key'):
|
for field in ('name', 'face_image_url', 'photo_id_image_url', 'photo_id_key'):
|
||||||
assert '' == getattr(ver_obj, field)
|
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
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user