Merge pull request #589 from edx/fix/cdodge/better-export-error-messaging
give some debug message regarding why export has failed
This commit is contained in:
@@ -3,6 +3,7 @@ import json
|
||||
import os
|
||||
import tarfile
|
||||
import shutil
|
||||
import cgi
|
||||
from tempfile import mkdtemp
|
||||
from path import path
|
||||
|
||||
@@ -27,7 +28,7 @@ from xmodule.modulestore import Location
|
||||
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)
|
||||
|
||||
export_to_xml(modulestore('direct'), contentstore(), loc, root_dir, name, modulestore())
|
||||
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
|
||||
|
||||
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')
|
||||
|
||||
@@ -6,6 +6,62 @@
|
||||
<%block name="title">${_("Course Export")}</%block>
|
||||
<%block name="bodyclass">is-signedin course tools export</%block>
|
||||
|
||||
<%block name="jsextra">
|
||||
% if in_err:
|
||||
<script type='text/javascript'>
|
||||
$(document).ready(function() {
|
||||
|
||||
%if unit:
|
||||
var dialog = new CMS.Views.Prompt({
|
||||
title: gettext('There has been an error while exporting.'),
|
||||
message: gettext("There has been a failure to export to XML at least one component. It is recommended that you go to the edit page and repair the error before attempting another export. Please check that all components on the page are valid and do not display any error messages."),
|
||||
intent: "error",
|
||||
actions: {
|
||||
primary: {
|
||||
text: gettext('Correct failed component'),
|
||||
click: function(view) {
|
||||
view.hide();
|
||||
document.location = "${edit_unit_url}"
|
||||
}
|
||||
},
|
||||
secondary: {
|
||||
text: gettext('Return to Export'),
|
||||
click: function(view) {
|
||||
view.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
% else:
|
||||
var msg = "<p>" + gettext("There has been a failure to export your course to XML. Unfortunately, we do not have specific enough information to assist you in identifying the failed component. It is recommended that you inspect your courseware to identify any components in error and try again.") + "</p><p>" + gettext("The raw error message is:") + "</p>";
|
||||
msg = msg + "${raw_err_msg}";
|
||||
var dialog = new CMS.Views.Prompt({
|
||||
title: gettext('There has been an error with your export.'),
|
||||
message: msg,
|
||||
intent: "error",
|
||||
actions: {
|
||||
primary: {
|
||||
text: gettext('Yes, take me to the main course page'),
|
||||
click: function(view) {
|
||||
view.hide();
|
||||
document.location = "${course_home_url}"
|
||||
}
|
||||
},
|
||||
secondary: {
|
||||
text: gettext('Cancel'),
|
||||
click: function(view) {
|
||||
view.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
%endif
|
||||
dialog.show();
|
||||
})
|
||||
</script>
|
||||
%endif
|
||||
</%block>
|
||||
|
||||
<%block name="content">
|
||||
<div class="wrapper-mast wrapper">
|
||||
<header class="mast has-subtitle">
|
||||
@@ -18,6 +74,7 @@
|
||||
|
||||
<div class="main-wrapper">
|
||||
<div class="inner-wrapper">
|
||||
|
||||
<article class="export-overview">
|
||||
<div class="description">
|
||||
<h2>${_("About Exporting Courses")}</h2>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,6 +4,7 @@ from xmodule.xml_module import XmlDescriptor
|
||||
import logging
|
||||
import sys
|
||||
from xblock.core import String, Scope
|
||||
from exceptions import SerializationError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -27,11 +28,11 @@ class RawDescriptor(XmlDescriptor, XMLEditingDescriptor):
|
||||
# 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):
|
||||
|
||||
Reference in New Issue
Block a user