From e3a311d28347a9bd128a26281b914265c93801e6 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Fri, 4 Jan 2013 11:40:49 -0500 Subject: [PATCH] Start creating open ended xmodule --- common/lib/xmodule/open_ended_module.py | 128 ++++++++++++++++++ .../xmodule/xmodule/self_assessment_module.py | 9 +- 2 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 common/lib/xmodule/open_ended_module.py diff --git a/common/lib/xmodule/open_ended_module.py b/common/lib/xmodule/open_ended_module.py new file mode 100644 index 0000000000..e728a8dba3 --- /dev/null +++ b/common/lib/xmodule/open_ended_module.py @@ -0,0 +1,128 @@ +""" +A Self Assessment module that allows students to write open-ended responses, +submit, then see a rubric and rate themselves. Persists student supplied +hints, answers, and assessment judgment (currently only correct/incorrect). +Parses xml definition file--see below for exact format. +""" + +import copy +from fs.errors import ResourceNotFoundError +import itertools +import json +import logging +from lxml import etree +from lxml.html import rewrite_links +from path import path +import os +import sys + +from pkg_resources import resource_string + +from .capa_module import only_one, ComplexEncoder +from .editing_module import EditingDescriptor +from .html_checker import check_html +from progress import Progress +from .stringify import stringify_children +from .x_module import XModule +from .xml_module import XmlDescriptor +from xmodule.modulestore import Location + +log = logging.getLogger("mitx.courseware") + +# Set the default number of max attempts. Should be 1 for production +# Set higher for debugging/testing +# attempts specified in xml definition overrides this. +MAX_ATTEMPTS = 1 + +# Set maximum available number of points. +# Overriden by max_score specified in xml. +MAX_SCORE = 1 + +class OpenEndedModule(): + """ + States: + + initial (prompt, textbox shown) + | + assessing (read-only textbox, rubric + assessment input shown) + | + request_hint (read-only textbox, read-only rubric and assessment, hint input box shown) + | + done (submitted msg, green checkmark, everything else read-only. If attempts < max, shows + a reset button that goes back to initial state. Saves previous + submissions too.) + """ + + DEFAULT_QUEUE = 'open-ended' + DEFAULT_MESSAGE_QUEUE = 'open-ended-message' + response_tag = 'openendedresponse' + allowed_inputfields = ['openendedinput'] + max_inputfields = 1 + + STATE_VERSION = 1 + + # states + INITIAL = 'initial' + ASSESSING = 'assessing' + REQUEST_HINT = 'post_assessment' + DONE = 'done' + + def __init__(self, system, location, definition, descriptor, + instance_state=None, shared_state=None, **kwargs): + """ + Definition file should have 4 blocks -- prompt, rubric, submitmessage, hintprompt, + and two optional attributes: + attempts, which should be an integer that defaults to 1. + If it's > 1, the student will be able to re-submit after they see + the rubric. + max_score, which should be an integer that defaults to 1. + It defines the maximum number of points a student can get. Assumed to be integer scale + from 0 to max_score, with an interval of 1. + + Note: all the submissions are stored. + + Sample file: + + + + Insert prompt text here. (arbitrary html) + + + Insert grading rubric here. (arbitrary html) + + + Please enter a hint below: (arbitrary html) + + + Thanks for submitting! (arbitrary html) + + + """ + + # Load instance state + if instance_state is not None: + instance_state = json.loads(instance_state) + else: + instance_state = {} + + instance_state = self.convert_state_to_current_format(instance_state) + + # History is a list of tuples of (answer, score, hint), where hint may be + # None for any element, and score and hint can be None for the last (current) + # element. + # Scores are on scale from 0 to max_score + self.history = instance_state.get('history', []) + + self.state = instance_state.get('state', 'initial') + + self.attempts = instance_state.get('attempts', 0) + self.max_attempts = int(instance_state.get('attempts', MAX_ATTEMPTS)) + + # Used for progress / grading. Currently get credit just for + # completion (doesn't matter if you self-assessed correct/incorrect). + self._max_score = int(instance_state.get('max_score', MAX_SCORE)) + + self.rubric = definition['rubric'] + self.prompt = definition['prompt'] + self.submit_message = definition['submitmessage'] + self.hint_prompt = definition['hintprompt'] \ No newline at end of file diff --git a/common/lib/xmodule/xmodule/self_assessment_module.py b/common/lib/xmodule/xmodule/self_assessment_module.py index 64cf140d38..0b7cc90994 100644 --- a/common/lib/xmodule/xmodule/self_assessment_module.py +++ b/common/lib/xmodule/xmodule/self_assessment_module.py @@ -93,15 +93,18 @@ class SelfAssessmentModule(): """ + self.xml = xml + self.inputfields = inputfields + self.context = context + self.system = system + # Load instance state if instance_state is not None: instance_state = json.loads(instance_state) else: instance_state = {} - instance_state = self.convert_state_to_current_format(instance_state) - - # History is a list of tuples of (answer, score, hint), where hint may be + # History is a list of tuples of (answer, score, feedback), where hint may be # None for any element, and score and hint can be None for the last (current) # element. # Scores are on scale from 0 to max_score