diff --git a/lms/djangoapps/verify_student/tests/test_views.py b/lms/djangoapps/verify_student/tests/test_views.py index 3b44ffd1e4..742d91fb47 100644 --- a/lms/djangoapps/verify_student/tests/test_views.py +++ b/lms/djangoapps/verify_student/tests/test_views.py @@ -108,6 +108,97 @@ class TestVerifiedView(TestCase): self.assertIn('dashboard', response._headers.get('location')[1]) +@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +class TestCreateOrderView(TestCase): + """ + Tests for the create_order view of verified course registration process + """ + def setUp(self): + self.user = UserFactory.create(username="rusty", password="test") + self.client.login(username="rusty", password="test") + self.course_id = 'Robot/999/Test_Course' + CourseFactory.create(org='Robot', number='999', display_name='Test Course') + verified_mode = CourseMode( + course_id=self.course_id, + mode_slug="verified", + mode_display_name="Verified Certificate", + min_price=50 + ) + verified_mode.save() + course_mode_post_data = { + 'certificate_mode': 'Select Certificate', + 'contribution': 50, + 'contribution-other-amt': '', + 'explain': '' + } + self.client.post( + reverse("course_modes_choose", kwargs={'course_id': self.course_id}), + course_mode_post_data + ) + + def test_invalid_photos_data(self): + """ + Test that the invalid photo data cannot be submitted + """ + create_order_post_data = { + 'contribution': 50, + 'course_id': self.course_id, + 'face_image': '', + 'photo_id_image': '' + } + response = self.client.post(reverse('verify_student_create_order'), create_order_post_data) + json_response = json.loads(response.content) + self.assertFalse(json_response.get('success')) + + @patch.dict(settings.FEATURES, {'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING': True}) + def test_invalid_amount(self): + """ + Test that the user cannot give invalid amount + """ + create_order_post_data = { + 'contribution': '1.a', + 'course_id': self.course_id, + 'face_image': ',', + 'photo_id_image': ',' + } + response = self.client.post(reverse('verify_student_create_order'), create_order_post_data) + self.assertEquals(response.status_code, 400) + self.assertIn('Selected price is not valid number.', response.content) + + @patch.dict(settings.FEATURES, {'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING': True}) + def test_invalid_mode(self): + """ + Test that the course without verified mode cannot be processed + """ + course_id = 'Fake/999/Test_Course' + CourseFactory.create(org='Fake', number='999', display_name='Test Course') + create_order_post_data = { + 'contribution': '50', + 'course_id': course_id, + 'face_image': ',', + 'photo_id_image': ',' + } + response = self.client.post(reverse('verify_student_create_order'), create_order_post_data) + self.assertEquals(response.status_code, 400) + self.assertIn('This course doesn\'t support verified certificates', response.content) + + @patch.dict(settings.FEATURES, {'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING': True}) + def test_create_order_success(self): + """ + Test that the order is created successfully when given valid data + """ + create_order_post_data = { + 'contribution': 50, + 'course_id': self.course_id, + 'face_image': ',', + 'photo_id_image': ',' + } + response = self.client.post(reverse('verify_student_create_order'), create_order_post_data) + json_response = json.loads(response.content) + self.assertTrue(json_response.get('success')) + self.assertIsNotNone(json_response.get('orderNumber')) + + @override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) class TestReverifyView(TestCase): """ diff --git a/lms/djangoapps/verify_student/views.py b/lms/djangoapps/verify_student/views.py index c296911ec1..5cc09eb833 100644 --- a/lms/djangoapps/verify_student/views.py +++ b/lms/djangoapps/verify_student/views.py @@ -42,8 +42,8 @@ EVENT_NAME_USER_ENTERED_MIDCOURSE_REVERIFY_VIEW = 'edx.course.enrollment.reverif EVENT_NAME_USER_SUBMITTED_MIDCOURSE_REVERIFY = 'edx.course.enrollment.reverify.submitted' EVENT_NAME_USER_REVERIFICATION_REVIEWED_BY_SOFTWARESECURE = 'edx.course.enrollment.reverify.reviewed' -class VerifyView(View): +class VerifyView(View): @method_decorator(login_required) def get(self, request, course_id): """ @@ -54,7 +54,6 @@ class VerifyView(View): before proceeding to payment """ upgrade = request.GET.get('upgrade', False) - # If the user has already been verified within the given time period, # redirect straight to the payment -- no need to verify again. if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user): @@ -99,7 +98,7 @@ class VerifyView(View): "min_price": verify_mode.min_price, "upgrade": upgrade, } - + context['retake'] = request.GET.get('retake', False) return render_to_response('verify_student/photo_verification.html', context) @@ -108,6 +107,7 @@ class VerifiedView(View): View that gets shown once the user has already gone through the verification flow """ + @method_decorator(login_required) def get(self, request, course_id): """ @@ -145,9 +145,14 @@ def create_order(request): """ if not SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user): attempt = SoftwareSecurePhotoVerification(user=request.user) - b64_face_image = request.POST['face_image'].split(",")[1] - b64_photo_id_image = request.POST['photo_id_image'].split(",")[1] - + try: + b64_face_image = request.POST['face_image'].split(",")[1] + b64_photo_id_image = request.POST['photo_id_image'].split(",")[1] + except IndexError: + context = { + 'success': False, + } + return HttpResponse(json.dumps(context), content_type="text/json") attempt.upload_face_image(b64_face_image.decode('base64')) attempt.upload_photo_id_image(b64_photo_id_image.decode('base64')) attempt.mark_ready() @@ -182,7 +187,7 @@ def create_order(request): CertificateItem.add_to_order(cart, course_id, amount, 'verified') params = get_signed_purchase_params(cart) - + params['success'] = True return HttpResponse(json.dumps(params), content_type="text/json") @@ -298,6 +303,7 @@ class ReverifyView(View): Does not need to be attached to a particular course. Does not need to worry about pricing """ + @method_decorator(login_required) def get(self, request): """ @@ -351,6 +357,7 @@ class MidCourseReverifyView(View): Does not need to worry about pricing """ + @method_decorator(login_required) def get(self, request, course_id): """ @@ -425,8 +432,7 @@ def midcourse_reverify_dash(request): try: course_enrollment_pairs.append((course_from_id(enrollment.course_id), enrollment)) except ItemNotFoundError: - log.error("User {0} enrolled in non-existent course {1}" - .format(user.username, enrollment.course_id)) + log.error("User {0} enrolled in non-existent course {1}".format(user.username, enrollment.course_id)) statuses = ["approved", "pending", "must_reverify", "denied"] @@ -453,7 +459,6 @@ def toggle_failed_banner_off(request): return HttpResponse('Success') - @login_required def reverification_submission_confirmation(_request): """ diff --git a/lms/static/js/verify_student/photocapture.js b/lms/static/js/verify_student/photocapture.js index 3be1e57b16..00b17e2795 100644 --- a/lms/static/js/verify_student/photocapture.js +++ b/lms/static/js/verify_student/photocapture.js @@ -73,7 +73,15 @@ var submitToPaymentProcessing = function() { } ) .done(function(data) { - $("#pay_form").submit(); + if(data.success) { + $("#pay_form").submit(); + }else{ + if($(location).attr('href').indexOf("retake")<0) { + window.location.href=$(location).attr('href')+"&retake=True"; + }else { + location.reload(); + } + } }) .fail(function(jqXhr,text_status, error_thrown) { if(jqXhr.status == 400) { @@ -303,6 +311,7 @@ $(document).ready(function() { // when moving between steps $('#face_next_link').click(function(){ analytics.pageview("Capture ID Photo"); + $('#photo-error').hide(); $('body').addClass('step-photos-id').removeClass('step-photos-cam') }) diff --git a/lms/templates/verify_student/photo_verification.html b/lms/templates/verify_student/photo_verification.html index f683ff905f..a22f21d62f 100644 --- a/lms/templates/verify_student/photo_verification.html +++ b/lms/templates/verify_student/photo_verification.html @@ -56,7 +56,19 @@ - +%if retake: +
+
+ +
+

${_("Error processing your order")}

+
+

${_("Oops! Something went wrong. Please take your photos again. If you are still having trouble, please try again later.")}

+
+
+
+
+%endif