From 243b1b4e2e6e065b685f678556164d5dcd47eb67 Mon Sep 17 00:00:00 2001 From: Alison Langston <46360176+alangsto@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:16:02 -0400 Subject: [PATCH] feat: update management command to manually create verified names (#35619) * feat: update management command to manually create verified names * fix: update function name --- .../commands/approve_id_verifications.py | 34 +++++++++++ .../tests/test_approve_id_verifications.py | 59 +++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/lms/djangoapps/verify_student/management/commands/approve_id_verifications.py b/lms/djangoapps/verify_student/management/commands/approve_id_verifications.py index 3a08ede0aaf6..4c45f415cf63 100644 --- a/lms/djangoapps/verify_student/management/commands/approve_id_verifications.py +++ b/lms/djangoapps/verify_student/management/commands/approve_id_verifications.py @@ -10,9 +10,11 @@ from django.core.management.base import BaseCommand, CommandError +from common.djangoapps.student.models_api import get_name, get_pending_name_change 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 +from openedx.features.name_affirmation_api.utils import get_name_affirmation_service log = logging.getLogger(__name__) @@ -149,5 +151,37 @@ def _approve_id_verifications(self, user_ids): for verification in existing_id_verifications: verification.approve(service='idv_verifications command') send_approval_email(verification) + self._approve_verified_name_for_software_secure_verification(verification) return list(failed_user_ids) + + def _approve_verified_name_for_software_secure_verification(self, verification): + """ + This method manually creates a verified name given a SoftwareSecurePhotoVerification object. + """ + + name_affirmation_service = get_name_affirmation_service() + + if name_affirmation_service: + from edx_name_affirmation.exceptions import VerifiedNameDoesNotExist # pylint: disable=import-error + + pending_name_change = get_pending_name_change(verification.user) + if pending_name_change: + full_name = pending_name_change.new_name + else: + full_name = get_name(verification.user.id) + + try: + name_affirmation_service.update_verified_name_status( + verification.user, + 'approved', + verification_attempt_id=verification.id + ) + except VerifiedNameDoesNotExist: + name_affirmation_service.create_verified_name( + verification.user, + verification.name, + full_name, + verification_attempt_id=verification.id, + status='approved', + ) diff --git a/lms/djangoapps/verify_student/management/commands/tests/test_approve_id_verifications.py b/lms/djangoapps/verify_student/management/commands/tests/test_approve_id_verifications.py index e6e580c1d1a6..6eccee194795 100644 --- a/lms/djangoapps/verify_student/management/commands/tests/test_approve_id_verifications.py +++ b/lms/djangoapps/verify_student/management/commands/tests/test_approve_id_verifications.py @@ -6,6 +6,8 @@ import logging import os import tempfile +from unittest import skipUnless +from unittest.mock import MagicMock, patch import pytest from django.core import mail @@ -15,9 +17,12 @@ from common.djangoapps.student.tests.factories import UserFactory, UserProfileFactory from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification +from openedx.features.name_affirmation_api.utils import get_name_affirmation_service LOGGER_NAME = 'lms.djangoapps.verify_student.management.commands.approve_id_verifications' +name_affirmation_service = get_name_affirmation_service() + @ddt.ddt class TestApproveIDVerificationsCommand(TestCase): @@ -158,3 +163,57 @@ def test_invalid_file_path(self): """ with pytest.raises(CommandError): call_command('approve_id_verifications', 'invalid/user_id/file/path') + + @skipUnless(name_affirmation_service is not None, 'Requires Name Affirmation') + @patch('lms.djangoapps.verify_student.management.commands.approve_id_verifications.get_name_affirmation_service') + def test_create_verified_names(self, mock_get_service): + mock_service = MagicMock() + mock_get_service.return_value = mock_service + + verification = SoftwareSecurePhotoVerification.objects.create( + user=self.user1_profile.user, + name=self.user1_profile.name, + status='submitted', + ) + + call_command('approve_id_verifications', self.tmp_file_path) + mock_service.update_verified_name_status.assert_called_with( + self.user1_profile.user, + 'approved', + verification_attempt_id=verification.id, + ) + + @skipUnless(name_affirmation_service is not None, 'Requires Name Affirmation') + @patch('lms.djangoapps.verify_student.management.commands.approve_id_verifications.get_name') + @patch('lms.djangoapps.verify_student.management.commands.approve_id_verifications.get_pending_name_change') + @patch('lms.djangoapps.verify_student.management.commands.approve_id_verifications.get_name_affirmation_service') + @ddt.data( + '', + MagicMock(new_name='test') + ) + def test_create_update_verified_names(self, pending_name, mock_get_service, mock_get_pending, mock_get_name): + from edx_name_affirmation.exceptions import VerifiedNameDoesNotExist # pylint: disable=import-error + + mock_service = MagicMock() + mock_get_service.return_value = mock_service + mock_service.update_verified_name_status.side_effect = VerifiedNameDoesNotExist() + + mock_get_pending.return_value = pending_name + mock_get_name.return_value = self.user1_profile.name + + verification = SoftwareSecurePhotoVerification.objects.create( + user=self.user1_profile.user, + name=self.user1_profile.name, + status='submitted', + ) + + expected_name = 'test' if pending_name else self.user1_profile.name + + call_command('approve_id_verifications', self.tmp_file_path) + mock_service.create_verified_name.assert_called_with( + verification.user, + verification.name, + expected_name, + verification_attempt_id=verification.id, + status='approved', + )