Commit b8f5be2c by Will Daly

Allow inactive users to modify their own enrollments

parent a13f4f2f
......@@ -115,7 +115,23 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
# Try to enroll, this should fail.
resp = self.client.post(reverse('courseenrollment', kwargs={'course_id': (unicode(self.course.id))}))
self.assertEqual(resp.status_code, status.HTTP_401_UNAUTHORIZED)
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
def test_user_not_activated(self):
# Create a user account, but don't activate it
self.user = UserFactory.create(
username="inactive",
email="inactive@example.com",
password=self.PASSWORD,
is_active=False
)
# Log in with the unactivated account
self.client.login(username="inactive", password=self.PASSWORD)
# Enrollment should succeed, even though we haven't authenticated.
resp = self.client.post(reverse('courseenrollment', kwargs={'course_id': (unicode(self.course.id))}))
self.assertEqual(resp.status_code, 200)
def test_unenroll_not_enrolled_in_course(self):
# Deactivate the enrollment in the course and verify the URL we get sent to
......
......@@ -17,6 +17,52 @@ class EnrollmentUserThrottle(UserRateThrottle):
rate = '50/second' # TODO Limit significantly after performance testing.
class SessionAuthenticationAllowInactiveUser(SessionAuthentication):
"""Ensure that the user is logged in, but do not require the account to be active.
We use this in the special case that a user has created an account,
but has not yet activated it. We still want to allow the user to
enroll in courses, so we remove the usual restriction
on session authentication that requires an active account.
You should use this authentication class ONLY for end-points that
it's safe for an unactived user to access. For example,
we can allow a user to update his/her own enrollments without
activating an account.
"""
def authenticate(self, request):
"""Authenticate the user, requiring a logged-in account and CSRF.
This is exactly the same as the `SessionAuthentication` implementation,
with the `user.is_active` check removed.
Args:
request (HttpRequest)
Returns:
Tuple of `(user, token)`
Raises:
PermissionDenied: The CSRF token check failed.
"""
# Get the underlying HttpRequest object
request = request._request
user = getattr(request, 'user', None)
# Unauthenticated, CSRF validation not required
# This is where regular `SessionAuthentication` checks that the user is active.
# We have removed that check in this implementation.
if not user:
return None
self.enforce_csrf(request)
# CSRF passed with authenticated user
return (user, None)
@api_view(['GET'])
@authentication_classes((OAuth2Authentication, SessionAuthentication))
@permission_classes((IsAuthenticated,))
......@@ -37,7 +83,7 @@ def list_student_enrollments(request):
@api_view(['GET', 'POST'])
@authentication_classes((OAuth2Authentication, SessionAuthentication))
@authentication_classes((OAuth2Authentication, SessionAuthenticationAllowInactiveUser))
@permission_classes((IsAuthenticated,))
@throttle_classes([EnrollmentUserThrottle])
def get_course_enrollment(request, course_id=None):
......
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