Commit 735b4009 by Will Daly

Login/Registration page can skip track selection.

Add querystring param "course_mode" to the login/registration
page so the user can skip track selection.

This supports upcoming changes to the course details page
that allow the user to choose the track when clicking
"enroll", which will replace the functionality of the track
selection page.
parent e1251bfe
......@@ -246,13 +246,26 @@ class StudentAccountLoginAndRegistrationTest(UrlResetMixin, ModuleStoreTestCase)
'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
# 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")
# 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})
@ddt.data("account_login", "account_register")
def test_third_party_auth_disabled(self, url_name):
......
......@@ -91,7 +91,8 @@ def login_and_registration_form(request, initial_mode="login"):
# We need to pass these parameters so that the header's
# "Sign In" button preserves the querystring params.
'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)
......
......@@ -166,7 +166,52 @@ define([
view.subview.login.trigger('auth-complete');
// 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() {
......
......@@ -19,7 +19,7 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'],
var requests = AjaxHelpers.requests( this );
// 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
AjaxHelpers.expectRequest(
......@@ -41,7 +41,7 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'],
var requests = AjaxHelpers.requests( this );
// Attempt to enroll the user
EnrollmentInterface.enroll( COURSE_KEY );
EnrollmentInterface.enroll( COURSE_KEY, FORWARD_URL );
// Simulate an error response from the server
AjaxHelpers.respondWithError(requests);
......@@ -55,7 +55,7 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'],
var requests = AjaxHelpers.requests( this );
// Attempt to enroll the user
EnrollmentInterface.enroll( COURSE_KEY );
EnrollmentInterface.enroll( COURSE_KEY, FORWARD_URL );
// Simulate an error response (403) from the server
// with a "user_message_url" parameter for the redirect.
......
......@@ -10,7 +10,6 @@ var edx = edx || {};
urls: {
orders: '/commerce/orders/',
trackSelection: '/course_modes/choose/'
},
headers: {
......@@ -18,11 +17,11 @@ var edx = edx || {};
},
/**
* Enroll a user in a course, then redirect the user
* to the track selection page.
* Enroll a user in a course, then redirect the user.
* @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},
data = JSON.stringify(data_obj);
......@@ -42,31 +41,23 @@ var edx = edx || {};
// If so, redirect to a page explaining to the user
// why they were blocked.
this.redirect( responseData.user_message_url );
}
else {
// Otherwise, go to the track selection page as usual.
// This can occur, for example, when a course does not
// have a free enrollment mode, so we can't auto-enroll.
this.redirect( this.trackSelectionUrl( courseKey ) );
} else {
// Otherwise, redirect the user to the next page.
if ( redirectUrl ) {
this.redirect( redirectUrl );
}
}
})
.done(function() {
// If we successfully enrolled, go to the track selection
// page to allow the user to choose a paid enrollment mode.
this.redirect( this.trackSelectionUrl( courseKey ) );
// If we successfully enrolled, redirect the user
// to the next page (usually the student dashboard or payment flow)
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.
* @param {string} url The URL to redirect to.
*/
......
......@@ -29,6 +29,12 @@ var edx = edx || {};
passwordHelp: {}
},
urls: {
dashboard: '/dashboard',
payment: '/verify_student/start-flow/',
trackSelection: '/course_modes/choose/'
},
// The form currently loaded
activeForm: '',
......@@ -243,15 +249,37 @@ var edx = edx || {};
enrollment: function() {
var enrollment = edx.student.account.EnrollmentInterface,
shoppingcart = edx.student.account.ShoppingCartInterface,
redirectUrl = '/dashboard',
redirectUrl = this.urls.dashboard,
queryParams = this.queryParams();
if ( queryParams.enrollmentAction === 'enroll' && queryParams.courseId) {
/*
If we need to enroll in a course, mark as enrolled.
The enrollment interface will redirect the student once enrollment completes.
*/
enrollment.enroll( decodeURIComponent( queryParams.courseId ) );
if ( queryParams.enrollmentAction === 'enroll' && queryParams.courseId ) {
var courseId = decodeURIComponent( queryParams.courseId );
// Determine where to redirect the user after auto-enrollment.
if ( !queryParams.courseMode ) {
/* 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) {
/*
If this is a paid course, add it to the shopping cart and redirect
......@@ -298,6 +326,7 @@ var edx = edx || {};
next: $.url( '?next' ),
enrollmentAction: $.url( '?enrollment_action' ),
courseId: $.url( '?course_id' ),
courseMode: $.url( '?course_mode' ),
emailOptIn: $.url( '?email_opt_in')
};
},
......
......@@ -173,9 +173,13 @@
</html>
<%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(enrollment_action),
course_mode=(
u"&course_mode=" + urlquote_plus(course_mode)
if course_mode else ""
),
email_opt_in=(
u"&email_opt_in=" + urlquote_plus(email_opt_in)
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