Commit 10b417c8 by Chris Dodge

initial checkin of export

parent 95c67194
###
### Script for exporting courseware from Mongo to a tar.gz file
###
import os
from django.core.management.base import BaseCommand, CommandError
from xmodule.modulestore.xml_exporter import export_to_xml
from xmodule.modulestore.django import modulestore
from xmodule.contentstore.django import contentstore
from xmodule.modulestore import Location
from xmodule.course_module import CourseDescriptor
unnamed_modules = 0
class Command(BaseCommand):
help = \
'''Import the specified data directory into the default ModuleStore'''
def handle(self, *args, **options):
if len(args) != 2:
raise CommandError("import requires two arguments: <course location> <output path>")
course_id = args[0]
output_path = args[1]
print "Exporting course id = {0} to {1}".format(course_id, output_path)
location = CourseDescriptor.id_to_location(course_id)
root_dir = os.path.dirname(output_path)
course_dir = os.path.splitext(os.path.basename(output_path))[0]
export_to_xml(modulestore('direct'), contentstore(), location, root_dir, course_dir)
...@@ -12,6 +12,7 @@ import logging ...@@ -12,6 +12,7 @@ import logging
from .content import StaticContent, ContentStore from .content import StaticContent, ContentStore
from xmodule.exceptions import NotFoundError from xmodule.exceptions import NotFoundError
from fs.osfs import OSFS from fs.osfs import OSFS
import os
class MongoContentStore(ContentStore): class MongoContentStore(ContentStore):
...@@ -47,16 +48,30 @@ class MongoContentStore(ContentStore): ...@@ -47,16 +48,30 @@ class MongoContentStore(ContentStore):
with self.fs.get(id) as fp: with self.fs.get(id) as fp:
return StaticContent(location, fp.displayname, fp.content_type, fp.read(), return StaticContent(location, fp.displayname, fp.content_type, fp.read(),
fp.uploadDate, thumbnail_location = fp.thumbnail_location if 'thumbnail_location' in fp else None, fp.uploadDate, thumbnail_location = fp.thumbnail_location if 'thumbnail_location' in fp else None,
import_path = fp.import_path if 'import_path' in fp else None) import_path = fp.import_path if hasattr(fp, 'import_path') else None)
except NoFile: except NoFile:
raise NotFoundError() raise NotFoundError()
def export(self, location, output_directory): def export(self, location, output_directory):
content = self.find(location) content = self.find(location)
if content.import_path is not None:
output_directory = output_directory + '/' + os.path.dirname(content.import_path)
if not os.path.exists(output_directory):
os.makedirs(output_directory)
disk_fs = OSFS(output_directory) disk_fs = OSFS(output_directory)
with disk_fs.open('course.xml', 'wb') as course_xml: with disk_fs.open(content.name, 'wb') as asset_file:
course_xml.write(content.data) asset_file.write(content.data)
def export_all_for_course(self, course_location, output_directory):
assets = self.get_all_content_for_course(course_location)
for asset in assets:
asset_location = Location(asset['_id'])
self.export(asset_location, output_directory)
def get_all_content_thumbnails_for_course(self, location): def get_all_content_thumbnails_for_course(self, location):
return self._get_all_content_for_course(location, get_thumbnails = True) return self._get_all_content_for_course(location, get_thumbnails = True)
......
import logging
from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore
from fs.osfs import OSFS
def export_to_xml(modulestore, contentstore, course_location, root_dir, course_dir):
course = modulestore.get_item(course_location)
fs = OSFS(root_dir)
export_fs = fs.makeopendir(course_dir)
xml = course.export_to_xml(export_fs)
with export_fs.open('course.xml', 'w') as course_xml:
course_xml.write(xml)
# export the static assets
contentstore.export_all_for_course(course_location, root_dir + '/' + course_dir + '/static/')
\ No newline at end of file
...@@ -102,6 +102,8 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -102,6 +102,8 @@ class XmlDescriptor(XModuleDescriptor):
# VS[compat] -- remove the below attrs once everything is in the CMS # VS[compat] -- remove the below attrs once everything is in the CMS
'course', 'org', 'url_name', 'filename') 'course', 'org', 'url_name', 'filename')
metadata_to_export_to_policy = ('discussion_topics')
# A dictionary mapping xml attribute names AttrMaps that describe how # A dictionary mapping xml attribute names AttrMaps that describe how
# to import and export them # to import and export them
# Allow json to specify either the string "true", or the bool True. The string is preferred. # Allow json to specify either the string "true", or the bool True. The string is preferred.
...@@ -112,6 +114,7 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -112,6 +114,7 @@ class XmlDescriptor(XModuleDescriptor):
# type conversion: want True/False in python, "true"/"false" in xml # type conversion: want True/False in python, "true"/"false" in xml
'graded': bool_map, 'graded': bool_map,
'hide_progress_tab': bool_map, 'hide_progress_tab': bool_map,
'allow_anonymous': bool_map
} }
...@@ -359,8 +362,9 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -359,8 +362,9 @@ class XmlDescriptor(XModuleDescriptor):
# Add the non-inherited metadata # Add the non-inherited metadata
for attr in sorted(self.own_metadata): for attr in sorted(self.own_metadata):
# don't want e.g. data_dir # don't want e.g. data_dir
if attr not in self.metadata_to_strip: if attr not in self.metadata_to_strip and attr not in self.metadata_to_export_to_policy:
val = val_for_xml(attr) val = val_for_xml(attr)
# logging.debug('location.category = {0}, attr = {1}'.format(self.location.category, attr))
xml_object.set(attr, val) xml_object.set(attr, val)
if self.export_to_file(): if self.export_to_file():
......
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