Commit 4d77b055 by Julia Hansbrough

Move server-side validation to enroll method

parent f94c677a
...@@ -589,6 +589,22 @@ class LoginFailures(models.Model): ...@@ -589,6 +589,22 @@ class LoginFailures(models.Model):
return return
class CourseEnrollmentException(Exception):
pass
class NonExistentCourseError(CourseEnrollmentException):
pass
class EnrollmentClosedError(CourseEnrollmentException):
pass
class CourseFullError(CourseEnrollmentException):
pass
class AlreadyEnrolledError(CourseEnrollmentException):
pass
class CourseEnrollment(models.Model): class CourseEnrollment(models.Model):
""" """
Represents a Student's Enrollment record for a single Course. You should Represents a Student's Enrollment record for a single Course. You should
...@@ -795,10 +811,59 @@ class CourseEnrollment(models.Model): ...@@ -795,10 +811,59 @@ class CourseEnrollment(models.Model):
until we have these mapped out. until we have these mapped out.
It is expected that this method is called from a method which has already It is expected that this method is called from a method which has already
verified the user authentication and access. verified the user authentication.
Also emits relevant events for analytics purposes. Also emits relevant events for analytics purposes.
""" """
# All the server-side checks for whether a user is allowed to enroll.
try:
course_id = SlashSeparatedCourseKey.from_deprecated_string(request.POST.get("course_id"))
except InvalidKeyError:
log.warning(
"User {username} tried to {action} with invalid course id: {course_id}".format(
username=user.username,
action=action,
course_id=request.POST.get("course_id")
)
)
raise CourseEnrollmentException
try:
course = modulestore().get_course(course_id)
except ItemNotFoundError:
log.warning(
"User {0} failed to enroll in non-existent course {1}".format(
user.username,
course_id
)
)
raise NonExistentCourseError
if not has_access(user, 'enroll', course):
log.warning(
"User {0} failed to enroll in course {1} because enrollment is closed".format(
user.username,
course_id
)
)
raise EnrollmentClosedError
if CourseEnrollment.is_course_full(course):
log.warning(
"User {0} failed to enroll in full course {1}".format(
user.username,
course_id
)
)
raise CourseFullError
if CourseEnrollment.is_enrolled(user, course_id):
log.warning(
"User {0} attempted to enroll in {1}, but they were already enrolled".format(
user.username,
course_id
)
)
raise AlreadyEnrolledError
# User is allowed to enroll if they've reached this point.
enrollment = cls.get_or_create_enrollment(user, course_key) enrollment = cls.get_or_create_enrollment(user, course_key)
enrollment.update_enrollment(is_active=True, mode=mode) enrollment.update_enrollment(is_active=True, mode=mode)
return enrollment return enrollment
......
...@@ -661,20 +661,19 @@ def change_enrollment(request, auto_register=False): ...@@ -661,20 +661,19 @@ def change_enrollment(request, auto_register=False):
Response Response
""" """
# Get the user
user = request.user user = request.user
# Ensure we received a course_id
action = request.POST.get("enrollment_action") action = request.POST.get("enrollment_action")
if 'course_id' not in request.POST: if 'course_id' not in request.POST:
return HttpResponseBadRequest(_("Course id not specified")) return HttpResponseBadRequest(_("Course id not specified"))
try: # Ensure the user is authenticated
course_id = SlashSeparatedCourseKey.from_deprecated_string(request.POST.get("course_id")) if not user.is_authenticated():
except InvalidKeyError: return HttpResponseForbidden()
log.warning("User {username} tried to {action} with invalid course id: {course_id}".format(
username=user.username, action=action, course_id=request.POST.get("course_id")
))
return HttpResponseBadRequest(_("Invalid course id"))
# Sets the auto_register flag, if that's desired
# TODO (ECOM-16): Remove this once the auto-registration A/B test completes # TODO (ECOM-16): Remove this once the auto-registration A/B test completes
# If a user is in the experimental condition (auto-registration enabled), # If a user is in the experimental condition (auto-registration enabled),
# immediately set a session flag so they stay in the experimental condition. # immediately set a session flag so they stay in the experimental condition.
...@@ -686,6 +685,7 @@ def change_enrollment(request, auto_register=False): ...@@ -686,6 +685,7 @@ def change_enrollment(request, auto_register=False):
if request.session.get('auto_register') and not auto_register: if request.session.get('auto_register') and not auto_register:
auto_register = True auto_register = True
# Don't execute auto-register for the set of courses excluded from auto-registration
# TODO (ECOM-16): Remove this once the auto-registration A/B test completes # TODO (ECOM-16): Remove this once the auto-registration A/B test completes
# We've agreed to exclude certain courses from the A/B test. If we find ourselves # We've agreed to exclude certain courses from the A/B test. If we find ourselves
# registering for one of these courses, immediately switch to the control. # registering for one of these courses, immediately switch to the control.
...@@ -694,34 +694,7 @@ def change_enrollment(request, auto_register=False): ...@@ -694,34 +694,7 @@ def change_enrollment(request, auto_register=False):
if 'auto_register' in request.session: if 'auto_register' in request.session:
del request.session['auto_register'] del request.session['auto_register']
if not user.is_authenticated():
return HttpResponseForbidden()
if action == "enroll": if action == "enroll":
# Make sure the course exists
# We don't do this check on unenroll, or a bad course id can't be unenrolled from
try:
course = modulestore().get_course(course_id)
except ItemNotFoundError:
log.warning("User {0} tried to enroll in non-existent course {1}"
.format(user.username, course_id))
return HttpResponseBadRequest(_("Course id is invalid"))
if not has_access(user, 'enroll', course):
return HttpResponseBadRequest(_("Enrollment is closed"))
# see if we have already filled up all allowed enrollments
is_course_full = CourseEnrollment.is_course_full(course)
if is_course_full:
return HttpResponseBadRequest(_("Course is full"))
# check to see if user is currently enrolled in that course
if CourseEnrollment.is_enrolled(user, course_id):
return HttpResponseBadRequest(
_("Student is already enrolled")
)
# We use this flag to determine which condition of an AB-test # We use this flag to determine which condition of an AB-test
# for auto-registration we're currently in. # for auto-registration we're currently in.
# (We have two URLs that both point to this view, but vary the # (We have two URLs that both point to this view, but vary the
...@@ -747,7 +720,10 @@ def change_enrollment(request, auto_register=False): ...@@ -747,7 +720,10 @@ def change_enrollment(request, auto_register=False):
# by its slug. If they do, it's possible (based on the state of the database) # by its slug. If they do, it's possible (based on the state of the database)
# for no such model to exist, even though we've set the enrollment type # for no such model to exist, even though we've set the enrollment type
# to "honor". # to "honor".
CourseEnrollment.enroll(user, course.id) try:
CourseEnrollment.enroll(user, course.id, mode=current_mode.slug)
except Exception:
return HttpResponseBadRequest(_("Could not enroll"))
# If we have more than one course mode or professional ed is enabled, # If we have more than one course mode or professional ed is enabled,
# then send the user to the choose your track page. # then send the user to the choose your track page.
...@@ -780,7 +756,10 @@ def change_enrollment(request, auto_register=False): ...@@ -780,7 +756,10 @@ def change_enrollment(request, auto_register=False):
reverse("course_modes_choose", kwargs={'course_id': unicode(course_id)}) reverse("course_modes_choose", kwargs={'course_id': unicode(course_id)})
) )
CourseEnrollment.enroll(user, course.id, mode=current_mode.slug) try:
CourseEnrollment.enroll(user, course.id, mode=current_mode.slug)
except Exception:
return HttpResponseBadRequest(_("Could not enroll"))
return HttpResponse() return HttpResponse()
......
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