Merge pull request #5762 from edx/diana/enrollment-integration
WIP: Combined Login/Registration: Set up basic enrollment infrastructure.
This commit is contained in:
@@ -31,6 +31,7 @@ class CourseModeViewTest(ModuleStoreTestCase):
|
||||
self.user = UserFactory.create(username="Bob", email="bob@example.com", password="edx")
|
||||
self.client.login(username=self.user.username, password="edx")
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@ddt.data(
|
||||
# is_active?, enrollment_mode, upgrade?, redirect?
|
||||
(True, 'verified', True, False), # User has an active verified enrollment and is trying to upgrade
|
||||
|
||||
@@ -26,10 +26,10 @@ class ChooseModeView(View):
|
||||
|
||||
When a get request is used, shows the selection page.
|
||||
|
||||
When a post request is used, assumes that it is a form submission
|
||||
When a post request is used, assumes that it is a form submission
|
||||
from the selection page, parses the response, and then sends user
|
||||
to the next step in the flow.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
@method_decorator(login_required)
|
||||
@@ -50,7 +50,7 @@ class ChooseModeView(View):
|
||||
"""
|
||||
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
|
||||
enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(request.user, course_key)
|
||||
|
||||
|
||||
upgrade = request.GET.get('upgrade', False)
|
||||
request.session['attempting_upgrade'] = upgrade
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ def update_course_enrollment(student_id, course_id, mode=None, is_active=None):
|
||||
course_key = CourseKey.from_string(course_id)
|
||||
student = User.objects.get(username=student_id)
|
||||
if not CourseEnrollment.is_enrolled(student, course_key):
|
||||
enrollment = CourseEnrollment.enroll(student, course_key)
|
||||
enrollment = CourseEnrollment.enroll(student, course_key, check_access=True)
|
||||
else:
|
||||
enrollment = CourseEnrollment.objects.get(user=student, course_id=course_key)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.throttling import UserRateThrottle
|
||||
from enrollment import api
|
||||
from student.models import NonExistentCourseError
|
||||
from student.models import NonExistentCourseError, CourseEnrollmentException
|
||||
|
||||
|
||||
class EnrollmentUserThrottle(UserRateThrottle):
|
||||
@@ -74,3 +74,5 @@ def get_course_enrollment(request, course_id=None):
|
||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||
except api.EnrollmentNotFoundError:
|
||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||
except CourseEnrollmentException:
|
||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@@ -1028,6 +1028,7 @@ instructor_dash_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/ins
|
||||
student_account_js = [
|
||||
'js/common_helpers/rwd_header_footer.js',
|
||||
'js/common_helpers/edx.utils.validate.js',
|
||||
'js/student_account/enrollment_interface.js',
|
||||
'js/student_account/models/LoginModel.js',
|
||||
'js/student_account/models/RegisterModel.js',
|
||||
'js/student_account/models/PasswordResetModel.js',
|
||||
|
||||
@@ -260,7 +260,10 @@
|
||||
exports: 'NotificationView',
|
||||
deps: ['backbone', 'jquery', 'underscore']
|
||||
},
|
||||
|
||||
'js/student_account/enrollment_interface': {
|
||||
exports: 'js/student_account/enrollment_interface',
|
||||
deps: ['jquery', 'underscore', 'gettext']
|
||||
},
|
||||
// Student account registration/login
|
||||
// Loaded explicitly until these are converted to RequireJS
|
||||
'js/student_account/views/FormView': {
|
||||
@@ -310,7 +313,7 @@
|
||||
'js/student_account/views/RegisterView',
|
||||
'underscore.string'
|
||||
]
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -327,6 +330,7 @@
|
||||
'lms/include/js/spec/student_account/login_spec.js',
|
||||
'lms/include/js/spec/student_account/register_spec.js',
|
||||
'lms/include/js/spec/student_account/password_reset_spec.js',
|
||||
'lms/include/js/spec/student_account/enrollment_interface_spec.js',
|
||||
'lms/include/js/spec/student_profile/profile.js',
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
define(['js/common_helpers/template_helpers', 'js/student_account/views/AccessView'],
|
||||
function(TemplateHelpers) {
|
||||
function(TemplateHelpers, AccessView) {
|
||||
describe('edx.student.account.AccessView', function() {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
define(['js/common_helpers/template_helpers', 'js/student_account/enrollment_interface'],
|
||||
function(TemplateHelpers, EnrollmentInterface) {
|
||||
describe("edx.student.account.EnrollmentInterface", function() {
|
||||
'use strict';
|
||||
|
||||
it("find course modes using modeInArray ", function() {
|
||||
var course_modes = [
|
||||
{
|
||||
slug: 'honor'
|
||||
},
|
||||
{
|
||||
slug: 'professional'
|
||||
}
|
||||
],
|
||||
|
||||
expect(EnrollmentInterface.modeInArray('professional')).toBe(true);
|
||||
expect(EnrollmentInterface.modeInArray('audit')).toBe(false);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -39,6 +39,10 @@ define(['js/common_helpers/template_helpers', 'js/student_account/views/LoginVie
|
||||
it("allows the user to navigate to the password assistance form", function() {
|
||||
// TODO
|
||||
});
|
||||
|
||||
it("enrolls the student into the right location and forwards them properly", function() {
|
||||
// TODO
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
78
lms/static/js/student_account/enrollment_interface.js
Normal file
78
lms/static/js/student_account/enrollment_interface.js
Normal file
@@ -0,0 +1,78 @@
|
||||
var edx = edx || {};
|
||||
|
||||
(function($, _, gettext) {
|
||||
'use strict';
|
||||
|
||||
edx.student = edx.student || {};
|
||||
edx.student.account = edx.student.account || {};
|
||||
|
||||
edx.student.account.EnrollmentInterface = {
|
||||
courseUrl: '/enrollment/v0/course/',
|
||||
studentUrl: '/enrollment/v0/student',
|
||||
trackSelectionUrl: '/course_modes/choose/',
|
||||
headers: {
|
||||
'X-CSRFToken': $.cookie('csrftoken')
|
||||
},
|
||||
|
||||
studentInformation: function(course_key) {
|
||||
// retrieve student enrollment information
|
||||
},
|
||||
|
||||
courseInformation: function(course_key) {
|
||||
// retrieve course information from the enrollment API
|
||||
},
|
||||
|
||||
modeInArray: function(mode_slug, course_modes) {
|
||||
// finds whether or not a particular course mode slug exists
|
||||
// in an array of course modes
|
||||
var result = _.find(course_modes, function(mode){ return mode.slug === mode_slug; });
|
||||
return result != undefined;
|
||||
},
|
||||
|
||||
enroll: function(course_key, forward_url){
|
||||
var me = this;
|
||||
// attempt to enroll a student in a course
|
||||
$.ajax({
|
||||
url: this.courseUrl + course_key,
|
||||
type: 'POST',
|
||||
data: {},
|
||||
headers: this.headers
|
||||
}).done(function(data){
|
||||
me.postEnrollmentHandler(course_key, data, forward_url);
|
||||
}
|
||||
).fail(function(data, textStatus) {
|
||||
me.enrollmentFailureHandler(course_key, data, forward_url);
|
||||
});
|
||||
},
|
||||
|
||||
enrollmentFailureHandler: function(course_key, data, forward_url) {
|
||||
// handle failures to enroll via the API
|
||||
if(data.status == 400) {
|
||||
// This status code probably means we don't have permissions to register for this course.
|
||||
// look at the contents of the response
|
||||
var course = $.parseJSON(data.responseText);
|
||||
// see if it's a professional ed course
|
||||
if('course_modes' in course && this.modeInArray('professional', course.course_modes)) {
|
||||
// forward appropriately
|
||||
forward_url = this.trackSelectionUrl + course_key;
|
||||
}
|
||||
}
|
||||
// TODO: if we have a paid registration mode, add item to the cart and send them along
|
||||
|
||||
// TODO: we should figure out how to handle errors here eventually
|
||||
window.location.href = forward_url;
|
||||
},
|
||||
|
||||
postEnrollmentHandler: function(course_key, data, forward_url) {
|
||||
// Determine whether or not the course needs to be redirected to
|
||||
// a particular page.
|
||||
var course = data.course,
|
||||
course_modes = course.course_modes;
|
||||
|
||||
// send the user to the track selection page, because it will do the right thing
|
||||
forward_url = this.trackSelectionUrl + course_key;
|
||||
|
||||
window.location.href = forward_url;
|
||||
}
|
||||
};
|
||||
})(jQuery, _, gettext);
|
||||
@@ -6,6 +6,7 @@ var edx = edx || {};
|
||||
edx.student = edx.student || {};
|
||||
edx.student.account = edx.student.account || {};
|
||||
|
||||
|
||||
edx.student.account.LoginModel = Backbone.Model.extend({
|
||||
|
||||
defaults: {
|
||||
@@ -32,17 +33,31 @@ var edx = edx || {};
|
||||
headers: headers
|
||||
})
|
||||
.done(function() {
|
||||
var query = window.location.search,
|
||||
url = '/dashboard';
|
||||
var enrollment = edx.student.account.EnrollmentInterface,
|
||||
query = new URI(window.location.search),
|
||||
url = '/dashboard',
|
||||
query_map = query.search(true),
|
||||
next = '';
|
||||
|
||||
// check for forwarding url
|
||||
if("next" in query_map) {
|
||||
next = query_map['next'];
|
||||
if(!window.isExternal(next)){
|
||||
url = next;
|
||||
}
|
||||
}
|
||||
|
||||
model.trigger('sync');
|
||||
|
||||
// If query string in url go back to that page
|
||||
if ( query.length > 1 ) {
|
||||
url = query.substring( query.indexOf('=') + 1 );
|
||||
// if we need to enroll in the course, mark as enrolled
|
||||
if('enrollment_action' in query_map && query_map['enrollment_action'] === 'enroll'){
|
||||
enrollment.enroll(query_map['course_id'], url);
|
||||
}
|
||||
else {
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
window.location.href = url;
|
||||
|
||||
})
|
||||
.fail( function( error ) {
|
||||
model.trigger('error', error);
|
||||
|
||||
@@ -39,17 +39,29 @@ var edx = edx || {};
|
||||
headers: headers
|
||||
})
|
||||
.done(function() {
|
||||
var query = window.location.search,
|
||||
url = '/dashboard';
|
||||
var enrollment = edx.student.account.EnrollmentInterface,
|
||||
query = new URI(window.location.search),
|
||||
url = '/dashboard',
|
||||
query_map = query.search(true),
|
||||
next = '';
|
||||
|
||||
// check for forwarding url
|
||||
if("next" in query_map) {
|
||||
next = query_map['next'];
|
||||
if(!window.isExternal(next)){
|
||||
url = next;
|
||||
}
|
||||
}
|
||||
|
||||
model.trigger('sync');
|
||||
|
||||
// If query string in url go back to that page
|
||||
if ( query.length > 1 ) {
|
||||
url = query.substring( query.indexOf('=') + 1 );
|
||||
// if we need to enroll in the course, mark as enrolled
|
||||
if('enrollment_action' in query_map && query_map['enrollment_action'] === 'enroll'){
|
||||
enrollment.enroll(query_map['course_id'], url);
|
||||
}
|
||||
else {
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
window.location.href = url;
|
||||
})
|
||||
.fail( function( error ) {
|
||||
model.trigger('error', error);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<%block name="js_extra">
|
||||
<script type="text/javascript" src="${static.url('js/vendor/backbone-min.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/vendor/underscore.string.min.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/vendor/URI.min.js')}"></script>
|
||||
<%static:js group='student_account'/>
|
||||
</%block>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user