Allow inactive users to modify their own enrollments
This commit is contained in:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user