diff --git a/cms/djangoapps/contentstore/views/assets.py b/cms/djangoapps/contentstore/views/assets.py index 1c22114d76ba..2334c61b4c8d 100644 --- a/cms/djangoapps/contentstore/views/assets.py +++ b/cms/djangoapps/contentstore/views/assets.py @@ -3,6 +3,7 @@ import os import tarfile import shutil +import cgi from tempfile import mkdtemp from path import path @@ -27,7 +28,7 @@ from xmodule.contentstore.content import StaticContent from xmodule.util.date_utils import get_default_time_display from xmodule.modulestore import InvalidLocationError -from xmodule.exceptions import NotFoundError +from xmodule.exceptions import NotFoundError, SerializationError from .access import get_location_and_verify_access from util.json_request import JsonResponse @@ -336,16 +337,59 @@ def generate_export_course(request, org, course, name): the course """ location = get_location_and_verify_access(request, org, course, name) - + course_module = modulestore().get_instance(location.course_id, location) loc = Location(location) export_file = NamedTemporaryFile(prefix=name + '.', suffix=".tar.gz") root_dir = path(mkdtemp()) - # export out to a tempdir - logging.debug('root = {0}'.format(root_dir)) + try: + export_to_xml(modulestore('direct'), contentstore(), loc, root_dir, name, modulestore()) + except SerializationError, e: + unit = None + failed_item = None + parent = None + try: + failed_item = modulestore().get_instance(course_module.location.course_id, e.location) + parent_locs = modulestore().get_parent_locations(failed_item.location, course_module.location.course_id) + + if len(parent_locs) > 0: + parent = modulestore().get_item(parent_locs[0]) + if parent.location.category == 'vertical': + unit = parent + except: + # if we have a nested exception, then we'll show the more generic error message + pass - export_to_xml(modulestore('direct'), contentstore(), loc, root_dir, name, modulestore()) + return render_to_response('export.html', { + 'context_course': course_module, + 'successful_import_redirect_url': '', + 'in_err': True, + 'raw_err_msg': str(e), + 'failed_module': failed_item, + 'unit': unit, + 'edit_unit_url': reverse('edit_unit', kwargs={ + 'location': parent.location + }) if parent else '', + 'course_home_url': reverse('course_index', kwargs={ + 'org': org, + 'course': course, + 'name': name + }) + }) + except Exception, e: + return render_to_response('export.html', { + 'context_course': course_module, + 'successful_import_redirect_url': '', + 'in_err': True, + 'unit': None, + 'raw_err_msg': str(e), + 'course_home_url': reverse('course_index', kwargs={ + 'org': org, + 'course': course, + 'name': name + }) + }) logging.debug('tar file being generated at {0}'.format(export_file.name)) tar_file = tarfile.open(name=export_file.name, mode='w:gz') diff --git a/cms/templates/export.html b/cms/templates/export.html index 593cf3dd6ea4..3356bea42b68 100644 --- a/cms/templates/export.html +++ b/cms/templates/export.html @@ -6,6 +6,62 @@ <%block name="title">${_("Course Export")} <%block name="bodyclass">is-signedin course tools export +<%block name="jsextra"> + % if in_err: + + %endif + + <%block name="content">
@@ -18,6 +74,7 @@

+

${_("About Exporting Courses")}

diff --git a/common/lib/xmodule/xmodule/exceptions.py b/common/lib/xmodule/xmodule/exceptions.py index d0a8e76557ed..48c083cbf11e 100644 --- a/common/lib/xmodule/xmodule/exceptions.py +++ b/common/lib/xmodule/xmodule/exceptions.py @@ -13,6 +13,7 @@ class ProcessingError(Exception): ''' pass + class InvalidVersionError(Exception): """ Tried to save an item with a location that a store cannot support (e.g., draft version @@ -21,3 +22,12 @@ class InvalidVersionError(Exception): def __init__(self, location): super(InvalidVersionError, self).__init__() self.location = location + + +class SerializationError(Exception): + """ + Thrown when a module cannot be exported to XML + """ + def __init__(self, location, msg): + super(SerializationError, self).__init__(msg) + self.location = location diff --git a/common/lib/xmodule/xmodule/raw_module.py b/common/lib/xmodule/xmodule/raw_module.py index b972d7c8eb3a..4c6ddb5b5124 100644 --- a/common/lib/xmodule/xmodule/raw_module.py +++ b/common/lib/xmodule/xmodule/raw_module.py @@ -4,6 +4,7 @@ import logging import sys from xblock.core import String, Scope +from exceptions import SerializationError log = logging.getLogger(__name__) @@ -27,11 +28,11 @@ def definition_to_xml(self, resource_fs): # re-raise lines = self.data.split('\n') line, offset = err.position - msg = ("Unable to create xml for problem {loc}. " + msg = ("Unable to create xml for module {loc}. " "Context: '{context}'".format( context=lines[line - 1][offset - 40:offset + 40], loc=self.location)) - raise Exception, msg, sys.exc_info()[2] + raise SerializationError(self.location, msg) class EmptyDataRawDescriptor(XmlDescriptor, XMLEditingDescriptor):