diff --git a/common/lib/xmodule/xmodule/contentstore/content.py b/common/lib/xmodule/xmodule/contentstore/content.py index 9badd4b..aedb4bc 100644 --- a/common/lib/xmodule/xmodule/contentstore/content.py +++ b/common/lib/xmodule/xmodule/contentstore/content.py @@ -12,13 +12,16 @@ from .django import contentstore from PIL import Image class StaticContent(object): - def __init__(self, loc, name, content_type, data, last_modified_at=None, thumbnail_location=None): + def __init__(self, loc, name, content_type, data, last_modified_at=None, thumbnail_location=None, import_path=None): self.location = loc self.name = name #a display string which can be edited, and thus not part of the location which needs to be fixed self.content_type = content_type self.data = data self.last_modified_at = last_modified_at self.thumbnail_location = thumbnail_location + # optional information about where this file was imported from. This is needed to support import/export + # cycles + self.import_path = import_path @property def is_thumbnail(self): diff --git a/common/lib/xmodule/xmodule/contentstore/mongo.py b/common/lib/xmodule/xmodule/contentstore/mongo.py index bd8e9dc..1579efa 100644 --- a/common/lib/xmodule/xmodule/contentstore/mongo.py +++ b/common/lib/xmodule/xmodule/contentstore/mongo.py @@ -11,6 +11,7 @@ import logging from .content import StaticContent, ContentStore from xmodule.exceptions import NotFoundError +from fs.osfs import OSFS class MongoContentStore(ContentStore): @@ -33,7 +34,7 @@ class MongoContentStore(ContentStore): self.fs.delete(id) with self.fs.new_file(_id = id, filename=content.get_url_path(), content_type=content.content_type, - displayname=content.name, thumbnail_location=content.thumbnail_location) as fp: + displayname=content.name, thumbnail_location=content.thumbnail_location, import_path=content.import_path) as fp: fp.write(content.data) @@ -45,10 +46,18 @@ class MongoContentStore(ContentStore): try: with self.fs.get(id) as fp: 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) except NoFile: raise NotFoundError() + def export(self, location, output_directory): + content = self.find(location) + disk_fs = OSFS(output_directory) + + with disk_fs.open('course.xml', 'wb') as course_xml: + course_xml.write(content.data) + def get_all_content_thumbnails_for_course(self, location): return self._get_all_content_for_course(location, get_thumbnails = True) diff --git a/common/lib/xmodule/xmodule/modulestore/xml_importer.py b/common/lib/xmodule/xmodule/modulestore/xml_importer.py index 3f1229b..35375d7 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_importer.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_importer.py @@ -32,7 +32,7 @@ def import_static_content(modules, course_loc, course_data_path, static_content_ with open(content_path, 'rb') as f: data = f.read() - content = StaticContent(content_loc, filename, mime_type, data) + content = StaticContent(content_loc, filename, mime_type, data, import_path = fullname_with_subpath) # first let's save a thumbnail so we can get back a thumbnail location thumbnail_content = static_content_store.generate_thumbnail(content) @@ -66,7 +66,7 @@ def verify_content_links(module, base_dir, static_content_store, link, remap_dic with open(static_pathname, 'rb') as f: data = f.read() - content = StaticContent(content_loc, filename, mime_type, data) + content = StaticContent(content_loc, filename, mime_type, data, import_path = path) # first let's save a thumbnail so we can get back a thumbnail location thumbnail_content = static_content_store.generate_thumbnail(content) diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py index c56803f..1143e05 100644 --- a/common/lib/xmodule/xmodule/xml_module.py +++ b/common/lib/xmodule/xmodule/xml_module.py @@ -98,7 +98,7 @@ class XmlDescriptor(XModuleDescriptor): metadata_to_strip = ('data_dir', # cdodge: @TODO: We need to figure out a way to export out 'tabs' and 'grading_policy' which is on the course - 'tabs', 'grading_policy', + 'tabs', 'grading_policy', 'is_draft', 'published_by', 'published_date', # VS[compat] -- remove the below attrs once everything is in the CMS 'course', 'org', 'url_name', 'filename') diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index 6de3090..643382b 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -148,7 +148,7 @@ def get_course_about_section(course, section_key): request = get_request_for_thread() loc = course.location._replace(category='about', name=section_key) - course_module = get_module(request.user, request, loc, None, course.id, not_found_ok = True, wrap_xmodule_display = False) + course_module = get_module(request.user, request, loc, None, course.id, not_found_ok = True, wrap_xmodule_display = True) html = '' @@ -186,7 +186,7 @@ def get_course_info_section(request, cache, course, section_key): loc = Location(course.location.tag, course.location.org, course.location.course, 'course_info', section_key) - course_module = get_module(request.user, request, loc, cache, course.id, wrap_xmodule_display = False) + course_module = get_module(request.user, request, loc, cache, course.id, wrap_xmodule_display = True) html = '' if course_module is not None: diff --git a/rakefile b/rakefile index fa8bb4f..8cff178 100644 --- a/rakefile +++ b/rakefile @@ -422,6 +422,18 @@ namespace :cms do end end +namespace :cms do + desc "Export course data to a tar.gz file" + task :export do + if ENV['COURSE_ID'] and ENV['OUTPUT_PATH'] + sh(django_admin(:cms, :dev, :export, ENV['COURSE_ID'], ENV['OUTPUT_PATH'])) + else + raise "Please specify a COURSE_ID and OUTPUT_PATH.\n" + + "Example: \`rake cms:export COURSE_ID=MITx/12345/name OUTPUT_PATH=foo.tar.gz\`" + end + end +end + desc "Build a properties file used to trigger autodeploy builds" task :autodeploy_properties do File.open("autodeploy.properties", "w") do |file|