Commit af4d288f by Stephen Sanchez

Merge pull request #7377 from edx/sanchez/enrollment_api_course_modes

XCOM-45 Enrollment API supports creating modes other than honor.
parents f0b44920 8c9f6370
......@@ -6,6 +6,7 @@ consist primarily of authentication, request validation, and serialization.
from ipware.ip import get_ip
from django.utils.decorators import method_decorator
from opaque_keys import InvalidKeyError
from course_modes.models import CourseMode
from openedx.core.djangoapps.user_api.preferences.api import update_email_opt_in
from openedx.core.lib.api.permissions import ApiKeyHeaderPermission, ApiKeyHeaderPermissionIsAuthenticated
from rest_framework import status
......@@ -215,20 +216,27 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
2. Enroll the currently logged in user in a course.
Currently you can use this command only to enroll the user in "honor" mode.
Currently a user can use this command only to enroll the user in "honor" mode.
If honor mode is not supported for the course, the request fails and returns the available modes.
A server-to-server call can be used by this command to enroll a user in other modes, such as "verified"
or "professional". If the mode is not supposed for the course, the request will fail and return the
available modes.
**Example Requests**:
GET /api/enrollment/v1/enrollment
POST /api/enrollment/v1/enrollment{"course_details":{"course_id": "edX/DemoX/Demo_Course"}}
POST /api/enrollment/v1/enrollment{"mode": "honor", "course_details":{"course_id": "edX/DemoX/Demo_Course"}}
**Post Parameters**
* user: The user ID of the currently logged in user. Optional. You cannot use the command to enroll a different user.
* mode: The Course Mode for the enrollment. Individual users cannot upgrade their enrollment mode from
'honor'. Only server to server requests can enroll with other modes. Optional.
* course details: A collection that contains:
* course_id: The unique identifier for the course.
......@@ -302,13 +310,8 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
"""
Enrolls the currently logged in user in a course.
"""
# Get the User, Course ID, and Mode from the request.
user = request.DATA.get('user', request.user.username)
if not user:
user = request.user.username
if user != request.user.username and not self.has_api_key_permissions(request):
# Return a 404 instead of a 403 (Unauthorized). If one user is looking up
# other users, do not let them deduce the existence of an enrollment.
return Response(status=status.HTTP_404_NOT_FOUND)
if 'course_details' not in request.DATA or 'course_id' not in request.DATA['course_details']:
return Response(
......@@ -316,7 +319,6 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
data={"message": u"Course ID must be specified to create a new enrollment."}
)
course_id = request.DATA['course_details']['course_id']
try:
course_id = CourseKey.from_string(course_id)
except InvalidKeyError:
......@@ -327,11 +329,33 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
}
)
mode = request.DATA.get('mode', CourseMode.HONOR)
has_api_key_permissions = self.has_api_key_permissions(request)
# Check that the user specified is either the same user, or this is a server-to-server request.
if not user:
user = request.user.username
if user != request.user.username and not has_api_key_permissions:
# Return a 404 instead of a 403 (Unauthorized). If one user is looking up
# other users, do not let them deduce the existence of an enrollment.
return Response(status=status.HTTP_404_NOT_FOUND)
if mode != CourseMode.HONOR and not has_api_key_permissions:
return Response(
status=status.HTTP_403_FORBIDDEN,
data={
"message": u"User does not have permission to create enrollment with mode [{mode}].".format(
mode=mode
)
}
)
# Check whether any country access rules block the user from enrollment
# We do this at the view level (rather than the Python API level)
# because this check requires information about the HTTP request.
redirect_url = embargo_api.redirect_if_blocked(
course_id, user=request.user,
course_id, user=user,
ip_address=get_ip(request),
url=request.path
)
......@@ -347,12 +371,25 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
)
try:
response = api.add_enrollment(user, unicode(course_id))
# Check if the user is currently enrolled, and if it is the same as the current enrolled mode. We do not
# have to check if it is inactive or not, because if it is, we are still upgrading if the mode is different,
# and either path will re-activate the enrollment.
#
# Only server-to-server calls will currently be allowed to modify the mode for existing enrollments. All
# other requests will go through add_enrollment(), which will allow creating of new enrollments, and
# re-activating enrollments
enrollment = api.get_enrollment(user, unicode(course_id))
if has_api_key_permissions and enrollment and enrollment['mode'] != mode:
response = api.update_enrollment(user, unicode(course_id), mode=mode)
http_success_status = status.HTTP_200_OK
else:
response = api.add_enrollment(user, unicode(course_id), mode=mode)
http_success_status = status.HTTP_201_CREATED
email_opt_in = request.DATA.get('email_opt_in', None)
if email_opt_in is not None:
org = course_id.org
update_email_opt_in(request.user, org, email_opt_in)
return Response(response)
return Response(response, status=http_success_status)
except CourseModeNotFoundError as error:
return Response(
status=status.HTTP_400_BAD_REQUEST,
......
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