Merge pull request #2216 from edx/andya/move-service
Implement a course outline REST API
This commit is contained in:
@@ -6,7 +6,7 @@ import lxml
|
||||
|
||||
from contentstore.tests.utils import CourseTestCase
|
||||
from xmodule.modulestore.django import loc_mapper
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
from xmodule.modulestore import parsers
|
||||
|
||||
class TestCourseIndex(CourseTestCase):
|
||||
@@ -83,3 +83,49 @@ class TestCourseIndex(CourseTestCase):
|
||||
|
||||
# test access
|
||||
self.check_index_and_outline(course_staff_client)
|
||||
|
||||
def test_json_responses(self):
|
||||
outline_url = self.course_locator.url_reverse('course/')
|
||||
chapter = ItemFactory.create(parent_location=self.course.location, category='chapter', display_name="Week 1")
|
||||
lesson = ItemFactory.create(parent_location=chapter.location, category='sequential', display_name="Lesson 1")
|
||||
subsection = ItemFactory.create(parent_location=lesson.location, category='vertical', display_name='Subsection 1')
|
||||
ItemFactory.create(parent_location=subsection.location, category="video", display_name="My Video")
|
||||
|
||||
resp = self.client.get(outline_url, HTTP_ACCEPT='application/json')
|
||||
json_response = json.loads(resp.content)
|
||||
|
||||
# First spot check some values in the root response
|
||||
self.assertEqual(json_response['category'], 'course')
|
||||
self.assertEqual(json_response['id'], 'MITx.999.Robot_Super_Course/branch/draft/block/Robot_Super_Course')
|
||||
self.assertEqual(json_response['display_name'], 'Robot Super Course')
|
||||
self.assertTrue(json_response['is_container'])
|
||||
self.assertFalse(json_response['is_draft'])
|
||||
|
||||
# Now verify that the first child
|
||||
children = json_response['children']
|
||||
self.assertTrue(len(children) > 0)
|
||||
first_child_response = children[0]
|
||||
self.assertEqual(first_child_response['category'], 'chapter')
|
||||
self.assertEqual(first_child_response['id'], 'MITx.999.Robot_Super_Course/branch/draft/block/Week_1')
|
||||
self.assertEqual(first_child_response['display_name'], 'Week 1')
|
||||
self.assertTrue(first_child_response['is_container'])
|
||||
self.assertFalse(first_child_response['is_draft'])
|
||||
self.assertTrue(len(first_child_response['children']) > 0)
|
||||
|
||||
# Finally, validate the entire response for consistency
|
||||
self.assert_correct_json_response(json_response)
|
||||
|
||||
def assert_correct_json_response(self, json_response):
|
||||
"""
|
||||
Asserts that the JSON response is syntactically consistent
|
||||
"""
|
||||
self.assertIsNotNone(json_response['display_name'])
|
||||
self.assertIsNotNone(json_response['id'])
|
||||
self.assertIsNotNone(json_response['category'])
|
||||
self.assertIsNotNone(json_response['is_draft'])
|
||||
self.assertIsNotNone(json_response['is_container'])
|
||||
if json_response['is_container']:
|
||||
for child_response in json_response['children']:
|
||||
self.assert_correct_json_response(child_response)
|
||||
else:
|
||||
self.assertFalse('children' in json_response)
|
||||
|
||||
@@ -100,9 +100,10 @@ def course_handler(request, tag=None, package_id=None, branch=None, version_guid
|
||||
DELETE
|
||||
json: delete this branch from this course (leaving off /branch/draft would imply delete the course)
|
||||
"""
|
||||
if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'):
|
||||
response_format = request.REQUEST.get('format', 'html')
|
||||
if response_format == 'json' or 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'):
|
||||
if request.method == 'GET':
|
||||
raise NotImplementedError('coming soon')
|
||||
return JsonResponse(_course_json(request, package_id, branch, version_guid, block))
|
||||
elif request.method == 'POST': # not sure if this is only post. If one will have ids, it goes after access
|
||||
return create_new_course(request)
|
||||
elif not has_course_access(
|
||||
@@ -125,6 +126,37 @@ def course_handler(request, tag=None, package_id=None, branch=None, version_guid
|
||||
return HttpResponseNotFound()
|
||||
|
||||
|
||||
@login_required
|
||||
def _course_json(request, package_id, branch, version_guid, block):
|
||||
"""
|
||||
Returns a JSON overview of a course
|
||||
"""
|
||||
__, course = _get_locator_and_course(
|
||||
package_id, branch, version_guid, block, request.user, depth=None
|
||||
)
|
||||
return _xmodule_json(course, course.location.course_id)
|
||||
|
||||
|
||||
def _xmodule_json(xmodule, course_id):
|
||||
"""
|
||||
Returns a JSON overview of an XModule
|
||||
"""
|
||||
locator = loc_mapper().translate_location(
|
||||
course_id, xmodule.location, published=False, add_entry_if_missing=True
|
||||
)
|
||||
is_container = xmodule.has_children
|
||||
result = {
|
||||
'display_name': xmodule.display_name,
|
||||
'id': unicode(locator),
|
||||
'category': xmodule.category,
|
||||
'is_draft': getattr(xmodule, 'is_draft', False),
|
||||
'is_container': is_container,
|
||||
}
|
||||
if is_container:
|
||||
result['children'] = [_xmodule_json(child, course_id) for child in xmodule.get_children()]
|
||||
return result
|
||||
|
||||
|
||||
@login_required
|
||||
@ensure_csrf_cookie
|
||||
def course_listing(request):
|
||||
|
||||
Reference in New Issue
Block a user