From 0a4d24adecbb23165b4e6472c5b79546e9707ef4 Mon Sep 17 00:00:00 2001 From: katrinan029 <71999631+katrinan029@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:35:39 +0000 Subject: [PATCH 1/3] feat: Upgrade Python dependency edx-enterprise version bump Commit generated by workflow `openedx/edx-platform/.github/workflows/upgrade-one-python-dependency.yml@refs/heads/master` --- requirements/constraints.txt | 2 +- requirements/edx/base.txt | 2 +- requirements/edx/development.txt | 2 +- requirements/edx/doc.txt | 2 +- requirements/edx/testing.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 3809b753a53..396b95d838e 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -26,7 +26,7 @@ celery>=5.2.2,<6.0.0 # The team that owns this package will manually bump this package rather than having it pulled in automatically. # This is to allow them to better control its deployment and to do it in a process that works better # for them. -edx-enterprise==4.27.0 +edx-enterprise==4.27.2 # Stay on LTS version, remove once this is added to common constraint Django<5.0 diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 0eca9a532ab..55793bd0c5a 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -467,7 +467,7 @@ edx-drf-extensions==10.4.0 # edx-when # edxval # openedx-learning -edx-enterprise==4.27.0 +edx-enterprise==4.27.2 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/kernel.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index abd99222532..1bdd3736516 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -741,7 +741,7 @@ edx-drf-extensions==10.4.0 # edx-when # edxval # openedx-learning -edx-enterprise==4.27.0 +edx-enterprise==4.27.2 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/doc.txt diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index f8b45c5ddcc..6f12d804675 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -547,7 +547,7 @@ edx-drf-extensions==10.4.0 # edx-when # edxval # openedx-learning -edx-enterprise==4.27.0 +edx-enterprise==4.27.2 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 7fa8962c4fd..d3b14a6f437 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -571,7 +571,7 @@ edx-drf-extensions==10.4.0 # edx-when # edxval # openedx-learning -edx-enterprise==4.27.0 +edx-enterprise==4.27.2 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt From f1a9286f731f20fde47ca3bdd797b3c615831536 Mon Sep 17 00:00:00 2001 From: Deborah Kaplan Date: Wed, 9 Oct 2024 09:45:05 -0400 Subject: [PATCH 2/3] chore: changing codeowners for several components (#35574) making sure the codeowners for some maintainership is accurate. --- .github/CODEOWNERS | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a05b78e8837..fc452f7acde 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -15,6 +15,7 @@ lms/djangoapps/grades/ lms/djangoapps/instructor/ lms/djangoapps/instructor_task/ lms/djangoapps/mobile_api/ +openedx/core/djangoapps/commerce/ @openedx/2u-infinity openedx/core/djangoapps/credentials @openedx/2U-aperture openedx/core/djangoapps/credit @openedx/2U-aperture openedx/core/djangoapps/enrollments/ @openedx/2U-aperture @@ -22,6 +23,7 @@ openedx/core/djangoapps/heartbeat/ openedx/core/djangoapps/oauth_dispatch openedx/core/djangoapps/user_api/ @openedx/2U-aperture openedx/core/djangoapps/user_authn/ @openedx/2U-vanguards +openedx/core/djangoapps/verified_track_content/ @openedx/2u-infinity openedx/features/course_experience/ xmodule/ @@ -36,16 +38,18 @@ common/djangoapps/track/ lms/djangoapps/certificates/ @openedx/2U-aperture # Discovery -common/djangoapps/course_modes/ +common/djangoapps/course_modes/ @openedx/2U-aperture common/djangoapps/enrollment/ -lms/djangoapps/branding/ @openedx/2U-aperture -lms/djangoapps/commerce/ -lms/djangoapps/experiments/ @openedx/2U-aperture -lms/djangoapps/learner_dashboard/ @openedx/2U-aperture -lms/djangoapps/learner_home/ @openedx/2U-aperture -openedx/features/content_type_gating/ +common/djangoapps/entitlements/ @openedx/2U-aperture +lms/djangoapps/branding/ @openedx/2U-aperture +lms/djangoapps/commerce/ @openedx/2u-infinity +lms/djangoapps/experiments/ @openedx/2u-infinity +lms/djangoapps/gating/ @openedx/2u-infinity +lms/djangoapps/learner_dashboard/ @openedx/2U-aperture +lms/djangoapps/learner_home/ @openedx/2U-aperture +openedx/features/content_type_gating/ @openedx/2u-infinity openedx/features/course_duration_limits/ -openedx/features/discounts/ +openedx/features/discounts/ @openedx/2u-infinity # Ping Axim On-call if someone uses the QuickStart # https://docs.openedx.org/en/latest/developers/quickstarts/first_openedx_pr.html 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 3/3] 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 3a08ede0aaf..4c45f415cf6 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 e6e580c1d1a..6eccee19479 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', + )