MDL-43733 use any auto-saved responses when questions are finished.

Before this, autosave was only working to save data when a student went
back in to continue an attempt. If the student, having crashed out,
never went back in and continued the attempt, their auto-saved responses
were not used when the attempt was automatically finished. That was a
rather bad oversight, which should now be fixed.
This commit is contained in:
Tim Hunt 2014-01-17 16:58:13 +00:00
parent f05e25d208
commit 3d96b4945a
2 changed files with 76 additions and 0 deletions

View file

@ -869,6 +869,24 @@ class question_attempt {
$this->observer->notify_step_deleted($autosaved, $this); $this->observer->notify_step_deleted($autosaved, $this);
} }
/**
* If there is an autosaved step, convert it into a real save, so that it
* is preserved.
*/
protected function convert_autosaved_step_to_real_step() {
if ($this->autosavedstep === null) {
return;
}
$laststep = end($this->steps);
if ($laststep !== $this->autosavedstep) {
throw new coding_exception('Cannot convert autosaved step to real step, since other steps have been added.');
}
$this->observer->notify_step_modified($this->autosavedstep, $this, key($this->steps));
$this->autosavedstep = null;
}
/** /**
* Use a strategy to pick a variant. * Use a strategy to pick a variant.
* @param question_variant_selection_strategy $variantstrategy a strategy. * @param question_variant_selection_strategy $variantstrategy a strategy.
@ -1174,6 +1192,7 @@ class question_attempt {
* @param int $userid the user to attribute the aciton to. (If not given, use the current user.) * @param int $userid the user to attribute the aciton to. (If not given, use the current user.)
*/ */
public function finish($timestamp = null, $userid = null) { public function finish($timestamp = null, $userid = null) {
$this->convert_autosaved_step_to_real_step();
$this->process_action(array('-finish' => 1), $timestamp, $userid); $this->process_action(array('-finish' => 1), $timestamp, $userid);
} }

View file

@ -628,4 +628,61 @@ class question_usage_autosave_test extends qbehaviour_walkthrough_test_base {
$this->delete_quba(); $this->delete_quba();
} }
public function test_finish_with_unhandled_autosave_data() {
$this->resetAfterTest();
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $generator->create_question_category();
$question = $generator->create_question('shortanswer', null,
array('category' => $cat->id));
// Start attempt at a shortanswer question.
$q = question_bank::load_question($question->id);
$this->start_attempt_at_question($q, 'deferredfeedback', 1);
$this->check_current_state(question_state::$todo);
$this->check_current_mark(null);
$this->check_step_count(1);
// Process a response and check the expected result.
$this->process_submission(array('answer' => 'cat'));
$this->check_current_state(question_state::$complete);
$this->check_current_mark(null);
$this->check_step_count(2);
$this->save_quba();
// Now check how that is re-displayed.
$this->render();
$this->check_output_contains_text_input('answer', 'cat');
$this->check_output_contains_hidden_input(':sequencecheck', 2);
// Process an autosave.
$this->load_quba();
$this->process_autosave(array('answer' => 'frog'));
$this->check_current_state(question_state::$complete);
$this->check_current_mark(null);
$this->check_step_count(3);
$this->save_quba();
// Now check how that is re-displayed.
$this->load_quba();
$this->render();
$this->check_output_contains_text_input('answer', 'frog');
$this->check_output_contains_hidden_input(':sequencecheck', 2);
// Now finishe the attempt, without having done anything since the autosave.
$this->finish();
$this->save_quba();
// Now check how that has been graded and is re-displayed.
$this->load_quba();
$this->check_current_state(question_state::$gradedright);
$this->check_current_mark(1);
$this->render();
$this->check_output_contains_text_input('answer', 'frog', false);
$this->check_output_contains_hidden_input(':sequencecheck', 4);
$this->delete_quba();
}
} }