diff --git a/cms/djangoapps/contentstore/management/commands/delete_orphans.py b/cms/djangoapps/contentstore/management/commands/delete_orphans.py new file mode 100644 index 0000000000..202f8c2057 --- /dev/null +++ b/cms/djangoapps/contentstore/management/commands/delete_orphans.py @@ -0,0 +1,42 @@ +"""Script for deleting orphans""" +from django.core.management.base import BaseCommand, CommandError +from contentstore.views.item import _delete_orphans +from opaque_keys.edx.keys import CourseKey +from opaque_keys import InvalidKeyError +from xmodule.modulestore import ModuleStoreEnum + + +class Command(BaseCommand): + """Command for deleting orphans""" + help = ''' + Delete orphans from a MongoDB backed course. Takes two arguments: + : the course id of the course whose orphans you want to delete + |commit|: optional argument. If not provided, will not run task. + ''' + + def handle(self, *args, **options): + if len(args) not in {1, 2}: + raise CommandError("delete_orphans requires one or more arguments: |commit|") + + try: + course_key = CourseKey.from_string(args[0]) + except InvalidKeyError: + raise CommandError("Invalid course key.") + + commit = False + if len(args) == 2: + commit = args[1] == 'commit' + + if commit: + print 'Deleting orphans from the course:' + deleted_items = _delete_orphans( + course_key, ModuleStoreEnum.UserID.mgmt_command, commit + ) + print "Success! Deleted the following orphans from the course:" + print "\n".join(deleted_items) + else: + print 'Dry run. The following orphans would have been deleted from the course:' + deleted_items = _delete_orphans( + course_key, ModuleStoreEnum.UserID.mgmt_command, commit + ) + print "\n".join(deleted_items) diff --git a/cms/djangoapps/contentstore/management/commands/tests/test_delete_orphans.py b/cms/djangoapps/contentstore/management/commands/tests/test_delete_orphans.py new file mode 100644 index 0000000000..649c4e7fb0 --- /dev/null +++ b/cms/djangoapps/contentstore/management/commands/tests/test_delete_orphans.py @@ -0,0 +1,40 @@ +"""Tests running the delete_orphan command""" + +from django.core.management import call_command +from contentstore.tests.test_orphan import TestOrphanBase + + +class TestDeleteOrphan(TestOrphanBase): + """ + Tests for running the delete_orphan management command. + Inherits from TestOrphan in order to use its setUp method. + """ + def setUp(self): + super(TestDeleteOrphan, self).setUp() + self.course_id = self.course.id.to_deprecated_string() + + def test_delete_orphans_no_commit(self): + """ + Tests that running the command without a 'commit' argument + results in no orphans being deleted + """ + call_command('delete_orphans', self.course_id) + self.assertTrue(self.store.has_item(self.course.id.make_usage_key('html', 'multi_parent_html'))) + self.assertTrue(self.store.has_item(self.course.id.make_usage_key('vertical', 'OrphanVert'))) + self.assertTrue(self.store.has_item(self.course.id.make_usage_key('chapter', 'OrphanChapter'))) + self.assertTrue(self.store.has_item(self.course.id.make_usage_key('html', 'OrphanHtml'))) + + def test_delete_orphans_commit(self): + """ + Tests that running the command WITH the 'commit' argument + results in the orphans being deleted + """ + call_command('delete_orphans', self.course_id, 'commit') + + # make sure this module wasn't deleted + self.assertTrue(self.store.has_item(self.course.id.make_usage_key('html', 'multi_parent_html'))) + + # and make sure that these were + self.assertFalse(self.store.has_item(self.course.id.make_usage_key('vertical', 'OrphanVert'))) + self.assertFalse(self.store.has_item(self.course.id.make_usage_key('chapter', 'OrphanChapter'))) + self.assertFalse(self.store.has_item(self.course.id.make_usage_key('html', 'OrphanHtml'))) diff --git a/cms/djangoapps/contentstore/tests/test_orphan.py b/cms/djangoapps/contentstore/tests/test_orphan.py index 1b0c2f3281..4dede3f71c 100644 --- a/cms/djangoapps/contentstore/tests/test_orphan.py +++ b/cms/djangoapps/contentstore/tests/test_orphan.py @@ -8,47 +8,60 @@ from xmodule.modulestore.django import modulestore from contentstore.utils import reverse_course_url -class TestOrphan(CourseTestCase): +class TestOrphanBase(CourseTestCase): + """ + Base class for Studio tests that require orphaned modules + """ + def setUp(self): + super(TestOrphanBase, self).setUp() + + # create chapters and add them to course tree + chapter1 = self.store.create_child(self.user.id, self.course.location, 'chapter', "Chapter1") + self.store.publish(chapter1.location, self.user.id) + + chapter2 = self.store.create_child(self.user.id, self.course.location, 'chapter', "Chapter2") + self.store.publish(chapter2.location, self.user.id) + + # orphan chapter + orphan_chapter = self.store.create_item(self.user.id, self.course.id, 'chapter', "OrphanChapter") + self.store.publish(orphan_chapter.location, self.user.id) + + # create vertical and add it as child to chapter1 + vertical1 = self.store.create_child(self.user.id, chapter1.location, 'vertical', "Vertical1") + self.store.publish(vertical1.location, self.user.id) + + # create orphan vertical + orphan_vertical = self.store.create_item(self.user.id, self.course.id, 'vertical', "OrphanVert") + self.store.publish(orphan_vertical.location, self.user.id) + + # create component and add it to vertical1 + html1 = self.store.create_child(self.user.id, vertical1.location, 'html', "Html1") + self.store.publish(html1.location, self.user.id) + + # create component and add it as a child to vertical1 and orphan_vertical + multi_parent_html = self.store.create_child(self.user.id, vertical1.location, 'html', "multi_parent_html") + self.store.publish(multi_parent_html.location, self.user.id) + + orphan_vertical.children.append(multi_parent_html.location) + self.store.update_item(orphan_vertical, self.user.id) + + # create an orphaned html module + orphan_html = self.store.create_item(self.user.id, self.course.id, 'html', "OrphanHtml") + self.store.publish(orphan_html.location, self.user.id) + + self.store.create_child(self.user.id, self.course.location, 'static_tab', "staticuno") + self.store.create_child(self.user.id, self.course.location, 'about', "overview") + self.store.create_child(self.user.id, self.course.location, 'course_info', "updates") + + +class TestOrphan(TestOrphanBase): """ Test finding orphans via view and django config """ def setUp(self): super(TestOrphan, self).setUp() - - runtime = self.course.runtime - - self._create_item('chapter', 'Chapter1', {}, {'display_name': 'Chapter 1'}, 'course', self.course.location.name, runtime) - self._create_item('chapter', 'Chapter2', {}, {'display_name': 'Chapter 2'}, 'course', self.course.location.name, runtime) - self._create_item('chapter', 'OrphanChapter', {}, {'display_name': 'Orphan Chapter'}, None, None, runtime) - self._create_item('vertical', 'Vert1', {}, {'display_name': 'Vertical 1'}, 'chapter', 'Chapter1', runtime) - self._create_item('vertical', 'OrphanVert', {}, {'display_name': 'Orphan Vertical'}, None, None, runtime) - self._create_item('html', 'Html1', "

Goodbye

", {'display_name': 'Parented Html'}, 'vertical', 'Vert1', runtime) - self._create_item('html', 'OrphanHtml', "

Hello

", {'display_name': 'Orphan html'}, None, None, runtime) - self._create_item('static_tab', 'staticuno', "

tab

", {'display_name': 'Tab uno'}, None, None, runtime) - self._create_item('about', 'overview', "

overview

", {}, None, None, runtime) - self._create_item('course_info', 'updates', "
  1. Sep 22

    test

", {}, None, None, runtime) - self.orphan_url = reverse_course_url('orphan_handler', self.course.id) - def _create_item(self, category, name, data, metadata, parent_category, parent_name, runtime): - location = self.course.location.replace(category=category, name=name) - store = modulestore() - store.create_item( - self.user.id, - location.course_key, - location.block_type, - location.block_id, - definition_data=data, - metadata=metadata, - runtime=runtime - ) - if parent_name: - # add child to parent in mongo - parent_location = self.course.location.replace(category=parent_category, name=parent_name) - parent = store.get_item(parent_location) - parent.children.append(location) - store.update_item(parent, self.user.id) - def test_mongo_orphan(self): """ Test that old mongo finds the orphans @@ -77,6 +90,10 @@ class TestOrphan(CourseTestCase): ) self.assertEqual(len(orphans), 0, "Orphans not deleted {}".format(orphans)) + # make sure that any children with one orphan parent and one non-orphan + # parent are not deleted + self.assertTrue(self.store.has_item(self.course.id.make_usage_key('html', "multi_parent_html"))) + def test_not_permitted(self): """ Test that auth restricts get and delete appropriately diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py index 28c9a5e480..2e6528ed0d 100644 --- a/cms/djangoapps/contentstore/views/item.py +++ b/cms/djangoapps/contentstore/views/item.py @@ -604,16 +604,27 @@ def orphan_handler(request, course_key_string): raise PermissionDenied() if request.method == 'DELETE': if request.user.is_staff: - store = modulestore() - items = store.get_orphans(course_usage_key) - for itemloc in items: - # need to delete all versions - store.delete_item(itemloc, request.user.id, revision=ModuleStoreEnum.RevisionOption.all) - return JsonResponse({'deleted': [unicode(item) for item in items]}) + deleted_items = _delete_orphans(course_usage_key, request.user.id, commit=True) + return JsonResponse({'deleted': deleted_items}) else: raise PermissionDenied() +def _delete_orphans(course_usage_key, user_id, commit=False): + """ + Helper function to delete orphans for a given course. + If `commit` is False, this function does not actually remove + the orphans. + """ + store = modulestore() + items = store.get_orphans(course_usage_key) + if commit: + for itemloc in items: + # need to delete all versions + store.delete_item(itemloc, user_id, revision=ModuleStoreEnum.RevisionOption.all) + return [unicode(item) for item in items] + + def _get_xblock(usage_key, user): """ Returns the xblock for the specified usage key. Note: if failing to find a key with a category diff --git a/cms/envs/common.py b/cms/envs/common.py index 0c7d5157d7..0d3b637acc 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -775,10 +775,13 @@ ADVANCED_COMPONENT_TYPES = [ 'audio', # Embed an audio file. See https://github.com/pmitros/AudioXBlock 'recommender', # Crowdsourced recommender. Prototype by dli&pmitros. Intended for roll-out in one place in one course. 'profile', # Prototype user profile XBlock. Used to test XBlock parameter passing. See https://github.com/pmitros/ProfileXBlock + 'split_test', 'combinedopenended', 'peergrading', 'notes', + 'schoolyourself_review', + 'schoolyourself_lesson', ] # Adding components in this list will disable the creation of new problem for those diff --git a/common/lib/xmodule/xmodule/modulestore/mongo/draft.py b/common/lib/xmodule/xmodule/modulestore/mongo/draft.py index 4f2c1360df..76ce0a6db4 100644 --- a/common/lib/xmodule/xmodule/modulestore/mongo/draft.py +++ b/common/lib/xmodule/xmodule/modulestore/mongo/draft.py @@ -541,7 +541,7 @@ class DraftModuleStore(MongoModuleStore): ) self._delete_subtree(location, as_functions) - def _delete_subtree(self, location, as_functions): + def _delete_subtree(self, location, as_functions, draft_only=False): """ Internal method for deleting all of the subtree whose revisions match the as_functions """ @@ -555,10 +555,23 @@ class DraftModuleStore(MongoModuleStore): next_tier = [] for child_loc in current_entry.get('definition', {}).get('children', []): child_loc = course_key.make_usage_key_from_deprecated_string(child_loc) - for rev_func in as_functions: - current_loc = rev_func(child_loc) - current_son = current_loc.to_deprecated_son() - next_tier.append(current_son) + + # single parent can have 2 versions: draft and published + # get draft parents only while deleting draft module + if draft_only: + revision = MongoRevisionKey.draft + else: + revision = ModuleStoreEnum.RevisionOption.all + + parents = self._get_raw_parent_locations(child_loc, revision) + # Don't delete modules if one of its parents shouldn't be deleted + # This should only be an issue for courses have ended up in + # a state where modules have multiple parents + if all(parent.to_deprecated_son() in to_be_deleted for parent in parents): + for rev_func in as_functions: + current_loc = rev_func(child_loc) + current_son = current_loc.to_deprecated_son() + next_tier.append(current_son) return next_tier @@ -738,7 +751,7 @@ class DraftModuleStore(MongoModuleStore): # If 2 versions versions exist, we can assume one is a published version. Go ahead and do the delete # of the draft version. if versions_found.count() > 1: - self._delete_subtree(root_location, [as_draft]) + self._delete_subtree(root_location, [as_draft], draft_only=True) elif versions_found.count() == 1: # Since this method cannot be called on something in DIRECT_ONLY_CATEGORIES and we call # delete_subtree as soon as we find an item with a draft version, if there is only 1 version diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py index 0bdef107b5..2b70cb7584 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py @@ -723,7 +723,7 @@ class TestMixedModuleStore(CourseComparisonTest): # Split: # queries: active_versions, draft and published structures, definition (unnecessary) # sends: update published (why?), draft, and active_versions - @ddt.data(('draft', 8, 2), ('split', 2, 2)) + @ddt.data(('draft', 9, 2), ('split', 2, 2)) @ddt.unpack def test_delete_private_vertical(self, default_ms, max_find, max_send): """ diff --git a/lms/djangoapps/shoppingcart/tests/test_views.py b/lms/djangoapps/shoppingcart/tests/test_views.py index eff77f1747..0b0750ff36 100644 --- a/lms/djangoapps/shoppingcart/tests/test_views.py +++ b/lms/djangoapps/shoppingcart/tests/test_views.py @@ -910,7 +910,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): # Two courses in user shopping cart self.login_user() - item1 = PaidCourseRegistration.add_to_order(self.cart, self.course_key) + PaidCourseRegistration.add_to_order(self.cart, self.course_key) item2 = PaidCourseRegistration.add_to_order(self.cart, self.testing_course.id) self.assertEquals(self.cart.orderitem_set.count(), 2) @@ -1217,7 +1217,14 @@ class ReceiptRedirectTest(UrlResetMixin, ModuleStoreTestCase): @patch.dict(settings.FEATURES, {'SEPARATE_VERIFICATION_FROM_PAYMENT': True}) def test_show_receipt_redirect_to_verify_student(self): + # Create other carts first + # This ensures that the order ID and order item IDs do not match + Order.get_cart_for_user(self.user).start_purchase() + Order.get_cart_for_user(self.user).start_purchase() + Order.get_cart_for_user(self.user).start_purchase() + # Purchase a verified certificate + self.cart = Order.get_cart_for_user(self.user) CertificateItem.add_to_order( self.cart, self.course_key, diff --git a/lms/djangoapps/shoppingcart/views.py b/lms/djangoapps/shoppingcart/views.py index 1da5c24bfc..f2a54457f5 100644 --- a/lms/djangoapps/shoppingcart/views.py +++ b/lms/djangoapps/shoppingcart/views.py @@ -818,7 +818,7 @@ def _show_receipt_html(request, order): # Add a query string param for the order ID # This allows the view to query for the receipt information later. url += '?payment-order-num={order_num}'.format( - order_num=order_items[0].id + order_num=order_items[0].order.id ) return HttpResponseRedirect(url) diff --git a/lms/static/js/spec/verify_student/make_payment_step_view_spec.js b/lms/static/js/spec/verify_student/make_payment_step_view_spec.js index 01abb15433..eb0fa26ecb 100644 --- a/lms/static/js/spec/verify_student/make_payment_step_view_spec.js +++ b/lms/static/js/spec/verify_student/make_payment_step_view_spec.js @@ -86,16 +86,10 @@ define([ }; var expectPaymentDisabledBecauseInactive = function() { - var payButton = $( '#pay_button'), - activateButton = $( '#activate_button' ); + var payButton = $( '#pay_button' ); // Payment button should be hidden expect( payButton.length ).toEqual(0); - - // Activate button should be displayed and disabled - expect( activateButton.length ).toEqual(1); - expect( activateButton.hasClass( 'is-disabled' ) ).toBe( true ); - expect( activateButton.prop( 'disabled' ) ).toBe( true ); }; var goToPayment = function( requests, kwargs ) { diff --git a/lms/static/js/spec/verify_student/webcam_photo_view_spec.js b/lms/static/js/spec/verify_student/webcam_photo_view_spec.js index 5f4d4a99f5..9a4fc13c71 100644 --- a/lms/static/js/spec/verify_student/webcam_photo_view_spec.js +++ b/lms/static/js/spec/verify_student/webcam_photo_view_spec.js @@ -158,7 +158,7 @@ define([ view = createView( backends ); // Expect an error - expect( view.errorModel.get( 'errorTitle' ) ).toEqual( 'No Flash Detected' ); + expect( view.errorModel.get( 'errorTitle' ) ).toEqual( 'Flash Not Detected' ); expect( view.errorModel.get( 'errorMsg' ) ).toContain( 'Get Flash' ); expect( view.errorModel.get( 'shown' ) ).toBe( true ); diff --git a/lms/static/js/student_account/views/AccessView.js b/lms/static/js/student_account/views/AccessView.js index 4796834b3a..7bcc13a4c5 100644 --- a/lms/static/js/student_account/views/AccessView.js +++ b/lms/static/js/student_account/views/AccessView.js @@ -172,7 +172,9 @@ var edx = edx || {}; toggleForm: function( e ) { var type = $(e.currentTarget).data('type'), $form = $('#' + type + '-form'), - $anchor = $('#' + type + '-anchor'); + $anchor = $('#' + type + '-anchor'), + queryParams = url('?'), + queryStr = queryParams.length > 0 ? '?' + queryParams : ''; e.preventDefault(); @@ -190,7 +192,7 @@ var edx = edx || {}; this.element.scrollTop( $anchor ); // Update url without reloading page - History.pushState( null, document.title, '/account/' + type + '/' ); + History.pushState( null, document.title, '/account/' + type + '/' + queryStr ); analytics.page( 'login_and_registration', type ); }, diff --git a/lms/static/js/verify_student/pay_and_verify.js b/lms/static/js/verify_student/pay_and_verify.js index f5fe75c7d7..803596fa11 100644 --- a/lms/static/js/verify_student/pay_and_verify.js +++ b/lms/static/js/verify_student/pay_and_verify.js @@ -55,7 +55,7 @@ var edx = edx || {}; minPrice: el.data('course-mode-min-price'), contributionAmount: el.data('contribution-amount'), suggestedPrices: _.filter( - (el.data('course-mode-suggested-prices') || "").split(","), + (el.data('course-mode-suggested-prices').toString()).split(","), function( price ) { return Boolean( price ); } ), currency: el.data('course-mode-currency'), diff --git a/lms/static/js/verify_student/views/make_payment_step_view.js b/lms/static/js/verify_student/views/make_payment_step_view.js index 1bf65c9bee..ad519a9cc1 100644 --- a/lms/static/js/verify_student/views/make_payment_step_view.js +++ b/lms/static/js/verify_student/views/make_payment_step_view.js @@ -38,11 +38,6 @@ var edx = edx || {}; // Set the payment button to disabled by default this.setPaymentEnabled( false ); - // The activate button is always disabled - $( '#activate_button' ) - .addClass( 'is-disabled' ) - .prop( 'disabled', true ); - // Update the contribution amount with the amount the user // selected in a previous screen. if ( templateContext.contributionAmount ) { @@ -140,7 +135,7 @@ var edx = edx || {}; }, handleCreateOrderError: function( xhr ) { - var errorMsg = gettext( 'An unexpected error occurred. Please try again.' ); + var errorMsg = gettext( 'An error has occurred. Please try again.' ); if ( xhr.status === 400 ) { errorMsg = xhr.responseText; diff --git a/lms/static/js/verify_student/views/review_photos_step_view.js b/lms/static/js/verify_student/views/review_photos_step_view.js index 87713352af..2cbaba592b 100644 --- a/lms/static/js/verify_student/views/review_photos_step_view.js +++ b/lms/static/js/verify_student/views/review_photos_step_view.js @@ -66,7 +66,7 @@ var edx = edx || {}; }, handleSubmissionError: function( xhr ) { - var errorMsg = gettext( 'An unexpected error occurred. Please try again later.' ); + var errorMsg = gettext( 'An error has occurred. Please try again later.' ); // Re-enable the submit button to allow the user to retry this.setSubmitButtonEnabled( true ); diff --git a/lms/static/js/verify_student/views/step_view.js b/lms/static/js/verify_student/views/step_view.js index 794726a672..96ad8c2d4f 100644 --- a/lms/static/js/verify_student/views/step_view.js +++ b/lms/static/js/verify_student/views/step_view.js @@ -46,7 +46,7 @@ handleError: function( errorTitle, errorMsg ) { this.errorModel.set({ errorTitle: errorTitle || gettext( "Error" ), - errorMsg: errorMsg || gettext( "An unexpected error occurred. Please reload the page to try again." ), + errorMsg: errorMsg || gettext( "An error has occurred. Please try reloading the page." ), shown: true }); }, diff --git a/lms/static/js/verify_student/views/webcam_photo_view.js b/lms/static/js/verify_student/views/webcam_photo_view.js index c40df11788..34cd46958d 100644 --- a/lms/static/js/verify_student/views/webcam_photo_view.js +++ b/lms/static/js/verify_student/views/webcam_photo_view.js @@ -85,8 +85,8 @@ handleVideoFailure: function() { this.trigger( 'error', - gettext( 'Video capture error' ), - gettext( 'Please check that your webcam is connected and you have allowed access to your webcam.' ) + gettext( 'Video Capture Error' ), + gettext( 'Please verify that your webcam is connected and that you have allowed your browser to access it.' ) ); } }, @@ -211,7 +211,7 @@ if ( !this.backend ) { this.handleError( - gettext( "No Flash Detected" ), + gettext( "Flash Not Detected" ), gettext( "You don't seem to have Flash installed." ) + " " + _.sprintf( gettext( "%(a_start)s Get Flash %(a_end)s to continue your enrollment." ), diff --git a/lms/static/sass/views/_decoupled-verification.scss b/lms/static/sass/views/_decoupled-verification.scss index 5f6a4bf014..7cdef0bf63 100644 --- a/lms/static/sass/views/_decoupled-verification.scss +++ b/lms/static/sass/views/_decoupled-verification.scss @@ -23,6 +23,12 @@ } } + .placeholder-cam { + .copy { + font-weight: bold !important; + } + } + .requirements-container { .list-reqs { @@ -41,7 +47,7 @@ } &.account-not-activated { - width: 990px; + width: 300px; .req { height: 290px; @@ -75,6 +81,7 @@ display: inline; float: left; line-height: 45px; + color: black; } .wizard-steps { @@ -119,11 +126,23 @@ .expandable-area { margin-top: 5px; + padding-bottom: 20px; } } .help-tips { margin-left: 0 !important; + + .title { + font-size: 16px !important; + } + + .list-tips { + .tip { + font-size: 16px; + line-height: 1.5em; + } + } } .photo-tip { @@ -137,6 +156,12 @@ padding-left: 20px; } + .list-faq { + dd { + color: black; + } + } + .wrapper-task { .msg-retake { margin-top: 0; diff --git a/lms/templates/shoppingcart/registration_code_redemption.html b/lms/templates/shoppingcart/registration_code_redemption.html index d8ac9fc56e..f21f0b1b2f 100644 --- a/lms/templates/shoppingcart/registration_code_redemption.html +++ b/lms/templates/shoppingcart/registration_code_redemption.html @@ -22,6 +22,7 @@ from courseware.courses import course_image_url, get_course_about_section course_number=course.display_number_with_default, course_title=get_course_about_section(course, 'title'), )}" /> +
${_("Confirm your enrollment for:")} ${_("course dates")} diff --git a/lms/templates/verify_student/enrollment_confirmation_step.underscore b/lms/templates/verify_student/enrollment_confirmation_step.underscore index b0d2de9d96..55d26ed69a 100644 --- a/lms/templates/verify_student/enrollment_confirmation_step.underscore +++ b/lms/templates/verify_student/enrollment_confirmation_step.underscore @@ -47,7 +47,7 @@
diff --git a/lms/templates/verify_student/face_photo_step.underscore b/lms/templates/verify_student/face_photo_step.underscore index 405fd5dc35..f0ff6a3a5c 100644 --- a/lms/templates/verify_student/face_photo_step.underscore +++ b/lms/templates/verify_student/face_photo_step.underscore @@ -2,7 +2,7 @@

<%- gettext( "Take Your Photo" ) %>

-

<%- gettext( "Use your webcam to take a picture of your face so we can match it with the picture on your ID." ) %>

+

<%- gettext( "Use your webcam to take a photo of your face. We will match this photo with the photo on your ID." ) %>

@@ -17,7 +17,7 @@
  • <%- gettext( "Make sure your face is well-lit" ) %>
  • <%- gettext( "Be sure your entire face is inside the frame" ) %>
  • - <%= _.sprintf( gettext( "Once in position, use the camera button %(icon)s to capture your picture" ), { icon: '()' } ) %> + <%= _.sprintf( gettext( "Once in position, use the camera button %(icon)s to capture your photo" ), { icon: '()' } ) %>
  • <%- gettext( "Can we match the photo you took with the one on your ID?" ) %>
  • <%- gettext( "Use the retake photo button if you are not pleased with your photo" ) %>
  • @@ -26,17 +26,17 @@
    -

    <%- gettext( "Common Questions" ) %>

    +

    <%- gettext( "Frequently Asked Questions" ) %>

    <%- _.sprintf( gettext( "Why does %(platformName)s need my photo?" ), { platformName: platformName } ) %>
    -
    <%- gettext( "As part of the verification process, we need your photo to confirm your identity." ) %>
    +
    <%- gettext( "As part of the verification process, you take a photo of both your face and a government-issued photo ID. Our authorization service confirms your identity by comparing the photo you take with the photo on your ID." ) %>
    - <%- _.sprintf( gettext( "What does %(platformName)s do with this picture?" ), { platformName: platformName } ) %> + <%- _.sprintf( gettext( "What does %(platformName)s do with this photo?" ), { platformName: platformName } ) %>
    -
    <%- gettext( "We encrypt it and send it to our secure authorization service for review. We use the highest levels of security and do not save the photo or information anywhere once the match has been completed." ) %>
    +
    <%- _.sprintf( gettext( "We use the highest levels of security available to encrypt your photo and send it to our authorization service for review. Your photo and information are not saved or visible anywhere on %(platformName)s after the verification process is complete." ), { platformName: platformName } ) %>
    diff --git a/lms/templates/verify_student/id_photo_step.underscore b/lms/templates/verify_student/id_photo_step.underscore index 22ef73bff6..265bac5abf 100644 --- a/lms/templates/verify_student/id_photo_step.underscore +++ b/lms/templates/verify_student/id_photo_step.underscore @@ -2,7 +2,7 @@

    <%- gettext( "Take a Photo of Your ID" ) %>

    -

    <%- gettext("Use your webcam to take a picture of your ID so we can match it with your photo and the name on your account.") %>

    +

    <%- gettext("Use your webcam to take a photo of your ID. We will match this photo with the photo of your face and the name on your account.") %>

    @@ -27,19 +27,19 @@
    -

    <%- gettext( "Common Questions" ) %>

    +

    <%- gettext( "Frequently Asked Questions" ) %>

    <%- _.sprintf( gettext( "Why does %(platformName)s need my photo?" ), { platformName: platformName } ) %>
    -
    <%- gettext( "We need to match your ID with your photo and name to confirm your identity." ) %>
    +
    <%- gettext( "As part of the verification process, you take a photo of both your face and a government-issued photo ID. Our authorization service confirms your identity by comparing the photo you take with the photo on your ID." ) %>
    - <%- _.sprintf( gettext( "What does %(platformName)s do with this picture?" ), { platformName: platformName } ) %> + <%- _.sprintf( gettext( "What does %(platformName)s do with this photo?" ), { platformName: platformName } ) %>
    -
    <%- gettext( "We encrypt it and send it to our secure authorization service for review. We use the highest levels of security and do not save the photo or information anywhere once the match has been completed." ) %>
    +
    <%- _.sprintf( gettext( "We use the highest levels of security available to encrypt your photo and send it to our authorization service for review. Your photo and information are not saved or visible anywhere on %(platformName)s after the verification process is complete." ), { platformName: platformName } ) %>
    diff --git a/lms/templates/verify_student/intro_step.underscore b/lms/templates/verify_student/intro_step.underscore index b85e35792e..fc235907e6 100644 --- a/lms/templates/verify_student/intro_step.underscore +++ b/lms/templates/verify_student/intro_step.underscore @@ -9,7 +9,13 @@ <% } else { %>

    <%- introTitle %>

    - <% if ( introMsg ) { %> + <% if ( !isActive ) { %> +
    +

    + <%- gettext( "You need to activate your account before you can enroll in courses. Check your inbox for an activation email. After you complete activation you can return and refresh this page." ) %> +

    +
    + <% } else if ( introMsg ) { %>

    <%- introMsg %>

    <% } %> <% } %> @@ -17,69 +23,63 @@
      <% if ( requirements['account-activation-required'] ) { %> -
    • -

      <%- gettext( "Activate Your Account" ) %>

      -
      - -
      +
    • +

      <%- gettext( "Activate Your Account" ) %>

      +
      + +
      -
      -

      - <%- gettext( "Check your email" ) %> - <%- - gettext( "You need to activate your account before you can register for courses. Check your inbox for an activation email." ) - %> - -

      -
      -
    • - <% } %> +
      +

      + <%- gettext( "Check Your Email" ) %> +

      +
      + + <% } else { %> + <% if ( requirements['photo-id-required'] ) { %> +
    • +

      <%- gettext( "Photo ID" ) %>

      +
      + + +
      - <% if ( requirements['photo-id-required'] ) { %> -
    • -

      <%- gettext( "Photo ID" ) %>

      -
      - - -
      +
      +

      + <%- gettext( "A driver's license, passport, or other government-issued ID with your name and photo" ) %> +

      +
      +
    • + <% } %> -
      -

      - <%- gettext( "A driver's license, passport, or government-issued ID with your name and picture" ) %> -

      -
      - - <% } %> + <% if ( requirements['webcam-required'] ) { %> +
    • +

      <%- gettext( "Webcam" ) %>

      +
      + +
      - <% if ( requirements['webcam-required'] ) { %> -
    • -

      <%- gettext( "Webcam" ) %>

      -
      - -
      - -
      -
    • +
      + + <% } %> <% } %>
    - <% if ( nextStepTitle ) { %> + <% if ( nextStepTitle && isActive ) { %> diff --git a/lms/templates/verify_student/make_payment_step.underscore b/lms/templates/verify_student/make_payment_step.underscore index e5ee1cc1bb..c04afcacd7 100644 --- a/lms/templates/verify_student/make_payment_step.underscore +++ b/lms/templates/verify_student/make_payment_step.underscore @@ -15,7 +15,7 @@ ) %>
    - <%- gettext( "We've already verified your identity through the photos of you and your ID you provided earlier. You can now pay and complete registration." ) %> + <%- gettext( "We have successfully verified your identity. You can now enter your payment information and complete your enrollment." ) %>
    <% } %> @@ -79,7 +79,7 @@ <% } else {%>
  • -

    <%- gettext( "Your Course Total" ) %>

    +

    <%- gettext( "Your Total Contribution" ) %>

    <%- gettext( "To complete your enrollment, you will need to pay:" ) %>

    @@ -105,6 +105,8 @@ gettext( "You can pay now even if you don't have the following items available, but you will need to have these by %(date)s to qualify to earn a Verified Certificate." ), { date: verificationDeadline } ) %> + <% } else if ( !isActive ) { %> + <%- gettext( "You need to activate your account before you can enroll in courses. Check your inbox for an activation email. After you complete activation you can return and refresh this page." ) %> <% } else if ( !upgrade ) { %> <%- gettext( "You can pay now even if you don't have the following items available, but you will need to have these to qualify to earn a Verified Certificate." ) %> <% } %> @@ -116,66 +118,60 @@
      <% if ( requirements['account-activation-required'] ) { %> -
    • -

      <%- gettext( "Activate Your Account" ) %>

      -
      - -
      +
    • +

      <%- gettext( "Activate Your Account" ) %>

      +
      + +
      -
      -

      - <%- gettext( "Check your email" ) %> - <%- - gettext( "You need to activate your account before you can enroll in courses. Check your inbox for an activation email." ) - %> - -

      -
      -
    • - <% } %> +
      +

      + <%- gettext( "Check Your Email" ) %> +

      +
      + + <% } else {%> + <% if ( requirements['photo-id-required'] ) { %> +
    • +

      <%- gettext( "Government-Issued Photo ID" ) %>

      +
      + + +
      - <% if ( requirements['photo-id-required'] ) { %> -
    • -

      <%- gettext( "Government-issued Photo ID" ) %>

      -
      - - -
      +
      +
    • + <% } %> -
      - - <% } %> + <% if ( requirements['webcam-required'] ) { %> +
    • +

      <%- gettext( "Webcam" ) %>

      +
      + +
      - <% if ( requirements['webcam-required'] ) { %> -
    • -

      <%- gettext( "Webcam" ) %>

      -
      - -
      - -
      -
    • +
      + + <% } %> <% } %>
    <% } %> + <% if ( isActive ) { %> + <% } %>
  • diff --git a/lms/templates/verify_student/pay_and_verify.html b/lms/templates/verify_student/pay_and_verify.html index a807722137..d5aef5cf8f 100644 --- a/lms/templates/verify_student/pay_and_verify.html +++ b/lms/templates/verify_student/pay_and_verify.html @@ -76,6 +76,7 @@ from verify_student.views import PayAndVerifyView data-is-active='${is_active}' >
    + % if is_active: ## Support
    + % endif
    diff --git a/lms/templates/verify_student/payment_confirmation_step.underscore b/lms/templates/verify_student/payment_confirmation_step.underscore index 615f3d57c2..780b715334 100644 --- a/lms/templates/verify_student/payment_confirmation_step.underscore +++ b/lms/templates/verify_student/payment_confirmation_step.underscore @@ -1,7 +1,7 @@

    - <%= _.sprintf( gettext( "Thank you! We have received your payment for %(courseName)s" ), { courseName: '' + courseName + '' } ) %> + <%= _.sprintf( gettext( "Thank you! We have received your payment for %(courseName)s." ), { courseName: '' + courseName + '' } ) %>

    <% if ( receipt ) { %> @@ -55,14 +55,14 @@

    <%- gettext( "Please Note" ) %>:

    -

    <%- gettext( "Items with strikethough have been refunded." ) %>

    +

    <%- gettext( "Crossed out items have been refunded." ) %>

    <% } %>
    -

    <%- gettext( "Billed To" ) %>: +

    <%- gettext( "Billed to" ) %>: <%- receipt.billedTo.firstName %> <%- receipt.billedTo.lastName %> (<%- receipt.billedTo.city %>, @@ -74,7 +74,7 @@ <% } else { %> -

    <%- gettext( "No receipt available." ) %>

    +

    <%- gettext( "No receipt available" ) %>

    <% } %> <% if ( nextStepTitle ) { %> @@ -83,49 +83,49 @@
      <% if ( requirements['account-activation-required'] ) { %> -
    • -

      <%- gettext( "Activate Your Account" ) %>

      -
      - -
      +
    • +

      <%- gettext( "Activate Your Account" ) %>

      +
      + +
      -
      -

      - <%- gettext( "Check your email." ) %> - <%- - gettext( "You need to activate your account before you can enroll in courses. Check your inbox for an activation email." ) - %> - -

      -
      -
    • - <% } %> +
      +

      + <%- gettext( "Check your email" ) %> + <%- + gettext( "You need to activate your account before you can enroll in courses. Check your inbox for an activation email." ) + %> + +

      +
      + + <% } else { %> + <% if ( requirements['photo-id-required'] ) { %> +
    • +

      <%- gettext( "Photo ID" ) %>

      +
      + + +
      - <% if ( requirements['photo-id-required'] ) { %> -
    • -

      <%- gettext( "Photo ID" ) %>

      -
      - - -
      +
      +

      + <%- gettext( "A driver's license, passport, or government-issued ID with your name and photo." ) %> +

      +
      +
    • + <% } %> -
      -

      - <%- gettext( "A driver's license, passport, or government-issued ID with your name and picture." ) %> -

      -
      - - <% } %> + <% if ( requirements['webcam-required'] ) { %> +
    • +

      <%- gettext( "Webcam" ) %>

      +
      + +
      - <% if ( requirements['webcam-required'] ) { %> -
    • -

      <%- gettext( "Webcam" ) %>

      -
      - -
      - -
      -
    • +
      + + <% } %> <% } %>
    @@ -141,7 +141,7 @@ ) %> - diff --git a/lms/templates/verify_student/review_photos_step.underscore b/lms/templates/verify_student/review_photos_step.underscore index 5c3a80ca0d..73421fc980 100644 --- a/lms/templates/verify_student/review_photos_step.underscore +++ b/lms/templates/verify_student/review_photos_step.underscore @@ -1,8 +1,8 @@
    -

    <%- gettext( "Review your photos" ) %>

    +

    <%- gettext( "Review Your Photos" ) %>

    -

    <%- gettext( "Make sure we can verify your identity from the photos below." ) %>

    +

    <%- gettext( "Make sure we can verify your identity with the photos and information you have provided." ) %>

    @@ -30,12 +30,12 @@
  • <%- _.sprintf( gettext( "Does the name on your ID match your account name: %(fullName)s?" ), { fullName: fullName } ) %>
  • @@ -48,7 +48,7 @@

    <%- gettext( "Photos don't meet the requirements?" ) %> - <%- gettext( "Retake your photos" ) %> + <%- gettext( "Retake Your Photos" ) %>

    diff --git a/lms/templates/verify_student/webcam_photo.underscore b/lms/templates/verify_student/webcam_photo.underscore index cdaaffdbc0..47fa3bebdb 100644 --- a/lms/templates/verify_student/webcam_photo.underscore +++ b/lms/templates/verify_student/webcam_photo.underscore @@ -9,11 +9,11 @@