MST-542 Roll out Accounts MFE IDV workflow (#25613)
* MST-542 remove the IDV redirect to Account MFE waffle flag to permanently redirect learners to new IDV workflow. This completes the rollout process on edx-platform
This commit is contained in:
@@ -127,11 +127,9 @@ class ProgressTabView(RetrieveAPIView):
|
||||
verification_status = IDVerificationService.user_status(request.user)
|
||||
verification_link = None
|
||||
if verification_status['status'] is None or verification_status['status'] == 'expired':
|
||||
verification_link = IDVerificationService.get_verify_location('verify_student_verify_now',
|
||||
course_id=course_key)
|
||||
verification_link = IDVerificationService.get_verify_location(course_id=course_key)
|
||||
elif verification_status['status'] == 'must_reverify':
|
||||
verification_link = IDVerificationService.get_verify_location('verify_student_reverify',
|
||||
course_id=course_key)
|
||||
verification_link = IDVerificationService.get_verify_location(course_id=course_key)
|
||||
verification_data = {
|
||||
'link': verification_link,
|
||||
'status': verification_status['status'],
|
||||
|
||||
@@ -664,11 +664,11 @@ class VerificationDeadlineDate(DateSummary):
|
||||
'verification-deadline-passed': (_('Learn More'), ''),
|
||||
'verification-deadline-retry': (
|
||||
_('Retry Verification'),
|
||||
IDVerificationService.get_verify_location('verify_student_reverify'),
|
||||
IDVerificationService.get_verify_location(),
|
||||
),
|
||||
'verification-deadline-upcoming': (
|
||||
_('Verify My Identity'),
|
||||
IDVerificationService.get_verify_location('verify_student_verify_now', self.course_id),
|
||||
IDVerificationService.get_verify_location(self.course_id),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ from lms.djangoapps.courseware.models import (
|
||||
)
|
||||
from lms.djangoapps.experiments.testutils import override_experiment_waffle_flag
|
||||
from lms.djangoapps.verify_student.models import VerificationDeadline
|
||||
from lms.djangoapps.verify_student.services import IDVerificationService
|
||||
from lms.djangoapps.verify_student.tests.factories import SoftwareSecurePhotoVerificationFactory
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.schedules.signals import CREATE_SCHEDULE_WAFFLE_FLAG
|
||||
@@ -679,7 +680,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
|
||||
'You must successfully complete verification before this date to qualify for a Verified Certificate.'
|
||||
)
|
||||
self.assertEqual(block.link_text, 'Verify My Identity')
|
||||
self.assertEqual(block.link, reverse('verify_student_verify_now', args=(course.id,)))
|
||||
self.assertEqual(block.link, IDVerificationService.get_verify_location(course.id))
|
||||
|
||||
def test_verification_deadline_date_retry(self):
|
||||
with freeze_time('2015-01-02'):
|
||||
@@ -696,7 +697,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
|
||||
'You must successfully complete verification before this date to qualify for a Verified Certificate.'
|
||||
)
|
||||
self.assertEqual(block.link_text, 'Retry Verification')
|
||||
self.assertEqual(block.link, reverse('verify_student_reverify'))
|
||||
self.assertEqual(block.link, IDVerificationService.get_verify_location())
|
||||
|
||||
def test_verification_deadline_date_denied(self):
|
||||
with freeze_time('2015-01-02'):
|
||||
|
||||
@@ -17,7 +17,6 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_
|
||||
from common.djangoapps.student.models import User
|
||||
|
||||
from .models import ManualVerification, SoftwareSecurePhotoVerification, SSOVerification
|
||||
from .toggles import redirect_to_idv_microfrontend
|
||||
from .utils import earliest_allowed_verification_date, most_recent_verification, active_verifications
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -49,7 +48,7 @@ class XBlockVerificationService(object):
|
||||
"""
|
||||
Returns the URL for a user to verify themselves.
|
||||
"""
|
||||
return IDVerificationService.get_verify_location('verify_student_reverify')
|
||||
return IDVerificationService.get_verify_location()
|
||||
|
||||
|
||||
class IDVerificationService(object):
|
||||
@@ -232,24 +231,12 @@ class IDVerificationService(object):
|
||||
return 'ID Verified'
|
||||
|
||||
@classmethod
|
||||
def get_verify_location(cls, url_name, course_id=None):
|
||||
def get_verify_location(cls, course_id=None):
|
||||
"""
|
||||
url_name is one of:
|
||||
'verify_student_verify_now'
|
||||
'verify_student_reverify'
|
||||
|
||||
Returns a string:
|
||||
If waffle flag is active, returns URL for IDV microfrontend.
|
||||
Else, returns URL for corresponding view.
|
||||
Returns URL for IDV on Account Microfrontend
|
||||
"""
|
||||
location = ''
|
||||
if redirect_to_idv_microfrontend():
|
||||
location = '{}/id-verification'.format(settings.ACCOUNT_MICROFRONTEND_URL)
|
||||
if course_id:
|
||||
location = location + '?{}'.format(str(course_id))
|
||||
else:
|
||||
if course_id:
|
||||
location = reverse(url_name, args=[str(course_id)])
|
||||
else:
|
||||
location = reverse(url_name)
|
||||
location = '{}/id-verification'.format(settings.ACCOUNT_MICROFRONTEND_URL)
|
||||
if course_id:
|
||||
location = location + '?{}'.format(str(course_id))
|
||||
return location
|
||||
|
||||
@@ -6,12 +6,13 @@ import six
|
||||
from django.urls import reverse
|
||||
|
||||
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
|
||||
from lms.djangoapps.commerce.tests.mocks import mock_payment_processors
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
from ..services import IDVerificationService
|
||||
|
||||
|
||||
class TestProfEdVerification(ModuleStoreTestCase):
|
||||
"""
|
||||
@@ -34,31 +35,26 @@ class TestProfEdVerification(ModuleStoreTestCase):
|
||||
min_price=self.MIN_PRICE,
|
||||
suggested_prices=''
|
||||
)
|
||||
purchase_workflow = "?purchase_workflow=single"
|
||||
self.urls = {
|
||||
'course_modes_choose': reverse(
|
||||
'course_modes_choose',
|
||||
args=[six.text_type(self.course_key)]
|
||||
),
|
||||
|
||||
'verify_student_start_flow': reverse(
|
||||
'verify_student_start_flow',
|
||||
args=[six.text_type(self.course_key)]
|
||||
) + purchase_workflow,
|
||||
'verify_student_start_flow': IDVerificationService.get_verify_location(self.course_key),
|
||||
}
|
||||
|
||||
def test_start_flow(self):
|
||||
# Go to the course mode page, expecting a redirect to the intro step of the
|
||||
# payment flow (since this is a professional ed course). Otherwise, the student
|
||||
# would have the option to choose their track.
|
||||
with mock_payment_processors():
|
||||
resp = self.client.get(self.urls['course_modes_choose'], follow=True)
|
||||
self.assertRedirects(resp, self.urls['verify_student_start_flow'])
|
||||
resp = self.client.get(self.urls['course_modes_choose'])
|
||||
self.assertRedirects(
|
||||
resp,
|
||||
self.urls['verify_student_start_flow'],
|
||||
fetch_redirect_response=False,
|
||||
)
|
||||
|
||||
# For professional ed courses, expect that the student is NOT enrolled
|
||||
# automatically in the course.
|
||||
self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course_key))
|
||||
|
||||
# On the first page of the flow, verify that there's a button allowing the user
|
||||
# to proceed to the payment processor; this is the only action the user is allowed to take.
|
||||
self.assertContains(resp, 'payment-button')
|
||||
|
||||
@@ -32,6 +32,7 @@ from lms.djangoapps.commerce.tests import TEST_API_URL, TEST_PAYMENT_DATA, TEST_
|
||||
from lms.djangoapps.commerce.tests.mocks import mock_payment_processors
|
||||
from lms.djangoapps.commerce.utils import EcommerceService
|
||||
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification, VerificationDeadline
|
||||
from lms.djangoapps.verify_student.services import IDVerificationService
|
||||
from lms.djangoapps.verify_student.views import PayAndVerifyView, checkout_with_ecommerce_service, render_to_response
|
||||
from openedx.core.djangoapps.embargo.test_utils import restrict_course
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme
|
||||
@@ -959,9 +960,8 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin, Tes
|
||||
|
||||
def _assert_redirects_to_verify_start(self, response, course_id, status_code=302):
|
||||
"""Check that the page redirects to the "verify later" part of the flow. """
|
||||
url = reverse('verify_student_verify_now', kwargs={'course_id': six.text_type(course_id)})
|
||||
with mock_payment_processors():
|
||||
self.assertRedirects(response, url, status_code)
|
||||
url = IDVerificationService.get_verify_location(course_id=course_id)
|
||||
self.assertRedirects(response, url, status_code, fetch_redirect_response=False)
|
||||
|
||||
def _assert_redirects_to_upgrade(self, response, course_id):
|
||||
"""Check that the page redirects to the "upgrade" part of the flow. """
|
||||
@@ -1713,13 +1713,13 @@ class TestReverifyView(TestVerificationBase):
|
||||
"""
|
||||
Test that a User can use re-verify link for initial verification.
|
||||
"""
|
||||
self._assert_can_reverify()
|
||||
self._assert_reverify()
|
||||
|
||||
def test_reverify_view_can_reverify_denied(self):
|
||||
# User has a denied attempt, so can re-verify
|
||||
attempt = self.create_and_submit_attempt_for_user(self.user)
|
||||
attempt.deny("error")
|
||||
self._assert_can_reverify()
|
||||
self._assert_reverify()
|
||||
|
||||
def test_reverify_view_can_reverify_expired(self):
|
||||
# User has a verification attempt, but it's expired
|
||||
@@ -1731,7 +1731,7 @@ class TestReverifyView(TestVerificationBase):
|
||||
attempt.save()
|
||||
|
||||
# Allow the student to re-verify
|
||||
self._assert_can_reverify()
|
||||
self._assert_reverify()
|
||||
|
||||
def test_reverify_view_can_reverify_pending(self):
|
||||
""" Test that the user can still re-verify even if the previous photo
|
||||
@@ -1746,7 +1746,7 @@ class TestReverifyView(TestVerificationBase):
|
||||
self.create_and_submit_attempt_for_user(self.user)
|
||||
|
||||
# Can re-verify because an attempt has already been submitted.
|
||||
self._assert_can_reverify()
|
||||
self._assert_reverify()
|
||||
|
||||
def test_reverify_view_cannot_reverify_approved(self):
|
||||
# Submitted attempt has been approved
|
||||
@@ -1754,7 +1754,7 @@ class TestReverifyView(TestVerificationBase):
|
||||
attempt.approve()
|
||||
|
||||
# Cannot re-verify because the user is already verified.
|
||||
self._assert_cannot_reverify()
|
||||
self._assert_reverify()
|
||||
|
||||
@override_settings(VERIFY_STUDENT={"DAYS_GOOD_FOR": 5, "EXPIRING_SOON_WINDOW": 10})
|
||||
def test_reverify_view_can_reverify_approved_expired_soon(self):
|
||||
@@ -1768,25 +1768,10 @@ class TestReverifyView(TestVerificationBase):
|
||||
attempt.approve()
|
||||
|
||||
# Can re-verify because verification is set to expired soon.
|
||||
self._assert_can_reverify()
|
||||
self._assert_reverify()
|
||||
|
||||
def _get_reverify_page(self):
|
||||
"""
|
||||
Retrieve the re-verification page and return the response.
|
||||
"""
|
||||
def _assert_reverify(self):
|
||||
url = reverse("verify_student_reverify")
|
||||
return self.client.get(url)
|
||||
|
||||
def _assert_can_reverify(self):
|
||||
"""
|
||||
Check that the re-verification flow is rendered.
|
||||
"""
|
||||
response = self._get_reverify_page()
|
||||
self.assertContains(response, "reverify-container")
|
||||
|
||||
def _assert_cannot_reverify(self):
|
||||
"""
|
||||
Check that the user is blocked from re-verifying.
|
||||
"""
|
||||
response = self._get_reverify_page()
|
||||
self.assertContains(response, "reverify-blocked")
|
||||
response = self.client.get(url)
|
||||
verification_start_url = IDVerificationService.get_verify_location()
|
||||
self.assertRedirects(response, verification_start_url, fetch_redirect_response=False)
|
||||
|
||||
@@ -27,24 +27,3 @@ USE_NEW_EMAIL_TEMPLATES = WaffleFlag(
|
||||
|
||||
def use_new_templates_for_id_verification_emails():
|
||||
return USE_NEW_EMAIL_TEMPLATES.is_enabled()
|
||||
|
||||
|
||||
# Waffle flag to redirect to the new IDV flow on the account microfrontend
|
||||
# .. toggle_name: verify_student.redirect_to_idv_microfrontend
|
||||
# .. toggle_implementation: WaffleFlag
|
||||
# .. toggle_default: False
|
||||
# .. toggle_description: Supports staged rollout to students for the new IDV flow.
|
||||
# .. toggle_use_cases: temporary, open_edx
|
||||
# .. toggle_creation_date: 2020-07-09
|
||||
# .. toggle_target_removal_date: None
|
||||
# .. toggle_warnings: This temporary feature toggle does not have a target removal date.
|
||||
# .. toggle_tickets: MST-318
|
||||
REDIRECT_TO_IDV_MICROFRONTEND = WaffleFlag(
|
||||
waffle_namespace=WAFFLE_FLAG_NAMESPACE,
|
||||
flag_name='redirect_to_idv_microfrontend',
|
||||
module_name=__name__,
|
||||
)
|
||||
|
||||
|
||||
def redirect_to_idv_microfrontend():
|
||||
return REDIRECT_TO_IDV_MICROFRONTEND.is_enabled()
|
||||
|
||||
@@ -52,7 +52,6 @@ from common.djangoapps.util.json_request import JsonResponse
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
from .services import IDVerificationService
|
||||
from .toggles import redirect_to_idv_microfrontend
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -499,10 +498,7 @@ class PayAndVerifyView(View):
|
||||
if is_enrolled:
|
||||
if already_paid:
|
||||
# If the student has paid, but not verified, redirect to the verification flow.
|
||||
url = IDVerificationService.get_verify_location(
|
||||
'verify_student_verify_now',
|
||||
six.text_type(course_key)
|
||||
)
|
||||
url = IDVerificationService.get_verify_location(six.text_type(course_key))
|
||||
else:
|
||||
url = reverse('verify_student_start_flow', kwargs=course_kwargs)
|
||||
|
||||
@@ -1216,19 +1212,5 @@ class ReverifyView(View):
|
||||
Most of the work is done client-side by composing the same
|
||||
Backbone views used in the initial verification flow.
|
||||
"""
|
||||
verification_status = IDVerificationService.user_status(request.user)
|
||||
expiration_datetime = IDVerificationService.get_expiration_datetime(request.user, ['approved'])
|
||||
if can_verify_now(verification_status, expiration_datetime):
|
||||
if redirect_to_idv_microfrontend():
|
||||
return redirect('{}/id-verification'.format(settings.ACCOUNT_MICROFRONTEND_URL))
|
||||
context = {
|
||||
"user_full_name": request.user.profile.name,
|
||||
"platform_name": configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
|
||||
"capture_sound": staticfiles_storage.url("audio/camera_capture.wav"),
|
||||
}
|
||||
return render_to_response("verify_student/reverify.html", context)
|
||||
else:
|
||||
context = {
|
||||
"status": verification_status['status']
|
||||
}
|
||||
return render_to_response("verify_student/reverify_not_allowed.html", context)
|
||||
IDV_workflow = IDVerificationService.get_verify_location()
|
||||
return redirect(IDV_workflow)
|
||||
|
||||
Reference in New Issue
Block a user