feat: add a create enrollment endpoint for support tools
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
updateEnrollment: function(new_mode, reason) {
|
||||
return $.ajax({
|
||||
url: this.url(),
|
||||
type: 'POST',
|
||||
type: 'PATCH',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
course_id: this.get('course_id'),
|
||||
|
||||
@@ -22,7 +22,7 @@ define([
|
||||
reason: 'Financial Assistance'
|
||||
};
|
||||
enrollment.updateEnrollment('verified', 'Financial Assistance');
|
||||
AjaxHelpers.expectJsonRequest(requests, 'POST', '/support/enrollment/test-user', {
|
||||
AjaxHelpers.expectJsonRequest(requests, 'PATCH', '/support/enrollment/test-user', {
|
||||
course_id: EnrollmentHelpers.TEST_COURSE,
|
||||
new_mode: 'verified',
|
||||
old_mode: 'audit',
|
||||
|
||||
@@ -73,7 +73,7 @@ define([
|
||||
$('.enrollment-new-mode').val('verified');
|
||||
$('.enrollment-reason').val('Financial Assistance');
|
||||
$('.enrollment-change-submit').click();
|
||||
AjaxHelpers.expectJsonRequest(requests, 'POST', '/support/enrollment/test-user', {
|
||||
AjaxHelpers.expectJsonRequest(requests, 'PATCH', '/support/enrollment/test-user', {
|
||||
course_id: EnrollmentHelpers.TEST_COURSE,
|
||||
new_mode: 'verified',
|
||||
old_mode: 'audit',
|
||||
|
||||
@@ -24,6 +24,7 @@ from common.djangoapps.course_modes.tests.factories import CourseModeFactory
|
||||
from common.djangoapps.entitlements.tests.factories import CourseEntitlementFactory
|
||||
from common.djangoapps.student.models import (
|
||||
ENROLLED_TO_ENROLLED,
|
||||
UNENROLLED_TO_ENROLLED,
|
||||
CourseEnrollment,
|
||||
CourseEnrollmentAttribute,
|
||||
ManualEnrollmentAudit
|
||||
@@ -329,18 +330,64 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
|
||||
@disable_signal(signals, 'post_save')
|
||||
@ddt.data('username', 'email')
|
||||
def test_change_enrollment(self, search_string_type):
|
||||
def test_create_new_enrollment(self, search_string_type):
|
||||
"""
|
||||
Assert that a new enrollment is created through post request endpoint.
|
||||
"""
|
||||
test_user = UserFactory.create(username='newStudent', email='test2@example.com', password='test')
|
||||
assert ManualEnrollmentAudit.get_manual_enrollment_by_email(test_user.email) is None
|
||||
url = reverse(
|
||||
'support:enrollment_list',
|
||||
kwargs={'username_or_email': getattr(test_user, search_string_type)}
|
||||
)
|
||||
response = self.client.post(url, data={
|
||||
'course_id': str(self.course.id),
|
||||
'mode': CourseMode.AUDIT,
|
||||
'reason': 'Financial Assistance'
|
||||
})
|
||||
assert response.status_code == 200
|
||||
manual_enrollment = ManualEnrollmentAudit.get_manual_enrollment_by_email(test_user.email)
|
||||
assert manual_enrollment is not None
|
||||
assert manual_enrollment.reason == response.json()['reason']
|
||||
assert manual_enrollment.enrolled_email == 'test2@example.com'
|
||||
assert manual_enrollment.state_transition == UNENROLLED_TO_ENROLLED
|
||||
|
||||
@disable_signal(signals, 'post_save')
|
||||
@ddt.data('username', 'email')
|
||||
def test_create_existing_enrollment(self, search_string_type):
|
||||
"""
|
||||
Assert that a new enrollment is not created when an enrollment already exist for that course.
|
||||
"""
|
||||
assert ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email) is None
|
||||
url = reverse(
|
||||
'support:enrollment_list',
|
||||
kwargs={'username_or_email': getattr(self.student, search_string_type)}
|
||||
)
|
||||
response = self.client.post(url, data={
|
||||
'course_id': str(self.course.id),
|
||||
'mode': CourseMode.AUDIT,
|
||||
'reason': 'Financial Assistance'
|
||||
})
|
||||
assert response.status_code == 400
|
||||
assert ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email) is None
|
||||
|
||||
@disable_signal(signals, 'post_save')
|
||||
@ddt.data('username', 'email')
|
||||
def test_change_enrollment(self, search_string_type):
|
||||
"""
|
||||
Assert changing mode for an enrollment.
|
||||
"""
|
||||
assert ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email) is None
|
||||
url = reverse(
|
||||
'support:enrollment_list',
|
||||
kwargs={'username_or_email': getattr(self.student, search_string_type)}
|
||||
)
|
||||
response = self.client.patch(url, data={
|
||||
'course_id': str(self.course.id),
|
||||
'old_mode': CourseMode.AUDIT,
|
||||
'new_mode': CourseMode.VERIFIED,
|
||||
'reason': 'Financial Assistance'
|
||||
})
|
||||
}, content_type='application/json')
|
||||
assert response.status_code == 200
|
||||
assert ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email) is not None
|
||||
self.assert_enrollment(CourseMode.VERIFIED)
|
||||
@@ -365,12 +412,12 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
'support:enrollment_list',
|
||||
kwargs={'username_or_email': getattr(self.student, search_string_type)}
|
||||
)
|
||||
response = self.client.post(url, data={
|
||||
response = self.client.patch(url, data={
|
||||
'course_id': str(self.course.id),
|
||||
'old_mode': CourseMode.AUDIT,
|
||||
'new_mode': CourseMode.VERIFIED,
|
||||
'reason': 'Financial Assistance'
|
||||
})
|
||||
}, content_type='application/json')
|
||||
entitlement.refresh_from_db()
|
||||
assert response.status_code == 200
|
||||
assert ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email) is not None
|
||||
@@ -406,7 +453,7 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
# assign the course ID here
|
||||
if 'course_id' in data and data['course_id'] is None:
|
||||
data['course_id'] = str(self.course.id)
|
||||
response = self.client.post(self.url, data)
|
||||
response = self.client.patch(self.url, data, content_type='application/json')
|
||||
|
||||
assert response.status_code == 400
|
||||
assert re.match(error_message, response.content.decode('utf-8').replace("'", '').replace('"', '')) is not None
|
||||
@@ -485,12 +532,12 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
['Arizona State University'], 'You are now eligible for credit from Arizona State University'
|
||||
)
|
||||
mock_method.return_value = credit_provider
|
||||
response = self.client.post(url, data={
|
||||
response = self.client.patch(url, data={
|
||||
'course_id': str(self.course.id),
|
||||
'old_mode': CourseMode.AUDIT,
|
||||
'new_mode': new_mode,
|
||||
'reason': 'Financial Assistance'
|
||||
})
|
||||
}, content_type='application/json')
|
||||
|
||||
assert response.status_code == 200
|
||||
assert ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email) is not None
|
||||
|
||||
@@ -17,6 +17,7 @@ from common.djangoapps.course_modes.models import CourseMode
|
||||
from common.djangoapps.edxmako.shortcuts import render_to_response
|
||||
from common.djangoapps.student.models import (
|
||||
ENROLLED_TO_ENROLLED,
|
||||
UNENROLLED_TO_ENROLLED,
|
||||
CourseEnrollment,
|
||||
CourseEnrollmentAttribute,
|
||||
ManualEnrollmentAudit
|
||||
@@ -84,6 +85,58 @@ class EnrollmentSupportListView(GenericAPIView):
|
||||
|
||||
@method_decorator(require_support_permission)
|
||||
def post(self, request, username_or_email):
|
||||
"""
|
||||
Allows support staff to create a user's enrollment.
|
||||
"""
|
||||
try:
|
||||
course_id = request.data['course_id']
|
||||
course_key = CourseKey.from_string(course_id)
|
||||
mode = request.data['mode']
|
||||
reason = request.data['reason']
|
||||
user = User.objects.get(Q(username=username_or_email) | Q(email=username_or_email))
|
||||
except KeyError as err:
|
||||
return HttpResponseBadRequest(f'The field {str(err)} is required.')
|
||||
except InvalidKeyError:
|
||||
return HttpResponseBadRequest('Could not parse course key.')
|
||||
except User.DoesNotExist:
|
||||
return HttpResponseBadRequest(
|
||||
'Could not find user {username}.'.format(
|
||||
username=username_or_email
|
||||
)
|
||||
)
|
||||
|
||||
enrollment = CourseEnrollment.get_enrollment(user=user, course_key=course_key)
|
||||
if enrollment is not None:
|
||||
return HttpResponseBadRequest(
|
||||
f'The user {str(username_or_email)} is already enrolled in {str(course_id)}.'
|
||||
)
|
||||
|
||||
enrollment_modes = [
|
||||
enrollment_mode['slug']
|
||||
for enrollment_mode in self.get_course_modes(course_key)
|
||||
]
|
||||
if mode not in enrollment_modes:
|
||||
return HttpResponseBadRequest(
|
||||
f'{str(mode)} is not a valid mode for {str(course_id)}. '
|
||||
f'Possible valid modes are {str(enrollment_modes)}'
|
||||
)
|
||||
|
||||
enrollment = CourseEnrollment.enroll(user=user, course_key=course_key, mode=mode)
|
||||
|
||||
# Wrapped in a transaction so that we can be sure the
|
||||
# ManualEnrollmentAudit record is always created correctly.
|
||||
with transaction.atomic():
|
||||
manual_enrollment = ManualEnrollmentAudit.create_manual_enrollment_audit(
|
||||
request.user,
|
||||
enrollment.user.email,
|
||||
UNENROLLED_TO_ENROLLED,
|
||||
reason=reason,
|
||||
enrollment=enrollment
|
||||
)
|
||||
return JsonResponse(ManualEnrollmentSerializer(instance=manual_enrollment).data)
|
||||
|
||||
@method_decorator(require_support_permission)
|
||||
def patch(self, request, username_or_email):
|
||||
"""Allows support staff to alter a user's enrollment."""
|
||||
try:
|
||||
user = User.objects.get(Q(username=username_or_email) | Q(email=username_or_email))
|
||||
|
||||
Reference in New Issue
Block a user