Exemplo n.º 1
0
 /**
  * Test update question flag
  */
 public function test_core_question_update_flag()
 {
     $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
     // Create a question category.
     $cat = $questiongenerator->create_question_category();
     $quba = question_engine::make_questions_usage_by_activity('core_question_update_flag', context_system::instance());
     $quba->set_preferred_behaviour('deferredfeedback');
     $questiondata = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     $question = question_bank::load_question($questiondata->id);
     $slot = $quba->add_question($question);
     $qa = $quba->get_question_attempt($slot);
     self::setUser($this->student);
     $quba->start_all_questions();
     question_engine::save_questions_usage_by_activity($quba);
     $qubaid = $quba->get_id();
     $questionid = $question->id;
     $qaid = $qa->get_database_id();
     $checksum = md5($qubaid . "_" . $this->student->secret . "_" . $questionid . "_" . $qaid . "_" . $slot);
     $flag = core_question_external::update_flag($qubaid, $questionid, $qaid, $slot, $checksum, true);
     $this->assertTrue($flag['status']);
     // Test invalid checksum.
     try {
         // Using random_string to force failing.
         $checksum = md5($qubaid . "_" . random_string(11) . "_" . $questionid . "_" . $qaid . "_" . $slot);
         core_question_external::update_flag($qubaid, $questionid, $qaid, $slot, $checksum, true);
         $this->fail('Exception expected due to invalid checksum.');
     } catch (moodle_exception $e) {
         $this->assertEquals('errorsavingflags', $e->errorcode);
     }
 }
Exemplo n.º 2
0
 protected function prepare_quiz_data()
 {
     $this->resetAfterTest(true);
     // Create a course
     $course = $this->getDataGenerator()->create_course();
     // Make a quiz.
     $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
     $quiz = $quizgenerator->create_instance(array('course' => $course->id, 'questionsperpage' => 0, 'grade' => 100.0, 'sumgrades' => 2));
     $cm = get_coursemodule_from_instance('quiz', $quiz->id, $course->id);
     // Create a couple of questions.
     $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $questiongenerator->create_question_category();
     $saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
     $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     // Add them to the quiz.
     quiz_add_quiz_question($saq->id, $quiz);
     quiz_add_quiz_question($numq->id, $quiz);
     // Make a user to do the quiz.
     $user1 = $this->getDataGenerator()->create_user();
     $this->setUser($user1);
     $quizobj = quiz::create($quiz->id, $user1->id);
     // Start the attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow);
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     return array($quizobj, $quba, $attempt);
 }
 public function definition()
 {
     $mform = $this->_form;
     $hiddenofvisible = array(question_display_options::HIDDEN => get_string('notshown', 'question'), question_display_options::VISIBLE => get_string('shown', 'question'));
     $mform->addElement('header', 'optionsheader', get_string('changeoptions', 'question'));
     $behaviours = question_engine::get_behaviour_options($this->_customdata['quba']->get_preferred_behaviour());
     $mform->addElement('select', 'behaviour', get_string('howquestionsbehave', 'question'), $behaviours);
     $mform->addHelpButton('behaviour', 'howquestionsbehave', 'question');
     $mform->addElement('text', 'maxmark', get_string('markedoutof', 'question'), array('size' => '5'));
     $mform->setType('maxmark', PARAM_NUMBER);
     if ($this->_customdata['maxvariant'] > 1) {
         $variants = range(1, $this->_customdata['maxvariant']);
         $mform->addElement('select', 'variant', get_string('questionvariant', 'question'), array_combine($variants, $variants));
     }
     $mform->setType('maxmark', PARAM_INT);
     $mform->addElement('select', 'correctness', get_string('whethercorrect', 'question'), $hiddenofvisible);
     $marksoptions = array(question_display_options::HIDDEN => get_string('notshown', 'question'), question_display_options::MAX_ONLY => get_string('showmaxmarkonly', 'question'), question_display_options::MARK_AND_MAX => get_string('showmarkandmax', 'question'));
     $mform->addElement('select', 'marks', get_string('marks', 'question'), $marksoptions);
     $mform->addElement('select', 'markdp', get_string('decimalplacesingrades', 'question'), question_engine::get_dp_options());
     $mform->addElement('select', 'feedback', get_string('specificfeedback', 'question'), $hiddenofvisible);
     $mform->addElement('select', 'generalfeedback', get_string('generalfeedback', 'question'), $hiddenofvisible);
     $mform->addElement('select', 'rightanswer', get_string('rightanswer', 'question'), $hiddenofvisible);
     $mform->addElement('select', 'history', get_string('responsehistory', 'question'), $hiddenofvisible);
     $mform->addElement('submit', 'submit', get_string('restartwiththeseoptions', 'question'), $hiddenofvisible);
 }
 /**
  * Given the quiz "How questions behave" setting, can the fault-tolerant mode work
  * with that behaviour?
  * @param string $behaviour the internal name (e.g. 'interactive') of an archetypal behaviour.
  * @return boolean whether fault-tolerant mode can be used.
  */
 public static function is_compatible_behaviour($behaviour)
 {
     $unusedoptions = question_engine::get_behaviour_unused_display_options($behaviour);
     // Sorry, double negative here. The heuristic is that:
     // The behaviour is compatible if we don't need to show specific feedback during the attempt.
     return in_array('specificfeedback', $unusedoptions);
 }
Exemplo n.º 5
0
/**
 * Manual graded question behaviour upgrade code.
 */
function xmldb_qbehaviour_manualgraded_upgrade($oldversion)
{
    global $CFG, $DB;
    $dbman = $DB->get_manager();
    // Moodle v2.4.0 release upgrade line
    // Put any upgrade step following this
    if ($oldversion < 2013050200) {
        // Hide the manualgraded behaviour from the list of behaviours that users
        // can select in the user-interface. If a user accidentally chooses manual
        // graded behaviour for a quiz, there is no way to get the questions automatically
        // graded after the student has answered them. If teachers really want to do
        // this they can ask their admin to enable it on the manage behaviours
        // screen in the UI.
        $disabledbehaviours = get_config('question', 'disabledbehaviours');
        if (!empty($disabledbehaviours)) {
            $disabledbehaviours = explode(',', $disabledbehaviours);
        } else {
            $disabledbehaviours = array();
        }
        if (array_search('manualgraded', $disabledbehaviours) === false) {
            $disabledbehaviours[] = 'manualgraded';
            set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
        }
        // Manual graded question behaviour savepoint reached.
        upgrade_plugin_savepoint(true, 2013050200, 'qbehaviour', 'manualgraded');
    }
    if ($oldversion < 2013050800) {
        // Also, fix any other admin settings that currently select manualgraded behaviour.
        // Work out a sensible default alternative to manualgraded.
        require_once $CFG->libdir . '/questionlib.php';
        $behaviours = question_engine::get_behaviour_options('');
        if (array_key_exists('deferredfeedback', $behaviours)) {
            $defaultbehaviour = 'deferredfeedback';
        } else {
            reset($behaviours);
            $defaultbehaviour = key($behaviours);
        }
        // Fix the question preview default.
        if (get_config('question_preview', 'behaviour') == 'manualgraded') {
            set_config('behaviour', $defaultbehaviour, 'question_preview');
        }
        // Fix the quiz settings default.
        if (get_config('quiz', 'preferredbehaviour') == 'manualgraded') {
            set_config('preferredbehaviour', $defaultbehaviour, 'quiz');
        }
        // Manual graded question behaviour savepoint reached.
        upgrade_plugin_savepoint(true, 2013050800, 'qbehaviour', 'manualgraded');
    }
    // Moodle v2.5.0 release upgrade line.
    // Put any upgrade step following this.
    // Moodle v2.6.0 release upgrade line.
    // Put any upgrade step following this.
    // Moodle v2.7.0 release upgrade line.
    // Put any upgrade step following this.
    // Moodle v2.8.0 release upgrade line.
    // Put any upgrade step following this.
    // Moodle v2.9.0 release upgrade line.
    // Put any upgrade step following this.
    return true;
}
Exemplo n.º 6
0
 /**
  * Constructor.
  * @param question_usage_by_activity $quba the question usage we will be picking variants for.
  * @param qubaid_condition $qubaids ids of the usages to consider when counting previous uses of each variant.
  */
 public function __construct(\question_usage_by_activity $quba, \qubaid_condition $qubaids)
 {
     $questionidtoseed = array();
     foreach ($quba->get_attempt_iterator() as $qa) {
         $question = $qa->get_question();
         if ($question->get_num_variants() > 1) {
             $questionidtoseed[$question->id] = $question->get_variants_selection_seed();
         }
     }
     if (empty($questionidtoseed)) {
         return;
     }
     $this->variantsusecounts = array_fill_keys($questionidtoseed, array());
     $variantsused = \question_engine::load_used_variants(array_keys($questionidtoseed), $qubaids);
     foreach ($variantsused as $questionid => $usagecounts) {
         $seed = $questionidtoseed[$questionid];
         foreach ($usagecounts as $variant => $count) {
             if (isset($this->variantsusecounts[$seed][$variant])) {
                 $this->variantsusecounts[$seed][$variant] += $count;
             } else {
                 $this->variantsusecounts[$seed][$variant] = $count;
             }
         }
     }
 }
 public function setUp()
 {
     $this->quba = question_engine::make_questions_usage_by_activity('unit_test', get_context_instance(CONTEXT_SYSTEM));
     $this->quba->set_preferred_behaviour('deferredfeedback');
     $slot = $this->quba->add_question(test_question_maker::make_a_description_question());
     $this->qas[$slot] = $this->quba->get_question_attempt($slot);
     $slot = $this->quba->add_question(test_question_maker::make_a_description_question());
     $this->qas[$slot] = $this->quba->get_question_attempt($slot);
     $this->iterator = $this->quba->get_attempt_iterator();
 }
 protected function setUp()
 {
     $this->quba = question_engine::make_questions_usage_by_activity('unit_test', context_system::instance());
     $this->quba->set_preferred_behaviour('deferredfeedback');
     $slot = $this->quba->add_question(test_question_maker::make_question('description'));
     $this->qas[$slot] = $this->quba->get_question_attempt($slot);
     $slot = $this->quba->add_question(test_question_maker::make_question('description'));
     $this->qas[$slot] = $this->quba->get_question_attempt($slot);
     $this->iterator = $this->quba->get_attempt_iterator();
 }
 /**
  * Test the various methods that load data for reporting.
  *
  * Since these methods need an expensive set-up, and then only do read-only
  * operations on the data, we use a single method to do the set-up, which
  * calls diffents methods to test each query.
  */
 public function test_reporting_queries()
 {
     // We create two usages, each with two questions, a short-answer marked
     // out of 5, and and essay marked out of 10.
     //
     // In the first usage, the student answers the short-answer
     // question correctly, and enters something in the essay.
     //
     // In the second useage, the student answers the short-answer question
     // wrongly, and leaves the essay blank.
     $this->resetAfterTest();
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category();
     $this->sa = $generator->create_question('shortanswer', null, array('category' => $cat->id));
     $this->essay = $generator->create_question('essay', null, array('category' => $cat->id));
     $this->usageids = array();
     // Create the first usage.
     $q = question_bank::load_question($this->sa->id);
     $this->start_attempt_at_question($q, 'interactive', 5);
     $this->allslots[] = $this->slot;
     $this->process_submission(array('answer' => 'cat'));
     $this->process_submission(array('answer' => 'frog', '-submit' => 1));
     $q = question_bank::load_question($this->essay->id);
     $this->start_attempt_at_question($q, 'interactive', 10);
     $this->allslots[] = $this->slot;
     $this->process_submission(array('answer' => '<p>The cat sat on the mat.</p>', 'answerformat' => FORMAT_HTML));
     $this->finish();
     $this->save_quba();
     $this->usageids[] = $this->quba->get_id();
     // Create the second usage.
     $this->quba = question_engine::make_questions_usage_by_activity('unit_test', context_system::instance());
     $q = question_bank::load_question($this->sa->id);
     $this->start_attempt_at_question($q, 'interactive', 5);
     $this->process_submission(array('answer' => 'fish'));
     $q = question_bank::load_question($this->essay->id);
     $this->start_attempt_at_question($q, 'interactive', 10);
     $this->finish();
     $this->save_quba();
     $this->usageids[] = $this->quba->get_id();
     // Set up some things the tests will need.
     $this->dm = new question_engine_data_mapper();
     $this->bothusages = new qubaid_list($this->usageids);
     // Now test the various queries.
     $this->dotest_load_questions_usages_latest_steps();
     $this->dotest_load_questions_usages_question_state_summary();
     $this->dotest_load_questions_usages_where_question_in_state();
     $this->dotest_load_average_marks();
     $this->dotest_sum_usage_marks_subquery();
     $this->dotest_question_attempt_latest_state_view();
 }
 public function test_sort_behaviours()
 {
     $in = array('b1' => 'Behave 1', 'b2' => 'Behave 2', 'b3' => 'Behave 3', 'b4' => 'Behave 4', 'b5' => 'Behave 5', 'b6' => 'Behave 6');
     $out = array('b1' => 'Behave 1', 'b2' => 'Behave 2', 'b3' => 'Behave 3', 'b4' => 'Behave 4', 'b5' => 'Behave 5', 'b6' => 'Behave 6');
     $this->assertIdentical($out, question_engine::sort_behaviours($in, '', '', ''));
     $this->assertIdentical($out, question_engine::sort_behaviours($in, '', 'b4', 'b4'));
     $out = array('b4' => 'Behave 4', 'b5' => 'Behave 5', 'b6' => 'Behave 6');
     $this->assertIdentical($out, question_engine::sort_behaviours($in, '', 'b1,b2,b3,b4', 'b4'));
     $out = array('b6' => 'Behave 6', 'b1' => 'Behave 1', 'b4' => 'Behave 4');
     $this->assertIdentical($out, question_engine::sort_behaviours($in, 'b6,b1,b4', 'b2,b3,b4,b5', 'b4'));
     $out = array('b6' => 'Behave 6', 'b5' => 'Behave 5', 'b4' => 'Behave 4');
     $this->assertIdentical($out, question_engine::sort_behaviours($in, 'b6,b5,b4', 'b1,b2,b3', 'b4'));
     $out = array('b6' => 'Behave 6', 'b5' => 'Behave 5', 'b4' => 'Behave 4');
     $this->assertIdentical($out, question_engine::sort_behaviours($in, 'b1,b6,b5', 'b1,b2,b3,b4', 'b4'));
     $out = array('b2' => 'Behave 2', 'b4' => 'Behave 4', 'b6' => 'Behave 6');
     $this->assertIdentical($out, question_engine::sort_behaviours($in, 'b2,b4,b6', 'b1,b3,b5', 'b2'));
     // Ignore unknown input in the order argument.
     $this->assertIdentical($in, question_engine::sort_behaviours($in, 'unknown', '', ''));
     // Ignore unknown input in the disabled argument.
     $this->assertIdentical($in, question_engine::sort_behaviours($in, '', 'unknown', ''));
 }
Exemplo n.º 11
0
    $archetypal[$behaviour] = question_engine::is_behaviour_archetypal($behaviour);
}
foreach ($counts as $behaviour => $count) {
    if (!array_key_exists($behaviour, $behaviours)) {
        $counts['missing'] += $count;
    }
}
$needed['missing'] = true;
// Work of the correct sort order.
$config = get_config('question');
$sortedbehaviours = array();
foreach ($behaviours as $behaviour => $notused) {
    $sortedbehaviours[$behaviour] = question_engine::get_behaviour_name($behaviour);
}
if (!empty($config->behavioursortorder)) {
    $sortedbehaviours = question_engine::sort_behaviours($sortedbehaviours, $config->behavioursortorder, '');
}
if (!empty($config->disabledbehaviours)) {
    $disabledbehaviours = explode(',', $config->disabledbehaviours);
} else {
    $disabledbehaviours = array();
}
// Process actions ============================================================
// Disable.
if (($disable = optional_param('disable', '', PARAM_PLUGIN)) && confirm_sesskey()) {
    if (!isset($behaviours[$disable])) {
        print_error('unknownbehaviour', 'question', $thispageurl, $disable);
    }
    if (array_search($disable, $disabledbehaviours) === false) {
        $disabledbehaviours[] = $disable;
        set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
Exemplo n.º 12
0
 protected function after_execute()
 {
     parent::after_execute();
     // Restore any files belonging to responses.
     foreach (question_engine::get_all_response_file_areas() as $filearea) {
         $this->add_related_files('question', $filearea, 'question_attempt_step');
     }
 }
Exemplo n.º 13
0
 /**
  * Search question behaviours for the specified string
  *
  * @param string $query The string to search for in question behaviours
  * @return array
  */
 public function search($query)
 {
     global $CFG;
     if ($result = parent::search($query)) {
         return $result;
     }
     $found = false;
     $textlib = textlib_get_instance();
     require_once $CFG->dirroot . '/question/engine/lib.php';
     foreach (get_plugin_list('qbehaviour') as $behaviour => $notused) {
         if (strpos($textlib->strtolower(question_engine::get_behaviour_name($behaviour)), $query) !== false) {
             $found = true;
             break;
         }
     }
     if ($found) {
         $result = new stdClass();
         $result->page = $this;
         $result->settings = array();
         return array($this->name => $result);
     } else {
         return array();
     }
 }
Exemplo n.º 14
0
 /**
  * Attach to $element (usually attempts) the needed backup structures
  * for question_usages and all the associated data.
  */
 protected function add_question_usages($element, $usageidname)
 {
     global $CFG;
     require_once $CFG->dirroot . '/question/engine/lib.php';
     // Check $element is one nested_backup_element
     if (!$element instanceof backup_nested_element) {
         throw new backup_step_exception('question_states_bad_parent_element', $element);
     }
     if (!$element->get_final_element($usageidname)) {
         throw new backup_step_exception('question_states_bad_question_attempt_element', $usageidname);
     }
     $quba = new backup_nested_element('question_usage', array('id'), array('component', 'preferredbehaviour'));
     $qas = new backup_nested_element('question_attempts');
     $qa = new backup_nested_element('question_attempt', array('id'), array('slot', 'behaviour', 'questionid', 'maxmark', 'minfraction', 'flagged', 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified'));
     $steps = new backup_nested_element('steps');
     $step = new backup_nested_element('step', array('id'), array('sequencenumber', 'state', 'fraction', 'timecreated', 'userid'));
     $response = new backup_nested_element('response');
     $variable = new backup_nested_element('variable', null, array('name', 'value'));
     // Build the tree
     $element->add_child($quba);
     $quba->add_child($qas);
     $qas->add_child($qa);
     $qa->add_child($steps);
     $steps->add_child($step);
     $step->add_child($response);
     $response->add_child($variable);
     // Set the sources
     $quba->set_source_table('question_usages', array('id' => '../' . $usageidname));
     $qa->set_source_sql('
             SELECT *
             FROM {question_attempts}
             WHERE questionusageid = :questionusageid
             ORDER BY slot', array('questionusageid' => backup::VAR_PARENTID));
     $step->set_source_sql('
             SELECT *
             FROM {question_attempt_steps}
             WHERE questionattemptid = :questionattemptid
             ORDER BY sequencenumber', array('questionattemptid' => backup::VAR_PARENTID));
     $variable->set_source_table('question_attempt_step_data', array('attemptstepid' => backup::VAR_PARENTID));
     // Annotate ids
     $qa->annotate_ids('question', 'questionid');
     $step->annotate_ids('user', 'userid');
     // Annotate files
     $fileareas = question_engine::get_all_response_file_areas();
     foreach ($fileareas as $filearea) {
         $step->annotate_files('question', $filearea, 'id');
     }
 }
Exemplo n.º 15
0
    public function test_access_out_of_sequence_throws_exception() {
        // Start a deferred feedback attempt with CBM and add the question to it.
        $tf = test_question_maker::make_question('truefalse', 'true');
        $quba = question_engine::make_questions_usage_by_activity('unit_test',
                context_system::instance());
        $quba->set_preferred_behaviour('deferredcbm');
        $slot = $quba->add_question($tf);
        $quba->start_all_questions();

        // Prepare data to be submitted
        $prefix = $quba->get_field_prefix($slot);
        $answername = $prefix . 'answer';
        $certaintyname = $prefix . '-certainty';
        $postdata = array(
            $answername => 1,
            $certaintyname => 3,
            $prefix . ':sequencecheck' => 1,
            'irrelevant' => 'should be ignored',
        );

        // Exercise SUT - no exception yet.
        $quba->process_all_actions($slot, $postdata);

        $postdata = array(
            $answername => 1,
            $certaintyname => 3,
            $prefix . ':sequencecheck' => 3,
            'irrelevant' => 'should be ignored',
        );

        // Exercise SUT - now it should fail.
        $this->setExpectedException('question_out_of_sequence_exception');
        $quba->process_all_actions($slot, $postdata);
    }
Exemplo n.º 16
0
 /**
  * Change the max mark for a slot.
  *
  * Saves changes to the question grades in the quiz_slots table and any
  * corresponding question_attempts.
  * It does not update 'sumgrades' in the quiz table.
  *
  * @param \stdClass $slot row from the quiz_slots table.
  * @param float $maxmark the new maxmark.
  * @return bool true if the new grade is different from the old one.
  */
 public function update_slot_maxmark($slot, $maxmark)
 {
     global $DB;
     if (abs($maxmark - $slot->maxmark) < 1.0E-7) {
         // Grade has not changed. Nothing to do.
         return false;
     }
     $trans = $DB->start_delegated_transaction();
     $slot->maxmark = $maxmark;
     $DB->update_record('quiz_slots', $slot);
     \question_engine::set_max_mark_in_attempts(new \qubaids_for_quiz($slot->quizid), $slot->slot, $maxmark);
     $trans->allow_commit();
     return true;
 }
Exemplo n.º 17
0
        $oldnumberstonew[$oldslot] = $newslot;
    }
    // Update attempt layout.
    $newlayout = array();
    foreach (explode(',', $lastattempt->layout) as $oldslot) {
        if ($oldslot != 0) {
            $newlayout[] = $oldnumberstonew[$oldslot];
        } else {
            $newlayout[] = 0;
        }
    }
    $attempt->layout = implode(',', $newlayout);
}
// Save the attempt in the database.
$transaction = $DB->start_delegated_transaction();
question_engine::save_questions_usage_by_activity($quba);
$attempt->uniqueid = $quba->get_id();
$attempt->id = $DB->insert_record('quiz_attempts', $attempt);
// Log the new attempt.
if ($attempt->preview) {
    add_to_log($course->id, 'quiz', 'preview', 'view.php?id=' . $quizobj->get_cmid(), $quizobj->get_quizid(), $quizobj->get_cmid());
} else {
    add_to_log($course->id, 'quiz', 'attempt', 'review.php?attempt=' . $attempt->id, $quizobj->get_quizid(), $quizobj->get_cmid());
}
// Trigger event.
$eventdata = new stdClass();
$eventdata->component = 'mod_quiz';
$eventdata->attemptid = $attempt->id;
$eventdata->timestart = $attempt->timestart;
$eventdata->timestamp = $attempt->timestart;
$eventdata->userid = $attempt->userid;
Exemplo n.º 18
0
 public function test_load_used_variants()
 {
     $this->resetAfterTest();
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category();
     $questiondata1 = $generator->create_question('shortanswer', null, array('category' => $cat->id));
     $questiondata2 = $generator->create_question('shortanswer', null, array('category' => $cat->id));
     $questiondata3 = $generator->create_question('shortanswer', null, array('category' => $cat->id));
     $quba = question_engine::make_questions_usage_by_activity('test', context_system::instance());
     $quba->set_preferred_behaviour('deferredfeedback');
     $question1 = question_bank::load_question($questiondata1->id);
     $question3 = question_bank::load_question($questiondata3->id);
     $quba->add_question($question1);
     $quba->add_question($question1);
     $quba->add_question($question3);
     $quba->start_all_questions();
     question_engine::save_questions_usage_by_activity($quba);
     $this->assertEquals(array($questiondata1->id => array(1 => 2), $questiondata2->id => array(), $questiondata3->id => array(1 => 1)), question_engine::load_used_variants(array($questiondata1->id, $questiondata2->id, $questiondata3->id), new qubaid_list(array($quba->get_id()))));
 }
Exemplo n.º 19
0
 public function process_finish($timestamp, $processsubmitted)
 {
     global $DB;
     $transaction = $DB->start_delegated_transaction();
     if ($processsubmitted) {
         $this->quba->process_all_actions($timestamp);
     }
     $this->quba->finish_all_questions($timestamp);
     question_engine::save_questions_usage_by_activity($this->quba);
     $this->attempt->timemodified = $timestamp;
     $this->attempt->timefinish = $timestamp;
     $this->attempt->sumgrades = $this->quba->get_total_mark();
     $this->attempt->state = self::FINISHED;
     $this->attempt->timecheckstate = null;
     $DB->update_record('quiz_attempts', $this->attempt);
     if (!$this->is_preview()) {
         quiz_save_best_grade($this->get_quiz(), $this->attempt->userid);
         // Trigger event.
         $this->fire_state_transition_event('\\mod_quiz\\event\\attempt_submitted', $timestamp);
         // Tell any access rules that care that the attempt is over.
         $this->get_access_manager($timestamp)->current_attempt_finished();
     }
     $transaction->allow_commit();
 }
Exemplo n.º 20
0
 /**
  * (non-PHPdoc)
  *
  * @see offlinequiz_default_report::display()
  */
 public function display($offlinequiz, $cm, $course)
 {
     global $CFG, $OUTPUT, $SESSION, $DB;
     // Define some strings.
     $strtimeformat = get_string('strftimedatetime');
     $letterstr = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ';
     offlinequiz_load_useridentification();
     $offlinequizconfig = get_config('offlinequiz');
     // Deal with actions.
     $action = optional_param('action', '', PARAM_ACTION);
     // Only print headers if not asked to download data or delete data.
     if (!($download = optional_param('download', null, PARAM_TEXT)) && !$action == 'delete') {
         $this->print_header_and_tabs($cm, $course, $offlinequiz, 'overview');
         echo $OUTPUT->box_start('linkbox');
         echo $OUTPUT->heading(format_string($offlinequiz->name));
         echo $OUTPUT->heading(get_string('results', 'offlinequiz'));
         require_once $CFG->libdir . '/grouplib.php';
         echo groups_print_activity_menu($cm, $CFG->wwwroot . '/mod/offlinequiz/report.php?id=' . $cm->id . '&mode=overview', true);
         echo $OUTPUT->box_end();
         echo '<br/>';
     }
     $context = context_module::instance($cm->id);
     $systemcontext = context_system::instance();
     // Set table options.
     $noresults = optional_param('noresults', 0, PARAM_INT);
     $pagesize = optional_param('pagesize', 10, PARAM_INT);
     $groupid = optional_param('group', 0, PARAM_INT);
     if ($pagesize < 1) {
         $pagesize = 10;
     }
     $answerletters = 'abcdefghijklmnopqrstuvwxyz';
     if ($action == 'delete' && confirm_sesskey()) {
         $selectedresultids = array();
         $params = (array) data_submitted();
         foreach ($params as $key => $value) {
             if (preg_match('!^s([0-9]+)$!', $key, $matches)) {
                 $selectedresultids[] = $matches[1];
             }
         }
         if ($selectedresultids) {
             foreach ($selectedresultids as $resultid) {
                 if ($resultid && ($todelete = $DB->get_record('offlinequiz_results', array('id' => $resultid)))) {
                     offlinequiz_delete_result($resultid, $context);
                     // Log this event.
                     $params = array('objectid' => $resultid, 'relateduserid' => $todelete->userid, 'context' => context_module::instance($cm->id), 'other' => array('mode' => 'overview'));
                     $event = \mod_offlinequiz\event\attempt_deleted::create($params);
                     $event->trigger();
                     // Change the status of all related pages with error 'resultexists' to 'suspended'.
                     $user = $DB->get_record('user', array('id' => $todelete->userid));
                     $group = $DB->get_record('offlinequiz_groups', array('id' => $todelete->offlinegroupid));
                     $sql = "SELECT id\n                                  FROM {offlinequiz_scanned_pages}\n                                 WHERE offlinequizid = :offlinequizid\n                                   AND userkey = :userkey\n                                   AND groupnumber = :groupnumber\n                                   AND status = 'error'\n                                   AND (error = 'resultexists' OR error = 'differentresultexists')";
                     $params = array('offlinequizid' => $offlinequiz->id, 'userkey' => $user->{$offlinequizconfig->ID_field}, 'groupnumber' => $group->number);
                     $otherpages = $DB->get_records_sql($sql, $params);
                     foreach ($otherpages as $page) {
                         $DB->set_field('offlinequiz_scanned_pages', 'status', 'suspended', array('id' => $page->id));
                         $DB->set_field('offlinequiz_scanned_pages', 'error', '', array('id' => $page->id));
                     }
                 }
             }
             offlinequiz_grade_item_update($offlinequiz, 'reset');
             offlinequiz_update_grades($offlinequiz);
             redirect(new moodle_url('/mod/offlinequiz/report.php', array('mode' => 'overview', 'id' => $cm->id, 'noresults' => $noresults, 'pagesize' => $pagesize)));
         }
     }
     // Now check if asked download of data.
     if ($download) {
         $filename = clean_filename("{$course->shortname} " . format_string($offlinequiz->name, true));
         $sort = '';
     }
     // Fetch the group data.
     $groups = $DB->get_records('offlinequiz_groups', array('offlinequizid' => $offlinequiz->id), 'number', '*', 0, $offlinequiz->numgroups);
     // Define table columns.
     $tablecolumns = array('checkbox', 'picture', 'fullname', $offlinequizconfig->ID_field, 'timestart', 'offlinegroupid', 'sumgrades');
     $tableheaders = array('<input type="checkbox" name="toggle" onClick="if (this.checked) {select_all_in(\'DIV\',null,\'tablecontainer\');}
             else {deselect_all_in(\'DIV\',null,\'tablecontainer\');}"/>', '', get_string('fullname'), get_string($offlinequizconfig->ID_field), get_string('importedon', 'offlinequiz'), get_string('group'), get_string('grade', 'offlinequiz'));
     $checked = array();
     // Get participants list.
     $withparticipants = false;
     if ($lists = $DB->get_records('offlinequiz_p_lists', array('offlinequizid' => $offlinequiz->id))) {
         $withparticipants = true;
         $tablecolumns[] = 'checked';
         $tableheaders[] = get_string('present', 'offlinequiz');
         foreach ($lists as $list) {
             $participants = $DB->get_records('offlinequiz_participants', array('listid' => $list->id));
             foreach ($participants as $participant) {
                 $checked[$participant->userid] = $participant->checked;
             }
         }
     }
     if (!$download) {
         // Set up the table.
         $params = array('offlinequiz' => $offlinequiz, 'noresults' => $noresults, 'pagesize' => $pagesize);
         $table = new offlinequiz_results_table('mod-offlinequiz-report-overview-report', $params);
         $table->define_columns($tablecolumns);
         $table->define_headers($tableheaders);
         $table->define_baseurl($CFG->wwwroot . '/mod/offlinequiz/report.php?mode=overview&amp;id=' . $cm->id . '&amp;noresults=' . $noresults . '&amp;pagesize=' . $pagesize);
         $table->sortable(true);
         $table->no_sorting('checkbox');
         if ($withparticipants) {
             $table->no_sorting('checked');
         }
         $table->column_suppress('picture');
         $table->column_suppress('fullname');
         $table->column_class('picture', 'picture');
         $table->column_class($offlinequizconfig->ID_field, 'userkey');
         $table->column_class('timestart', 'timestart');
         $table->column_class('offlinegroupid', 'offlinegroupid');
         $table->column_class('sumgrades', 'sumgrades');
         $table->set_attribute('cellpadding', '2');
         $table->set_attribute('id', 'attempts');
         $table->set_attribute('class', 'generaltable generalbox');
         // Start working -- this is necessary as soon as the niceties are over.
         $table->setup();
     } else {
         if ($download == 'ODS') {
             require_once "{$CFG->libdir}/odslib.class.php";
             $filename .= ".ods";
             // Creating a workbook.
             $workbook = new MoodleODSWorkbook("-");
             // Sending HTTP headers.
             $workbook->send($filename);
             // Creating the first worksheet.
             $sheettitle = get_string('reportoverview', 'offlinequiz');
             $myxls = $workbook->add_worksheet($sheettitle);
             // Format types.
             $format = $workbook->add_format();
             $format->set_bold(0);
             $formatbc = $workbook->add_format();
             $formatbc->set_bold(1);
             $formatbc->set_align('center');
             $formatb = $workbook->add_format();
             $formatb->set_bold(1);
             $formaty = $workbook->add_format();
             $formaty->set_bg_color('yellow');
             $formatc = $workbook->add_format();
             $formatc->set_align('center');
             $formatr = $workbook->add_format();
             $formatr->set_bold(1);
             $formatr->set_color('red');
             $formatr->set_align('center');
             $formatg = $workbook->add_format();
             $formatg->set_bold(1);
             $formatg->set_color('green');
             $formatg->set_align('center');
             // Here starts workshhet headers.
             $headers = array(get_string($offlinequizconfig->ID_field), get_string('firstname'), get_string('lastname'), get_string('importedon', 'offlinequiz'), get_string('group'), get_string('grade', 'offlinequiz'));
             if (!empty($withparticipants)) {
                 $headers[] = get_string('present', 'offlinequiz');
             }
             $colnum = 0;
             foreach ($headers as $item) {
                 $myxls->write(0, $colnum, $item, $formatbc);
                 $colnum++;
             }
             $rownum = 1;
         } else {
             if ($download == 'Excel') {
                 require_once "{$CFG->libdir}/excellib.class.php";
                 $filename .= ".xls";
                 // Creating a workbook.
                 $workbook = new MoodleExcelWorkbook("-");
                 // Sending HTTP headers.
                 $workbook->send($filename);
                 // Creating the first worksheet.
                 $sheettitle = get_string('results', 'offlinequiz');
                 $myxls = $workbook->add_worksheet($sheettitle);
                 // Format types.
                 $format = $workbook->add_format();
                 $format->set_bold(0);
                 $formatbc = $workbook->add_format();
                 $formatbc->set_bold(1);
                 $formatbc->set_align('center');
                 $formatb = $workbook->add_format();
                 $formatb->set_bold(1);
                 $formaty = $workbook->add_format();
                 $formaty->set_bg_color('yellow');
                 $formatc = $workbook->add_format();
                 $formatc->set_align('center');
                 $formatr = $workbook->add_format();
                 $formatr->set_bold(1);
                 $formatr->set_color('red');
                 $formatr->set_align('center');
                 $formatg = $workbook->add_format();
                 $formatg->set_bold(1);
                 $formatg->set_color('green');
                 $formatg->set_align('center');
                 // Here starts worksheet headers.
                 $headers = array(get_string($offlinequizconfig->ID_field), get_string('firstname'), get_string('lastname'), get_string('importedon', 'offlinequiz'), get_string('group'), get_string('grade', 'offlinequiz'));
                 if (!empty($withparticipants)) {
                     $headers[] = get_string('present', 'offlinequiz');
                 }
                 $colnum = 0;
                 foreach ($headers as $item) {
                     $myxls->write(0, $colnum, $item, $formatbc);
                     $colnum++;
                 }
                 $rownum = 1;
             } else {
                 if ($download == 'CSV') {
                     $filename .= ".csv";
                     header("Content-Encoding: UTF-8");
                     header("Content-Type: text/csv; charset=utf-8");
                     header("Content-Disposition: attachment; filename=\"{$filename}\"");
                     header("Expires: 0");
                     header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
                     header("Pragma: public");
                     echo "";
                     // UTF-8 BOM.
                     $headers = get_string($offlinequizconfig->ID_field) . ", " . get_string('fullname') . ", " . get_string('importedon', 'offlinequiz') . ", " . get_string('group') . ", " . get_string('grade', 'offlinequiz');
                     if (!empty($withparticipants)) {
                         $headers .= ", " . get_string('present', 'offlinequiz');
                     }
                     echo $headers . " \n";
                 } else {
                     if ($download == 'CSVplus1' || $download == 'CSVpluspoints') {
                         $filename .= ".csv";
                         header("Content-Encoding: UTF-8");
                         header("Content-Type: text/csv; charset=utf-8");
                         header("Content-Disposition: attachment; filename=\"{$filename}\"");
                         header("Expires: 0");
                         header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
                         header("Pragma: public");
                         echo "";
                         // UTF-8 BOM.
                         // Print the table headers.
                         echo get_string('firstname') . ',' . get_string('lastname') . ',' . get_string($offlinequizconfig->ID_field) . ',' . get_string('group');
                         $maxquestions = offlinequiz_get_maxquestions($offlinequiz, $groups);
                         for ($i = 0; $i < $maxquestions; $i++) {
                             echo ', ' . get_string('question') . ' ' . ($i + 1);
                         }
                         echo "\n";
                         // Print the correct answer bit-strings.
                         foreach ($groups as $group) {
                             if ($group->templateusageid) {
                                 $quba = question_engine::load_questions_usage_by_activity($group->templateusageid);
                                 $slots = $quba->get_slots();
                                 echo ', ,' . get_string('correct', 'offlinequiz');
                                 echo ',' . $group->number;
                                 foreach ($slots as $slot) {
                                     $slotquestion = $quba->get_question($slot);
                                     $qtype = $slotquestion->get_type_name();
                                     if ($qtype == 'multichoice' || $qtype == 'multichoiceset') {
                                         $attempt = $quba->get_question_attempt($slot);
                                         $order = $slotquestion->get_order($attempt);
                                         // Order of the answers.
                                         $tempstr = ",";
                                         $letters = array();
                                         $counter = 0;
                                         foreach ($order as $key => $answerid) {
                                             $fraction = $DB->get_field('question_answers', 'fraction', array('id' => $answerid));
                                             if ($fraction > 0) {
                                                 $letters[] = $answerletters[$counter];
                                             }
                                             $counter++;
                                         }
                                         if (empty($letters)) {
                                             $tempstr .= '99';
                                         } else {
                                             $tempstr .= implode('/', $letters);
                                         }
                                         echo $tempstr;
                                     }
                                 }
                                 echo "\n";
                             }
                         }
                     }
                 }
             }
         }
     }
     $coursecontext = context_course::instance($course->id);
     $contextids = $coursecontext->get_parent_context_ids(true);
     // Construct the SQL
     // First get roleids for students from leagcy.
     if (!($roles = get_roles_with_capability('mod/offlinequiz:attempt', CAP_ALLOW, $systemcontext))) {
         error("No roles with capability 'moodle/offlinequiz:attempt' defined in system context");
     }
     $roleids = array();
     foreach ($roles as $role) {
         $roleids[] = $role->id;
     }
     $rolelist = implode(',', $roleids);
     $select = "SELECT " . $DB->sql_concat('u.id', "'#'", "COALESCE(qa.usageid, 0)") . " AS uniqueid,\n        qa.id AS resultid, u.id, qa.usageid, qa.offlinegroupid, qa.status,\n        u.id AS userid, u.firstname, u.lastname,\n        u.alternatename, u.middlename, u.firstnamephonetic, u.lastnamephonetic,\n        u.picture, u." . $offlinequizconfig->ID_field . ",\n        qa.sumgrades, qa.timefinish, qa.timestart, qa.timefinish - qa.timestart AS duration ";
     $result = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'ctx');
     list($contexttest, $cparams) = $result;
     list($roletest, $rparams) = $DB->get_in_or_equal($roleids, SQL_PARAMS_NAMED, 'role');
     $from = "FROM {user} u\n                  JOIN {role_assignments} ra ON ra.userid = u.id\n             LEFT JOIN {offlinequiz_results} qa ON u.id = qa.userid AND qa.offlinequizid = :offlinequizid\n             ";
     $where = " WHERE ra.contextid {$contexttest} AND ra.roleid {$roletest} ";
     $params = array('offlinequizid' => $offlinequiz->id);
     $params = array_merge($params, $cparams, $rparams);
     if ($groupid) {
         $from .= " JOIN {groups_members} gm ON gm.userid = u.id ";
         $where .= " AND gm.groupid = :groupid ";
         $params['groupid'] = $groupid;
     }
     if (empty($noresults)) {
         $where = $where . " AND qa.userid IS NOT NULL\n                                AND qa.status = 'complete'";
         // Show ONLY students with results.
     } else {
         if ($noresults == 1) {
             // The value noresults = 1 means only no results, so make the left join ask for only records
             // where the right is null (no results).
             $where .= ' AND qa.userid IS NULL';
             // Show ONLY students without results.
         } else {
             if ($noresults == 3) {
                 // We want all results, also the partial ones.
                 $from = "FROM {user} u\n                      JOIN {offlinequiz_results} qa ON u.id = qa.userid ";
                 $where = " WHERE qa.offlinequizid = :offlinequizid";
             }
         }
     }
     // The value noresults = 2 means we want all students, with or without results.
     $countsql = 'SELECT COUNT(DISTINCT(u.id)) ' . $from . $where;
     if (!$download) {
         // Count the records NOW, before funky question grade sorting messes up $from.
         $totalinitials = $DB->count_records_sql($countsql, $params);
         // Add extra limits due to initials bar.
         list($ttest, $tparams) = $table->get_sql_where();
         if (!empty($ttest)) {
             $where .= ' AND ' . $ttest;
             $countsql .= ' AND ' . $ttest;
             $params = array_merge($params, $tparams);
         }
         $total = $DB->count_records_sql($countsql, $params);
         // Add extra limits due to sorting by question grade.
         $sort = $table->get_sql_sort();
         // Fix some wired sorting.
         if (empty($sort)) {
             $sort = ' ORDER BY u.lastname';
         } else {
             $sort = ' ORDER BY ' . $sort;
         }
         $table->pagesize($pagesize, $total);
     }
     // Fetch the results.
     if (!$download) {
         $results = $DB->get_records_sql($select . $from . $where . $sort, $params, $table->get_page_start(), $table->get_page_size());
     } else {
         $results = $DB->get_records_sql($select . $from . $where . $sort, $params);
     }
     // Build table rows.
     if (!$download) {
         $table->initialbars(true);
     }
     if (!empty($results) || !empty($noresults)) {
         foreach ($results as $result) {
             $user = $DB->get_record('user', array('id' => $result->userid));
             $picture = $OUTPUT->user_picture($user, array('courseid' => $course->id));
             if (!empty($result->resultid)) {
                 $checkbox = '<input type="checkbox" name="s' . $result->resultid . '" value="' . $result->resultid . '" />';
             } else {
                 $checkbox = '';
             }
             if (!empty($result) && (empty($result->resultid) || $result->timefinish == 0)) {
                 $resultdate = '-';
             } else {
                 $resultdate = userdate($result->timefinish, $strtimeformat);
             }
             if (!empty($result) && $result->offlinegroupid) {
                 $groupletter = $letterstr[$groups[$result->offlinegroupid]->number];
             } else {
                 $groupletter = '-';
             }
             $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $result->userid . '&amp;course=' . $course->id . '">' . fullname($result) . '</a>';
             if (!$download) {
                 $row = array($checkbox, $picture, $userlink, $result->{$offlinequizconfig->ID_field}, $resultdate, $groupletter);
             } else {
                 $row = array($result->{$offlinequizconfig->ID_field}, $result->firstname, $result->lastname, $resultdate, $groupletter);
             }
             if (!empty($result) && $result->offlinegroupid) {
                 $outputgrade = format_float($result->sumgrades / $groups[$result->offlinegroupid]->sumgrades * $offlinequiz->grade, $offlinequiz->decimalpoints);
             } else {
                 $outputgrade = '-';
             }
             if (!$download) {
                 if ($result->status == 'partial') {
                     $row[] = get_string('partial', 'offlinequiz');
                 } else {
                     if ($result->sumgrades === null) {
                         $row[] = '-';
                     } else {
                         $row[] = '<a href="review.php?q=' . $offlinequiz->id . '&amp;resultid=' . $result->resultid . '">' . $outputgrade . '</a>';
                     }
                 }
                 if ($withparticipants) {
                     $row[] = !empty($checked[$result->userid]) ? "<img src=\"{$CFG->wwwroot}/mod/offlinequiz/pix/tick.gif\" alt=\"" . get_string('ischecked', 'offlinequiz') . "\">" : "<img src=\"{$CFG->wwwroot}/mod/offlinequiz/pix/cross.gif\" alt=\"" . get_string('isnotchecked', 'offlinequiz') . "\">";
                 }
             } else {
                 if ($download != 'CSVplus1' || $download == 'CSVpluspoints') {
                     $row[] = $result->sumgrades === null ? '-' : $outputgrade;
                     if ($withparticipants) {
                         if (array_key_exists($result->userid, $checked)) {
                             $row[] = $checked[$result->userid] ? get_string('ok') : '-';
                         } else {
                             $row[] = '-';
                         }
                     }
                 }
             }
             if (!$download) {
                 $table->add_data($row);
             } else {
                 if ($download == 'Excel' or $download == 'ODS') {
                     $colnum = 0;
                     foreach ($row as $item) {
                         $myxls->write($rownum, $colnum, $item, $format);
                         $colnum++;
                     }
                     $rownum++;
                 } else {
                     if ($download == 'CSV') {
                         $text = implode(',', $row);
                         echo $text . "\n";
                     } else {
                         if ($download == 'CSVplus1' || $download == 'CSVpluspoints') {
                             $text = $row[1] . ',' . $row[2] . ',' . $row[0] . ',' . $groups[$result->offlinegroupid]->number;
                             if ($pages = $DB->get_records('offlinequiz_scanned_pages', array('resultid' => $result->resultid), 'pagenumber ASC')) {
                                 foreach ($pages as $page) {
                                     if ($page->status == 'ok' || $page->status == 'submitted') {
                                         $choices = $DB->get_records('offlinequiz_choices', array('scannedpageid' => $page->id), 'slotnumber, choicenumber');
                                         $counter = 0;
                                         $oldslot = -1;
                                         $letters = array();
                                         foreach ($choices as $choice) {
                                             if ($oldslot == -1) {
                                                 $oldslot = $choice->slotnumber;
                                             } else {
                                                 if ($oldslot != $choice->slotnumber) {
                                                     if (empty($letters)) {
                                                         $text .= ',99';
                                                     } else {
                                                         $text .= ',' . implode('/', $letters);
                                                     }
                                                     $counter = 0;
                                                     $oldslot = $choice->slotnumber;
                                                     $letters = array();
                                                 }
                                             }
                                             if ($choice->value == 1) {
                                                 $letters[] = $answerletters[$counter];
                                             }
                                             $counter++;
                                         }
                                         if (empty($letters)) {
                                             $text .= ',99';
                                         } else {
                                             $text .= ',' . implode('/', $letters);
                                         }
                                     }
                                 }
                             }
                             echo $text . "\n";
                             if ($download == 'CSVpluspoints') {
                                 $text = $row[1] . ',' . $row[2] . ',' . $row[0] . ',' . $groups[$result->offlinegroupid]->number;
                                 $quba = question_engine::load_questions_usage_by_activity($result->usageid);
                                 $slots = $quba->get_slots();
                                 foreach ($slots as $slot) {
                                     $slotquestion = $quba->get_question($slot);
                                     $attempt = $quba->get_question_attempt($slot);
                                     $text .= ',' . format_float($attempt->get_mark(), $offlinequiz->decimalpoints, false);
                                 }
                                 echo $text . "\n";
                             }
                         }
                     }
                 }
             }
         }
         // End foreach ($results...
     } else {
         if (!$download) {
             $table->print_initials_bar();
         }
     }
     if (!$download) {
         // Print table.
         $table->finish_html();
         if (!empty($results)) {
             echo '<form id="downloadoptions" action="report.php" method="get">';
             echo ' <input type="hidden" name="id" value="' . $cm->id . '" />';
             echo ' <input type="hidden" name="q" value="' . $offlinequiz->id . '" />';
             echo ' <input type="hidden" name="mode" value="overview" />';
             echo ' <input type="hidden" name="noheader" value="yes" />';
             echo ' <table class="boxaligncenter"><tr><td>';
             $options = array('Excel' => get_string('excelformat', 'offlinequiz'), 'ODS' => get_string('odsformat', 'offlinequiz'), 'CSV' => get_string('csvformat', 'offlinequiz'), 'CSVplus1' => get_string('csvplus1format', 'offlinequiz'), 'CSVpluspoints' => get_string('csvpluspointsformat', 'offlinequiz'));
             print_string('downloadresultsas', 'offlinequiz');
             echo "</td><td>";
             echo html_writer::select($options, 'download', '', false);
             echo ' <input type="submit" value="' . get_string('download') . '" />';
             echo ' <script type="text/javascript">' . "\n<!--\n" . 'document.getElementById("noscriptmenuaction").style.display = "none";' . "\n-->\n" . '</script>';
             echo " </td>\n";
             echo "<td>";
             echo "</td>\n";
             echo '</tr></table></form>';
         }
     } else {
         if ($download == 'Excel' || $download == 'ODS') {
             $workbook->close();
             exit;
         } else {
             if ($download == 'CSV' || $download == 'CSVplus1' || $download == 'CSVpluspoints') {
                 exit;
             }
         }
     }
     // Print display options.
     echo '<div class="controls">';
     echo '<form id="options" action="report.php" method="get">';
     echo '<div class=centerbox>';
     echo '<p>' . get_string('displayoptions', 'offlinequiz') . ': </p>';
     echo '<input type="hidden" name="id" value="' . $cm->id . '" />';
     echo '<input type="hidden" name="q" value="' . $offlinequiz->id . '" />';
     echo '<input type="hidden" name="mode" value="overview" />';
     echo '<input type="hidden" name="detailedmarks" value="0" />';
     echo '<table id="overview-options" class="boxaligncenter">';
     echo '<tr align="left">';
     echo '<td><label for="pagesize">' . get_string('pagesizeparts', 'offlinequiz') . '</label></td>';
     echo '<td><input type="text" id="pagesize" name="pagesize" size="3" value="' . $pagesize . '" /></td>';
     echo '</tr>';
     echo '<tr align="left">';
     echo '<td colspan="2">';
     $options = array();
     $options[] = get_string('attemptsonly', 'offlinequiz');
     $options[] = get_string('noattemptsonly', 'offlinequiz');
     $options[] = get_string('allstudents', 'offlinequiz');
     $options[] = get_string('allresults', 'offlinequiz');
     echo html_writer::select($options, 'noresults', $noresults, '');
     echo '</td></tr>';
     echo '<tr><td colspan="2" align="center">';
     echo '<input type="submit" value="' . get_string('go') . '" />';
     echo '</td></tr></table>';
     echo '</div>';
     echo '</form>';
     echo '</div>';
     echo "\n";
     return true;
 }
Exemplo n.º 21
0
 /**
  * Test get_attempt_access_information
  */
 public function test_get_attempt_access_information()
 {
     global $DB;
     // Create a new quiz with attempts.
     $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
     $data = array('course' => $this->course->id, 'sumgrades' => 2);
     $quiz = $quizgenerator->create_instance($data);
     // Create some questions.
     $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $questiongenerator->create_question_category();
     $question = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     $question = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     // Add new question types in the category (for the random one).
     $question = $questiongenerator->create_question('truefalse', null, array('category' => $cat->id));
     $question = $questiongenerator->create_question('essay', null, array('category' => $cat->id));
     $question = $questiongenerator->create_question('random', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     $quizobj = quiz::create($quiz->id, $this->student->id);
     // Set grade to pass.
     $item = grade_item::fetch(array('courseid' => $this->course->id, 'itemtype' => 'mod', 'itemmodule' => 'quiz', 'iteminstance' => $quiz->id, 'outcomeid' => null));
     $item->gradepass = 80;
     $item->update();
     $this->setUser($this->student);
     // Default restrictions (none).
     $result = mod_quiz_external::get_attempt_access_information($quiz->id);
     $result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_access_information_returns(), $result);
     $expected = array('isfinished' => false, 'preventnewattemptreasons' => [], 'warnings' => []);
     $this->assertEquals($expected, $result);
     // Limited attempts.
     $quiz->attempts = 1;
     $DB->update_record('quiz', $quiz);
     // Now, do one attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $this->student->id);
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     // Process some responses from the student.
     $attemptobj = quiz_attempt::create($attempt->id);
     $tosubmit = array(1 => array('answer' => '3.14'));
     $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
     // Finish the attempt.
     $attemptobj = quiz_attempt::create($attempt->id);
     $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
     $attemptobj->process_finish($timenow, false);
     // Can we start a new attempt? We shall not!
     $result = mod_quiz_external::get_attempt_access_information($quiz->id, $attempt->id);
     $result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_access_information_returns(), $result);
     // Now new attemps allowed.
     $this->assertCount(1, $result['preventnewattemptreasons']);
     $this->assertFalse($result['ispreflightcheckrequired']);
     $this->assertEquals(get_string('nomoreattempts', 'quiz'), $result['preventnewattemptreasons'][0]);
 }
Exemplo n.º 22
0
 public function test_is_manual_grade_in_range_ungraded()
 {
     $this->assertTrue(question_engine::is_manual_grade_in_range(1, 2));
 }
Exemplo n.º 23
0
 public function make_behaviour(question_attempt $qa, $preferredbehaviour)
 {
     return question_engine::make_behaviour('manualgraded', $qa, $preferredbehaviour);
 }
Exemplo n.º 24
0
 public function test_quiz_get_user_attempts()
 {
     global $DB;
     $this->resetAfterTest();
     $dg = $this->getDataGenerator();
     $quizgen = $dg->get_plugin_generator('mod_quiz');
     $course = $dg->create_course();
     $u1 = $dg->create_user();
     $u2 = $dg->create_user();
     $u3 = $dg->create_user();
     $u4 = $dg->create_user();
     $role = $DB->get_record('role', ['shortname' => 'student']);
     $dg->enrol_user($u1->id, $course->id, $role->id);
     $dg->enrol_user($u2->id, $course->id, $role->id);
     $dg->enrol_user($u3->id, $course->id, $role->id);
     $dg->enrol_user($u4->id, $course->id, $role->id);
     $quiz1 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]);
     $quiz2 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]);
     // Questions.
     $questgen = $dg->get_plugin_generator('core_question');
     $quizcat = $questgen->create_question_category();
     $question = $questgen->create_question('numerical', null, ['category' => $quizcat->id]);
     quiz_add_quiz_question($question->id, $quiz1);
     quiz_add_quiz_question($question->id, $quiz2);
     $quizobj1a = quiz::create($quiz1->id, $u1->id);
     $quizobj1b = quiz::create($quiz1->id, $u2->id);
     $quizobj1c = quiz::create($quiz1->id, $u3->id);
     $quizobj1d = quiz::create($quiz1->id, $u4->id);
     $quizobj2a = quiz::create($quiz2->id, $u1->id);
     // Set attempts.
     $quba1a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1a->get_context());
     $quba1a->set_preferred_behaviour($quizobj1a->get_quiz()->preferredbehaviour);
     $quba1b = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1b->get_context());
     $quba1b->set_preferred_behaviour($quizobj1b->get_quiz()->preferredbehaviour);
     $quba1c = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1c->get_context());
     $quba1c->set_preferred_behaviour($quizobj1c->get_quiz()->preferredbehaviour);
     $quba1d = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1d->get_context());
     $quba1d->set_preferred_behaviour($quizobj1d->get_quiz()->preferredbehaviour);
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $timenow = time();
     // User 1 passes quiz 1.
     $attempt = quiz_create_attempt($quizobj1a, 1, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj1a, $quba1a, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1a, $quba1a, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_submitted_actions($timenow, false, [1 => ['answer' => '3.14']]);
     $attemptobj->process_finish($timenow, false);
     // User 2 goes overdue in quiz 1.
     $attempt = quiz_create_attempt($quizobj1b, 1, false, $timenow, false, $u2->id);
     quiz_start_new_attempt($quizobj1b, $quba1b, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1b, $quba1b, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_going_overdue($timenow, true);
     // User 3 does not finish quiz 1.
     $attempt = quiz_create_attempt($quizobj1c, 1, false, $timenow, false, $u3->id);
     quiz_start_new_attempt($quizobj1c, $quba1c, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1c, $quba1c, $attempt);
     // User 4 abandons the quiz 1.
     $attempt = quiz_create_attempt($quizobj1d, 1, false, $timenow, false, $u4->id);
     quiz_start_new_attempt($quizobj1d, $quba1d, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1d, $quba1d, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_abandon($timenow, true);
     // User 1 attempts the quiz three times (abandon, finish, in progress).
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $attempt = quiz_create_attempt($quizobj2a, 1, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_abandon($timenow, true);
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $attempt = quiz_create_attempt($quizobj2a, 2, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 2, $timenow);
     quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_finish($timenow, false);
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $attempt = quiz_create_attempt($quizobj2a, 3, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 3, $timenow);
     quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
     // Check for user 1.
     $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'finished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'unfinished');
     $this->assertCount(0, $attempts);
     // Check for user 2.
     $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state);
     $this->assertEquals($u2->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'finished');
     $this->assertCount(0, $attempts);
     $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'unfinished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state);
     $this->assertEquals($u2->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     // Check for user 3.
     $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u3->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'finished');
     $this->assertCount(0, $attempts);
     $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'unfinished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u3->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     // Check for user 4.
     $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u4->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'finished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u4->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'unfinished');
     $this->assertCount(0, $attempts);
     // Multiple attempts for user 1 in quiz 2.
     $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'all');
     $this->assertCount(3, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'finished');
     $this->assertCount(2, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'unfinished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     // Multiple quiz attempts fetched at once.
     $attempts = quiz_get_user_attempts([$quiz1->id, $quiz2->id], $u1->id, 'all');
     $this->assertCount(4, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
 }
 public function test_load_with_unnecessary_autosaved_data()
 {
     // The point here is that the somehow (probably due to two things
     // happening concurrently, we have autosaved data in the database that
     // has already been superceded by real data, so it should be ignored.
     // There is also a second lot of redundant data to delete.
     $records = new question_test_recordset(array(array('questionattemptid', 'contextid', 'questionusageid', 'slot', 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'maxfraction', 'flagged', 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', 'attemptstepid', 'sequencenumber', 'state', 'fraction', 'timecreated', 'userid', 'name', 'value'), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 5, -2, 'complete', null, 1256233715, 1, 'answer', '0'), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 4, -1, 'complete', null, 1256233715, 1, 'answer', '0'), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 2, 1, 'complete', null, 1256233705, 1, 'answer', '1'), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 1, '', '', '', 1256233790, 3, 2, 'complete', null, 1256233710, 1, 'answer', '0')));
     $question = test_question_maker::make_question('truefalse', 'true');
     $question->id = -1;
     question_bank::start_unit_test();
     question_bank::load_test_question_data($question);
     $observer = new testable_question_engine_unit_of_work(question_engine::make_questions_usage_by_activity('unit_test', context_system::instance()));
     $qa = question_attempt::load_from_records($records, 1, $observer, 'deferredfeedback');
     question_bank::end_unit_test();
     $this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
     $this->assertEquals(3, $qa->get_num_steps());
     $this->assertFalse($qa->has_autosaved_step());
     $step = $qa->get_step(0);
     $this->assertEquals(question_state::$todo, $step->get_state());
     $this->assertNull($step->get_fraction());
     $this->assertEquals(1256233700, $step->get_timecreated());
     $this->assertEquals(1, $step->get_user_id());
     $this->assertEquals(array(), $step->get_all_data());
     $step = $qa->get_step(1);
     $this->assertEquals(question_state::$complete, $step->get_state());
     $this->assertNull($step->get_fraction());
     $this->assertEquals(1256233705, $step->get_timecreated());
     $this->assertEquals(1, $step->get_user_id());
     $this->assertEquals(array('answer' => '1'), $step->get_all_data());
     $step = $qa->get_step(2);
     $this->assertEquals(question_state::$complete, $step->get_state());
     $this->assertNull($step->get_fraction());
     $this->assertEquals(1256233710, $step->get_timecreated());
     $this->assertEquals(1, $step->get_user_id());
     $this->assertEquals(array('answer' => '0'), $step->get_all_data());
     $this->assertEquals(2, count($observer->get_steps_deleted()));
 }
Exemplo n.º 26
0
/**
 * @param array $questionids of question ids.
 * @return boolean whether any of these questions are being used by any part of Moodle.
 */
function questions_in_use($questionids)
{
    global $CFG;
    if (question_engine::questions_in_use($questionids)) {
        return true;
    }
    foreach (core_component::get_plugin_list('mod') as $module => $path) {
        $lib = $path . '/lib.php';
        if (is_readable($lib)) {
            include_once $lib;
            $fn = $module . '_questions_in_use';
            if (function_exists($fn)) {
                if ($fn($questionids)) {
                    return true;
                }
            } else {
                // Fallback for legacy modules.
                $fn = $module . '_question_list_instances';
                if (function_exists($fn)) {
                    foreach ($questionids as $questionid) {
                        $instances = $fn($questionid);
                        if (!empty($instances)) {
                            return true;
                        }
                    }
                }
            }
        }
    }
    return false;
}
Exemplo n.º 27
0
/**
 * Save changes to question instance
 *
 * Saves changes to the question grades in the quiz_question_instances table.
 * It does not update 'sumgrades' in the quiz table.
 *
 * @param int grade    The maximal grade for the question
 * @param int $questionid  The id of the question
 * @param int $quizid  The id of the quiz to update / add the instances for.
 */
function quiz_update_question_instance($grade, $questionid, $quiz) {
    global $DB;
    $instance = $DB->get_record('quiz_question_instances', array('quiz' => $quiz->id,
            'question' => $questionid));
    $slot = quiz_get_slot_for_question($quiz, $questionid);

    if (!$instance || !$slot) {
        throw new coding_exception('Attempt to change the grade of a quesion not in the quiz.');
    }

    if (abs($grade - $instance->grade) < 1e-7) {
        // Grade has not changed. Nothing to do.
        return;
    }

    $instance->grade = $grade;
    $DB->update_record('quiz_question_instances', $instance);
    question_engine::set_max_mark_in_attempts(new qubaids_for_quiz($quiz->id),
            $slot, $grade);
}
Exemplo n.º 28
0
 /**
  * Create a question_attempt_with_restricted_history
  * @param question_attempt $baseqa The question_attempt to make a restricted version of.
  * @param int $lastseq the index of the last step to include.
  * @param string $preferredbehaviour the preferred behaviour. It is slightly
  *      annoyting that this needs to be passed, but unavoidable for now.
  */
 public function __construct(question_attempt $baseqa, $lastseq, $preferredbehaviour)
 {
     $this->baseqa = $baseqa->get_full_qa();
     if ($lastseq < 0 || $lastseq >= $this->baseqa->get_num_steps()) {
         throw new coding_exception('$lastseq out of range', $lastseq);
     }
     $this->steps = array_slice($this->baseqa->steps, 0, $lastseq + 1);
     $this->observer = new question_usage_null_observer();
     // This should be a straight copy of all the remaining fields.
     $this->id = $this->baseqa->id;
     $this->usageid = $this->baseqa->usageid;
     $this->slot = $this->baseqa->slot;
     $this->question = $this->baseqa->question;
     $this->maxmark = $this->baseqa->maxmark;
     $this->minfraction = $this->baseqa->minfraction;
     $this->maxfraction = $this->baseqa->maxfraction;
     $this->questionsummary = $this->baseqa->questionsummary;
     $this->responsesummary = $this->baseqa->responsesummary;
     $this->rightanswer = $this->baseqa->rightanswer;
     $this->flagged = $this->baseqa->flagged;
     // Except behaviour, where we need to create a new one.
     $this->behaviour = question_engine::make_behaviour($this->baseqa->get_behaviour_name(), $this, $preferredbehaviour);
 }
Exemplo n.º 29
0
 /**
  * Regrade a particular quiz attempt. Either for real ($dryrun = false), or
  * as a pretend regrade to see which fractions would change. The outcome is
  * stored in the quiz_overview_regrades table.
  *
  * Note, $attempt is not upgraded in the database. The caller needs to do that.
  * However, $attempt->sumgrades is updated, if this is not a dry run.
  *
  * @param object $attempt the quiz attempt to regrade.
  * @param bool $dryrun if true, do a pretend regrade, otherwise do it for real.
  * @param array $slots if null, regrade all questions, otherwise, just regrade
  *      the quetsions with those slots.
  */
 protected function regrade_attempt($attempt, $dryrun = false, $slots = null)
 {
     global $DB;
     $transaction = $DB->start_delegated_transaction();
     $quba = question_engine::load_questions_usage_by_activity($attempt->uniqueid);
     if (is_null($slots)) {
         $slots = $quba->get_slots();
     }
     $finished = $attempt->timefinish > 0;
     foreach ($slots as $slot) {
         $qqr = new stdClass();
         $qqr->oldfraction = $quba->get_question_fraction($slot);
         $quba->regrade_question($slot, $finished);
         $qqr->newfraction = $quba->get_question_fraction($slot);
         if (abs($qqr->oldfraction - $qqr->newfraction) > 1.0E-7) {
             $qqr->questionusageid = $quba->get_id();
             $qqr->slot = $slot;
             $qqr->regraded = empty($dryrun);
             $qqr->timemodified = time();
             $DB->insert_record('quiz_overview_regrades', $qqr, false);
         }
     }
     if (!$dryrun) {
         question_engine::save_questions_usage_by_activity($quba);
     }
     $transaction->allow_commit();
 }
            if (empty($quizobj->get_quiz()->showblocks)) {
                $PAGE->blocks->show_only_fake_blocks();
            }
            echo $output->start_attempt_page($quizobj, $mform);
            die;
        }
    }
    // Pre-flight check passed.
    $accessmanager->notify_preflight_check_passed($currentattemptid);
}
if ($currentattemptid) {
    redirect($quizobj->attempt_url($currentattemptid, $page));
}
// Delete any previous preview attempts belonging to this user.
quiz_delete_previews($quizobj->get_quiz(), $USER->id);
$quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
$quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
// Create the new attempt and initialize the question sessions
$timenow = time();
// Update time now, in case the server is running really slowly.
$attempt = quiz_create_attempt($quizobj, $attemptnumber, $lastattempt, $timenow, $quizobj->is_preview_user());
if (!($quizobj->get_quiz()->attemptonlast && $lastattempt)) {
    $attempt = quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow);
} else {
    $attempt = quiz_start_attempt_built_on_last($quba, $attempt, $lastattempt);
}
$transaction = $DB->start_delegated_transaction();
$attempt = quiz_attempt_save_started($quizobj, $quba, $attempt);
quiz_fire_attempt_started_event($attempt, $quizobj);
$transaction->allow_commit();
// Redirect to the attempt page.