Commit 4527a67d by Chris Dodge

add ability to enroll users into courses

parent f59612ce
......@@ -16,5 +16,6 @@ urlpatterns = patterns(
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/updates$', 'course_updates'),
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/static_tabs/(?P<tab_id>[a-zA-Z0-9/_:]+)$', 'static_tab_detail'),
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/static_tabs$', 'static_tabs_list'),
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/users$', 'course_users_list'),
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)$', 'courses_detail'),
)
""" API implementation for course-oriented interactions. """
from django.contrib.auth.models import Group
from django.contrib.auth.models import Group, User
from django.core.exceptions import ObjectDoesNotExist
from lxml import etree
from StringIO import StringIO
......@@ -18,6 +18,7 @@ from xmodule.modulestore import Location, InvalidLocationError
from courseware.courses import get_course_about_section, get_course_info_section
from courseware.views import get_static_tab_contents
from student.models import CourseEnrollment, CourseEnrollmentAllowed
log = logging.getLogger(__name__)
......@@ -549,3 +550,72 @@ def static_tab_detail(request, course_id, tab_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
return Response(response_data)
@api_view(['GET', 'POST', 'DELETE'])
@permission_classes((ApiKeyHeaderPermission,))
def course_users_list(request, course_id):
"""
GET returns a list of users enrolled in the course_id
POST enrolls a student in the course. Note, this can be a user_id or just an email, in case
the user does not exist in the system
"""
store = modulestore()
response_data = OrderedDict()
try:
# find the course
course_module = store.get_course(course_id)
if not course_module:
return Response({}, status=status.HTTP_404_NOT_FOUND)
except InvalidLocationError:
return Response({}, status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
# Get a list of all enrolled students
users = CourseEnrollment.users_enrolled_in(course_id)
response_data['enrollments'] = []
for user in users:
user_data = OrderedDict()
user_data['id'] = user.id
user_data['email'] = user.email
user_data['username'] = user.username
# @TODO: Should we create a URI resourse that points to user?!? But that's in a different URL subpath
response_data['enrollments'].append(user_data)
# Then list all enrollments which are pending. These are enrollments for students that have not yet
# created an account
pending_enrollments = CourseEnrollmentAllowed.objects.filter(course_id=course_id)
if pending_enrollments:
response_data['pending_enrollments'] = []
for cea in pending_enrollments:
response_data['pending_enrollments'].append(cea.email)
return Response(response_data)
elif request.method == 'POST':
if 'user_id' in request.DATA:
user_id = request.DATA['user_id']
try:
existing_user = User.objects.get(id=user_id)
CourseEnrollment.enroll(existing_user, course_id)
except ObjectDoesNotExist:
return Response({'err': 'user_does_not_exist'}, status=status.HTTP_400_BAD_REQUEST)
elif 'email' in request.DATA:
# If caller passed in an email, then let's look up user by email address
# if it doesn't exist then we need to assume that the student does not exist
# in our database and that the instructor is pre-enrolling ment
email = request.DATA['email']
try:
existing_user = User.objects.get(email=email)
CourseEnrollment.enroll(existing_user, course_id)
except ObjectDoesNotExist:
if not request.DATA.get('allow_pending', False):
return Response({'err': 'user_does_not_exist'}, status=status.HTTP_400_BAD_REQUEST)
# In this case we can pre-enroll a non-existing student. This is what the
# CourseEnrollmentAllowed table is for
# NOTE: This logic really should live in CourseEnrollment.....
cea, _ = CourseEnrollmentAllowed.objects.get_or_create(course_id=course_id, email=email)
cea.auto_enroll = True
cea.save()
return Response({}, status.HTTP_201_CREATED)
......@@ -7,6 +7,7 @@ Run these tests @ Devstack:
import simplejson as json
import unittest
import uuid
from random import randint
from django.core.cache import cache
from django.test import TestCase, Client
......@@ -450,3 +451,73 @@ class CoursesApiTests(TestCase):
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 404)
def test_course_enrollments(self):
test_uri = self.base_courses_uri + '/' + self.test_course_id + '/users'
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 200)
self.assertGreater(len(response.data), 0)
# assert that there is no enrolled students
enrollments = response.data['enrollments']
self.assertEqual(len(enrollments), 0)
self.assertNotIn('pending_enrollments', response.data)
# enroll a non-existing student
# first, don't allow non-existing
post_data = {}
post_data['email'] = 'test+pending@tester.com'
post_data['allow_pending'] = False
response = self.do_post(test_uri, post_data)
self.assertEqual(response.status_code, 400)
post_data['allow_pending'] = True
response = self.do_post(test_uri, post_data)
self.assertEqual(response.status_code, 201)
# re-run query
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 200)
self.assertGreater(len(response.data), 0)
# assert that we just have a single pending enrollment
enrollments = response.data['enrollments']
self.assertEqual(len(enrollments), 0)
self.assertIn('pending_enrollments', response.data)
pending = response.data['pending_enrollments']
self.assertEqual(len(pending), 1)
self.assertEqual(pending[0], 'test+pending@tester.com')
# create a new user (note, this calls into the /users/ subsystem)
test_user_uri = '/api/users'
local_username = "some_test_user" + str(randint(11, 99))
local_email = "test+notpending@tester.com"
data = {
'email': local_email,
'username': local_username,
'password': 'fooabr',
'first_name': 'Joe',
'last_name': 'Brown'
}
response = self.do_post(test_user_uri, data)
self.assertEqual(response.status_code, 201)
self.assertGreater(response.data['id'], 0)
created_user_id = response.data['id']
# now register this user
post_data = {}
post_data['user_id'] = created_user_id
response = self.do_post(test_uri, post_data)
self.assertEqual(response.status_code, 201)
# now re-query, we should see it listed now in the list of enrollments
# re-run query
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 200)
self.assertGreater(len(response.data), 0)
# assert that we just have a single pending enrollment
enrollments = response.data['enrollments']
self.assertEqual(len(enrollments), 1)
self.assertEqual(enrollments[0]['id'], created_user_id)
self.assertEqual(enrollments[0]['email'], local_email)
self.assertEqual(enrollments[0]['username'], local_username)
......@@ -105,6 +105,9 @@ def user_list(request):
user.last_name = last_name
user.save()
# CDODGE: @TODO: We will have to extend this to look in the CourseEnrollmentAllowed table and
# auto-enroll students when they create a new account. Also be sure to remove from
# the CourseEnrollmentAllow table after the auto-registration has taken place
if user:
status_code = status.HTTP_201_CREATED
response_data = _serialize_user(response_data, user)
......
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