Capa (Problem) Architecture

This page is meant to capture the current architecture of capa problems within the LMS and Studio.

UML Diagram

Overview

With Methods

Rendering of a Capa Problem

The following chart shows the breakdown of templates used when rendering the sections of a Capa Problem.

Message Flow Diagram of Rendering

Other client interactions that follow the same basic pattern as "Submit" are:

  • Submit with file submission (after doing validation of the file(s) selected, calls problem_check).
  • Problem reset (calls problem_reset).
  • Render if no HTML content is provided to the method (calls problem_get), though it is not clear if this code path gets executed anymore with caching of content HTML.

Client interactions that do not re-render the problem HTML in the ajax callback handler:

  • Show answer (calls problem_show). In the ajax callback handler, injects answers into the HTML that is already being displayed.
  • Save answer (calls problem_save). In the ajax callback handler, shows the save notification in the HTML that is already being displayed.
  • Show hint (calls hint_button). In the ajax callback handler, shows the hint area in the HTML that is already being displayed

Submit with poll, used by Python Custom Grader

The polling will continue until the problem is graded (with exponential back off on polling times)

Response Types

Response TypeTagsAllowed Input Fields
CodeResponse
coderesponse
'textbox', 'filesubmission', 'matlabinput'
NumericalResponse
numericalresponse
'textline', 'formulaequationinput'
FormulaResponse
formularesponse
'textline', 'formulaequationinput'
CustomResponse
customresponse
'textline', 'textbox', 'crystallography',
'chemicalequationinput', 'vsepr_input',
'drag_and_drop_input', 'editamoleculeinput',
'designprotein2dinput', 'editageneinput',
'annotationinput', 'jsinput', 'formulaequationinput'
SchematicResponse
schematicresponse
schematic
ExternalResponse
externalresponse
'textline', 'textbox'
ImageResponse
imageresponse
imageinput
OptionResponse
optionresponse
optioninput
SymbolicResponse
symbolicresponse

StringResponse
stringresponse
textline
ChoiceResponse
choiceresponse
'checkboxgroup', 'radiogroup'
MultipleChoiceResponse
multiplechoiceresponse
choicegroup
TrueFalseResponse
truefalseresponse

AnnotationResponse
annotationresponse
annotationinput
ChoiceTextResponse
choicetextresponse
'choicetextgroup',
'checkboxtextgroup',
'radiotextgroup',

Markdown Lifecycle

Markdown is stored in CapaFields as an XBlock field with scope Scope.settings:

markdown = String(help=_("Markdown source of this module"), default=None, scope=Scope.settings)

It gets sent to the front end in the CapaDescriptor context.

def get_context(self):
    _context = RawDescriptor.get_context(self)
    _context.update({
        'markdown': self.markdown,
        'enable_markdown': self.markdown is not None,
        'enable_latex_compiler': self.use_latex_compiler,
    })
    return _context

In Studio, "Common Problem Types" expose the markdown initially; clicking on "Advanced Editor" will convert the markdown to XML (and if saved, there is no way to go back to markdown). Note that when a problem is first instantiated, it is possible for the markdown not to match the stored XML, which is stored in "data" (this was the case for some of our templates). Once the problem is first saved, the markdown is converted to XML, and at that point they are guaranteed to match.

Conversion of markdown to XML happens in MarkdownEditingDescriptor.markdownToXml (in problem/edit.js), via regular expressions. It is persisted on the server side when when Save is pressed, if the markdown editor is being displayed.

if (this.current_editor === this.markdown_editor) {
    return {
        data: MarkdownEditingDescriptor.markdownToXml(this.markdown_editor.getValue()),
        metadata: {
            markdown: this.markdown_editor.getValue()
        }
    };
} else {
    return {
        data: this.xml_editor.getValue(),
        nullout: ['markdown']
    };
}

Additional resources