Commit aeff0880 by Will Daly

Merge pull request #7453 from edx/will/ecom-1198

ECOM-1198: Login/Registration page can skip track selection.
parents e1251bfe 735b4009
...@@ -246,13 +246,26 @@ class StudentAccountLoginAndRegistrationTest(UrlResetMixin, ModuleStoreTestCase) ...@@ -246,13 +246,26 @@ class StudentAccountLoginAndRegistrationTest(UrlResetMixin, ModuleStoreTestCase)
'course_id': 'edX/DemoX/Demo_Course' 'course_id': 'edX/DemoX/Demo_Course'
} }
with mock.patch.dict(settings.FEATURES, {'IS_EDX_DOMAIN': is_edx_domain}):
response = self.client.get(reverse(url_name), params)
# The response should have a "Sign In" button with the URL # The response should have a "Sign In" button with the URL
# that preserves the querystring params # that preserves the querystring params
with mock.patch.dict(settings.FEATURES, {'IS_EDX_DOMAIN': is_edx_domain}):
response = self.client.get(reverse(url_name), params)
self.assertContains(response, "login?course_id=edX%2FDemoX%2FDemo_Course&enrollment_action=enroll") self.assertContains(response, "login?course_id=edX%2FDemoX%2FDemo_Course&enrollment_action=enroll")
# Add an additional "course mode" parameter
params['course_mode'] = 'honor'
# Verify that this parameter is also preserved
with mock.patch.dict(settings.FEATURES, {'IS_EDX_DOMAIN': is_edx_domain}):
response = self.client.get(reverse(url_name), params)
expected_url = (
"login?course_id=edX%2FDemoX%2FDemo_Course"
"&enrollment_action=enroll"
"&course_mode=honor"
)
self.assertContains(response, expected_url)
@mock.patch.dict(settings.FEATURES, {"ENABLE_THIRD_PARTY_AUTH": False}) @mock.patch.dict(settings.FEATURES, {"ENABLE_THIRD_PARTY_AUTH": False})
@ddt.data("account_login", "account_register") @ddt.data("account_login", "account_register")
def test_third_party_auth_disabled(self, url_name): def test_third_party_auth_disabled(self, url_name):
......
...@@ -91,7 +91,8 @@ def login_and_registration_form(request, initial_mode="login"): ...@@ -91,7 +91,8 @@ def login_and_registration_form(request, initial_mode="login"):
# We need to pass these parameters so that the header's # We need to pass these parameters so that the header's
# "Sign In" button preserves the querystring params. # "Sign In" button preserves the querystring params.
'enrollment_action': request.GET.get('enrollment_action'), 'enrollment_action': request.GET.get('enrollment_action'),
'course_id': request.GET.get('course_id') 'course_id': request.GET.get('course_id'),
'course_mode': request.GET.get('course_mode'),
} }
return render_to_response('student_account/login_and_register.html', context) return render_to_response('student_account/login_and_register.html', context)
......
...@@ -166,7 +166,52 @@ define([ ...@@ -166,7 +166,52 @@ define([
view.subview.login.trigger('auth-complete'); view.subview.login.trigger('auth-complete');
// Expect that the view tried to enroll the student // Expect that the view tried to enroll the student
expect( EnrollmentInterface.enroll ).toHaveBeenCalledWith( COURSE_KEY ); expect( EnrollmentInterface.enroll ).toHaveBeenCalledWith(
COURSE_KEY,
'/course_modes/choose/' + COURSE_KEY + '/'
);
});
it('sends the user to the payment flow when the course mode is not honor', function() {
ajaxSpyAndInitialize(this, 'login');
// Simulate providing enrollment query string params
// AND specifying a course mode.
setFakeQueryParams({
'?enrollment_action': 'enroll',
'?course_id': COURSE_KEY,
'?course_mode': 'verified'
});
// Trigger auth complete on the login view
view.subview.login.trigger('auth-complete');
// Expect that the view tried to auto-enroll the student
// with a redirect into the payment flow.
expect( EnrollmentInterface.enroll ).toHaveBeenCalledWith(
COURSE_KEY,
'/verify_student/start-flow/' + COURSE_KEY + '/'
);
});
it('sends the user to the student dashboard when the course mode is honor', function() {
ajaxSpyAndInitialize(this, 'login');
// Simulate providing enrollment query string params
// AND specifying a course mode.
setFakeQueryParams({
'?enrollment_action': 'enroll',
'?course_id': COURSE_KEY,
'?course_mode': 'honor'
});
// Trigger auth complete on the login view
view.subview.login.trigger('auth-complete');
// Expect that the view tried auto-enrolled the student
// and sent the student to the dashboard
// (skipping the payment flow).
expect( EnrollmentInterface.enroll ).toHaveBeenCalledWith(COURSE_KEY, '/dashboard');
}); });
it('adds a white-label course to the shopping cart on auth complete', function() { it('adds a white-label course to the shopping cart on auth complete', function() {
......
...@@ -19,7 +19,7 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'], ...@@ -19,7 +19,7 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'],
var requests = AjaxHelpers.requests( this ); var requests = AjaxHelpers.requests( this );
// Attempt to enroll the user // Attempt to enroll the user
EnrollmentInterface.enroll( COURSE_KEY ); EnrollmentInterface.enroll( COURSE_KEY, FORWARD_URL );
// Expect that the correct request was made to the server // Expect that the correct request was made to the server
AjaxHelpers.expectRequest( AjaxHelpers.expectRequest(
...@@ -41,7 +41,7 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'], ...@@ -41,7 +41,7 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'],
var requests = AjaxHelpers.requests( this ); var requests = AjaxHelpers.requests( this );
// Attempt to enroll the user // Attempt to enroll the user
EnrollmentInterface.enroll( COURSE_KEY ); EnrollmentInterface.enroll( COURSE_KEY, FORWARD_URL );
// Simulate an error response from the server // Simulate an error response from the server
AjaxHelpers.respondWithError(requests); AjaxHelpers.respondWithError(requests);
...@@ -55,7 +55,7 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'], ...@@ -55,7 +55,7 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'],
var requests = AjaxHelpers.requests( this ); var requests = AjaxHelpers.requests( this );
// Attempt to enroll the user // Attempt to enroll the user
EnrollmentInterface.enroll( COURSE_KEY ); EnrollmentInterface.enroll( COURSE_KEY, FORWARD_URL );
// Simulate an error response (403) from the server // Simulate an error response (403) from the server
// with a "user_message_url" parameter for the redirect. // with a "user_message_url" parameter for the redirect.
......
...@@ -10,7 +10,6 @@ var edx = edx || {}; ...@@ -10,7 +10,6 @@ var edx = edx || {};
urls: { urls: {
orders: '/commerce/orders/', orders: '/commerce/orders/',
trackSelection: '/course_modes/choose/'
}, },
headers: { headers: {
...@@ -18,11 +17,11 @@ var edx = edx || {}; ...@@ -18,11 +17,11 @@ var edx = edx || {};
}, },
/** /**
* Enroll a user in a course, then redirect the user * Enroll a user in a course, then redirect the user.
* to the track selection page.
* @param {string} courseKey Slash-separated course key. * @param {string} courseKey Slash-separated course key.
* @param {string} redirectUrl The URL to redirect to once enrollment completes.
*/ */
enroll: function( courseKey ) { enroll: function( courseKey, redirectUrl ) {
var data_obj = {course_id: courseKey}, var data_obj = {course_id: courseKey},
data = JSON.stringify(data_obj); data = JSON.stringify(data_obj);
...@@ -42,31 +41,23 @@ var edx = edx || {}; ...@@ -42,31 +41,23 @@ var edx = edx || {};
// If so, redirect to a page explaining to the user // If so, redirect to a page explaining to the user
// why they were blocked. // why they were blocked.
this.redirect( responseData.user_message_url ); this.redirect( responseData.user_message_url );
} } else {
else { // Otherwise, redirect the user to the next page.
// Otherwise, go to the track selection page as usual. if ( redirectUrl ) {
// This can occur, for example, when a course does not this.redirect( redirectUrl );
// have a free enrollment mode, so we can't auto-enroll. }
this.redirect( this.trackSelectionUrl( courseKey ) );
} }
}) })
.done(function() { .done(function() {
// If we successfully enrolled, go to the track selection // If we successfully enrolled, redirect the user
// page to allow the user to choose a paid enrollment mode. // to the next page (usually the student dashboard or payment flow)
this.redirect( this.trackSelectionUrl( courseKey ) ); if ( redirectUrl ) {
this.redirect( redirectUrl );
}
}); });
}, },
/** /**
* Construct the URL to the track selection page for a course.
* @param {string} courseKey Slash-separated course key.
* @return {string} The URL to the track selection page.
*/
trackSelectionUrl: function( courseKey ) {
return this.urls.trackSelection + courseKey + '/';
},
/**
* Redirect to a URL. Mainly useful for mocking out in tests. * Redirect to a URL. Mainly useful for mocking out in tests.
* @param {string} url The URL to redirect to. * @param {string} url The URL to redirect to.
*/ */
......
...@@ -29,6 +29,12 @@ var edx = edx || {}; ...@@ -29,6 +29,12 @@ var edx = edx || {};
passwordHelp: {} passwordHelp: {}
}, },
urls: {
dashboard: '/dashboard',
payment: '/verify_student/start-flow/',
trackSelection: '/course_modes/choose/'
},
// The form currently loaded // The form currently loaded
activeForm: '', activeForm: '',
...@@ -243,15 +249,37 @@ var edx = edx || {}; ...@@ -243,15 +249,37 @@ var edx = edx || {};
enrollment: function() { enrollment: function() {
var enrollment = edx.student.account.EnrollmentInterface, var enrollment = edx.student.account.EnrollmentInterface,
shoppingcart = edx.student.account.ShoppingCartInterface, shoppingcart = edx.student.account.ShoppingCartInterface,
redirectUrl = '/dashboard', redirectUrl = this.urls.dashboard,
queryParams = this.queryParams(); queryParams = this.queryParams();
if ( queryParams.enrollmentAction === 'enroll' && queryParams.courseId) { if ( queryParams.enrollmentAction === 'enroll' && queryParams.courseId ) {
/* var courseId = decodeURIComponent( queryParams.courseId );
If we need to enroll in a course, mark as enrolled.
The enrollment interface will redirect the student once enrollment completes. // Determine where to redirect the user after auto-enrollment.
*/ if ( !queryParams.courseMode ) {
enrollment.enroll( decodeURIComponent( queryParams.courseId ) ); /* Backwards compatibility with the original course details page.
The old implementation did not specify the course mode for enrollment,
so we'd always send the user to the "track selection" page.
The track selection page would allow the user to select the course mode
("verified", "honor", etc.) -- or, if the only course mode was "honor",
it would redirect the user to the dashboard. */
redirectUrl = this.urls.trackSelection + courseId + '/';
} else if ( queryParams.courseMode === 'honor' || queryParams.courseMode === 'audit' ) {
/* The newer version of the course details page allows the user
to specify which course mode to enroll as. If the student has
chosen "honor", we send them immediately to the dashboard
rather than the payment flow. The user may decide to upgrade
from the dashboard later. */
redirectUrl = this.urls.dashboard;
} else {
/* If the user selected any other kind of course mode, send them
to the payment/verification flow. */
redirectUrl = this.urls.payment + courseId + '/';
}
/* Attempt to auto-enroll the user in a free mode of the course,
then redirect to the next location. */
enrollment.enroll( courseId, redirectUrl );
} else if ( queryParams.enrollmentAction === 'add_to_cart' && queryParams.courseId) { } else if ( queryParams.enrollmentAction === 'add_to_cart' && queryParams.courseId) {
/* /*
If this is a paid course, add it to the shopping cart and redirect If this is a paid course, add it to the shopping cart and redirect
...@@ -298,6 +326,7 @@ var edx = edx || {}; ...@@ -298,6 +326,7 @@ var edx = edx || {};
next: $.url( '?next' ), next: $.url( '?next' ),
enrollmentAction: $.url( '?enrollment_action' ), enrollmentAction: $.url( '?enrollment_action' ),
courseId: $.url( '?course_id' ), courseId: $.url( '?course_id' ),
courseMode: $.url( '?course_mode' ),
emailOptIn: $.url( '?email_opt_in') emailOptIn: $.url( '?email_opt_in')
}; };
}, },
......
...@@ -173,9 +173,13 @@ ...@@ -173,9 +173,13 @@
</html> </html>
<%def name="login_query()">${ <%def name="login_query()">${
u"?course_id={0}&enrollment_action={1}{email_opt_in}".format( u"?course_id={0}&enrollment_action={1}{course_mode}{email_opt_in}".format(
urlquote_plus(course_id), urlquote_plus(course_id),
urlquote_plus(enrollment_action), urlquote_plus(enrollment_action),
course_mode=(
u"&course_mode=" + urlquote_plus(course_mode)
if course_mode else ""
),
email_opt_in=( email_opt_in=(
u"&email_opt_in=" + urlquote_plus(email_opt_in) u"&email_opt_in=" + urlquote_plus(email_opt_in)
if email_opt_in else "" if email_opt_in else ""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment