Commit 8cc86082 by Carlos Andrés Rocha

Add command to dump the structure of a course as a JSON

parent 956a960c
"""
A Django command that dumps the structure of a course as a JSON object.
The resulting JSON object has one entry for each module in the course:
{
"$module_url": {
"category": "$module_category",
"children": [$module_children_urls... ],
"metadata": {$module_metadata}
},
"$module_url": ....
...
}
"""
import json
from optparse import make_option
from textwrap import dedent
from django.core.management.base import BaseCommand, CommandError
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.inheritance import own_metadata
FILTER_LIST = ['xml_attributes', 'checklists']
class Command(BaseCommand):
"""
Write out to stdout a structural and metadata information for a
course as a JSON object
"""
args = "<course_id>"
help = dedent(__doc__).strip()
option_list = BaseCommand.option_list + (
make_option('--modulestore',
action='store',
default='default',
help='Name of the modulestore'),
)
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError("course_id not specified")
# Get the modulestore
try:
name = options['modulestore']
store = modulestore(name)
except KeyError:
raise CommandError("Unknown modulestore {}".format(name))
# Get the course data
course_id = args[0]
course = store.get_course(course_id)
if course is None:
raise CommandError("Invalid course_id")
# Convert course data to dictionary and dump it as JSON to stdout
info = dump_module(course)
return json.dumps(info, indent=2, sort_keys=True)
def dump_module(module, destination=None):
"""
Add the module and all its children to the destination dictionary in
as a flat structure.
"""
destination = destination if destination else {}
items = own_metadata(module).iteritems()
filtered_metadata = {k: v for k, v in items if k not in FILTER_LIST}
destination[module.location.url()] = {
'category': module.location.category,
'children': module.children if hasattr(module, 'children') else [],
'metadata': filtered_metadata
}
for child in module.get_children():
dump_module(child, destination)
return destination
"""Tests for Django management commands"""
import json
from StringIO import StringIO
from django.core.management import call_command
......@@ -43,3 +44,30 @@ class CommandsTestCase(CommandTestCase):
output = self.call_command('dump_course_ids', **kwargs)
dumped_courses = output.strip().split('\n')
self.assertEqual(self.loaded_courses, dumped_courses)
def test_dump_course_structure(self):
args = ['edX/simple/2012_Fall']
kwargs = {'modulestore': 'default'}
output = self.call_command('dump_course_structure', *args, **kwargs)
dump = json.loads(output)
# Check a few elements in the course dump
parent_id = 'i4x://edX/simple/chapter/Overview'
self.assertEqual(dump[parent_id]['category'], 'chapter')
self.assertEqual(len(dump[parent_id]['children']), 3)
child_id = dump[parent_id]['children'][1]
self.assertEqual(dump[child_id]['category'], 'videosequence')
self.assertEqual(len(dump[child_id]['children']), 2)
video_id = 'i4x://edX/simple/video/Welcome'
self.assertEqual(dump[video_id]['category'], 'video')
self.assertEqual(len(dump[video_id]['metadata']), 4)
self.assertIn('youtube_id_1_0', dump[video_id]['metadata'])
# Check if there is the right number of elements
self.assertEqual(len(dump), 16)
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