question: Add the Question.multimedia attribute master
authorW. Trevor King <wking@tremily.us>
Fri, 26 Apr 2013 12:46:06 +0000 (08:46 -0400)
committerW. Trevor King <wking@tremily.us>
Fri, 26 Apr 2013 12:46:06 +0000 (08:46 -0400)
commit3fcfd9ceeb8e80eb15f38bf9bd396b62fb5bc0dc
treeec9785109fcaf559dbe2b3fe707475fe5a9142de
parente6a60a981745bdc7c0983bf14c9705cfc427b9c4
question: Add the Question.multimedia attribute

Many questions have figures associated with the prompt text or the
answer choices.  This attribute provides a means to link to these
multimedia assets from the question.  Here's an example from the force
concept inventory, which I'm currently transcribing:

    {
      "class": "ChoiceQuestion",
      "id": "sling shot",
      "prompt": "A heavy ball is attached to a string...",
      "multimedia": [
        {
          "content-type": "image/png",
          "path": "force-concept-inventory/04.png"
        }
      ],
      "display_choices": true,
      "answer": [
        "(A) in the figure",
        "(B) in the figure",
        "(C) in the figure",
        "(D) in the figure",
        "(E) in the figure"
      ]
    }

The 'multimedia' attribute is an array because a question might
conceivably reference several assets (e.g. an image and an audio clip,
or multiple images).

To display the assets alongside the question, I've refactored the WSGI
handler to pull out QuestionApp._format_prompt(), which in turn
delegates to the new QuestionApp._format_multimedia().  This embeds a
link to the asset, using a MIME-appropriate container (currently just
<img> for image/* types).  The assets themselves are served as
media/<HASH>, where I hash the whole multimedia-defining dictionary to
avoid information leakage which might otherwise help in solving the
problem.  Using hash-based URLs also avoids problems with special
characters in the multimedia data.

In the CLI handler, we can't inline multimedia.  I use the user's
mailcap configuration (RFC 1524) to spawn their preferred
MIME-appropriate viewer when the prompt for a new question is being
generated.  If the user hasn't configured a viewer for the MIME type
in question, we just print a message referring to the asset by its
full path and let the user take it from there.

The mailcap viewer is adapted from an example I initially posted on my
blog in 2011 [1].  The path-quoting follows the Mutt docs [2]:

> The interpretion of shell meta-characters embedded in MIME
> parameters can lead to security problems in general. Mutt tries to
> quote parameters in expansion of `%s` syntaxes properly, and avoids
> risky characters by substituting them, see the `mailcap_sanitize`
> variable.

[1]: http://blog.tremily.us/posts/mailcap/mailcap-test.py
[2]: http://www.mutt.org/doc/manual/manual-5.html
quizzer/question.py
quizzer/quiz.py
quizzer/ui/cli.py
quizzer/ui/util.py [new file with mode: 0644]
quizzer/ui/wsgi.py