PROD-448: Gracefully handle exceptions from user-supplied code in

advanced problems so that they do not become uneditable.
This commit is contained in:
Alan Zarembok
2019-07-11 13:09:29 -04:00
parent b92c30de10
commit 95616d7d11
2 changed files with 29 additions and 8 deletions

View File

@@ -387,8 +387,11 @@ class CapaMixin(ScorableXBlockMixin, CapaFields):
"""
For now, just return weighted earned / weighted possible
"""
raw_earned = self.score.raw_earned
raw_possible = self.score.raw_possible
if self.score:
raw_earned = self.score.raw_earned
raw_possible = self.score.raw_possible
else:
raw_earned = raw_possible = 0
if raw_possible > 0:
if self.weight is not None:
@@ -439,6 +442,18 @@ class CapaMixin(ScorableXBlockMixin, CapaFields):
'graded': self.graded,
})
def handle_fatal_lcp_error(self, error):
if error:
return(
HTML(u'<p>Error formatting HTML for problem:</p><p><pre style="color:red">{msg}</pre></p>').format(
msg=text_type(error))
)
else:
return HTML(
u'<p>Could not format HTML for problem. '
u'Contact course staff in the discussion forum for assistance.</p>'
)
def submit_button_name(self):
"""
Determine the name for the "submit" button.
@@ -549,8 +564,8 @@ class CapaMixin(ScorableXBlockMixin, CapaFields):
# TODO (vshnayder): another switch on DEBUG.
if self.runtime.DEBUG:
msg = HTML(
u'[courseware.capa.capa_module] <font size="+1" color="red">'
u'Failed to generate HTML for problem {url}</font>'
u'[courseware.capa.capa_module] '
u'Failed to generate HTML for problem {url}'
).format(
url=text_type(self.location)
)
@@ -564,6 +579,7 @@ class CapaMixin(ScorableXBlockMixin, CapaFields):
# Presumably, student submission has corrupted LoncapaProblem HTML.
# First, pull down all student answers
student_answers = self.lcp.student_answers
answer_ids = list(student_answers.keys())

View File

@@ -103,13 +103,18 @@ class ProblemBlock(
if 'lcp' in self.__dict__:
del self.__dict__['lcp']
def student_view(self, _context):
def student_view(self, _context, show_detailed_errors=False):
"""
Return the student view.
"""
# self.score is initialized in self.lcp but in this method is accessed before self.lcp so just call it first.
self.lcp
fragment = Fragment(self.get_html())
try:
self.lcp
except Exception as err:
html = self.handle_fatal_lcp_error(err if show_detailed_errors else None)
else:
html = self.get_html()
fragment = Fragment(html)
add_webpack_to_fragment(fragment, 'ProblemBlockPreview')
shim_xmodule_js(fragment, 'Problem')
return fragment
@@ -118,7 +123,7 @@ class ProblemBlock(
"""
Renders the Studio preview view.
"""
return self.student_view(context)
return self.student_view(context, show_detailed_errors=True)
def studio_view(self, _context):
"""