public function test_quiz_report_overview_report_forcesubmit_specific_attempt() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator(); $quizgenerator = $generator->get_plugin_generator('mod_quiz'); $questiongenerator = $generator->get_plugin_generator('core_question'); // Make a user to do the quiz. $user1 = $generator->create_user(); $user2 = $generator->create_user(); $user3 = $generator->create_user(); // Create our course. $course = $generator->create_course(array('visible' => true)); // Create the quiz. $quiz = $quizgenerator->create_instance(array('course' => $course->id, 'visible' => true, 'questionsperpage' => 0, 'grade' => 100.0, 'sumgrades' => 2)); // Create two questions. $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 the questions to the quiz. quiz_add_quiz_question($saq->id, $quiz); quiz_add_quiz_question($numq->id, $quiz); // Get a quiz object with user access overrides. $quizobj = quiz::create($quiz->id, $user1->id); $quizobj2 = quiz::create($quiz->id, $user2->id); $quizobj3 = quiz::create($quiz->id, $user3->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); $quba2 = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2->get_context()); $quba2->set_preferred_behaviour($quizobj2->get_quiz()->preferredbehaviour); $quba3 = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj3->get_context()); $quba3->set_preferred_behaviour($quizobj3->get_quiz()->preferredbehaviour); // Create a quiz attempt. $timenow = time(); $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $user1->id); $attempt2 = quiz_create_attempt($quizobj2, 1, false, $timenow, false, $user2->id); $attempt3 = quiz_create_attempt($quizobj3, 1, false, $timenow, false, $user3->id); // Start the attempt. quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow); quiz_attempt_save_started($quizobj, $quba, $attempt); quiz_start_new_attempt($quizobj2, $quba2, $attempt2, 1, $timenow); quiz_attempt_save_started($quizobj2, $quba2, $attempt2); quiz_start_new_attempt($quizobj3, $quba3, $attempt3, 1, $timenow); quiz_attempt_save_started($quizobj3, $quba3, $attempt3); // Answer first question and set it overdue. $tosubmit = array(1 => array('answer' => 'frog')); $tosubmit2 = array(1 => array('answer' => 'tiger')); $tosubmit3 = array(1 => array('answer' => 'tiger')); $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_submitted_actions($timenow, true, $tosubmit); $attemptobj2 = quiz_attempt::create($attempt2->id); $attemptobj2->process_submitted_actions($timenow, true, $tosubmit2); $attemptobj3 = quiz_attempt::create($attempt3->id); $attemptobj3->process_submitted_actions($timenow, true, $tosubmit3); // Finish the attempt. $attemptobj = quiz_attempt::create($attempt->id); $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question()); $attemptobj->process_abandon($timenow, false); // Re-load quiz attempt2 data. $attemptobj = quiz_attempt::create($attempt->id); $attemptobj2 = quiz_attempt::create($attempt2->id); $attemptobj3 = quiz_attempt::create($attempt3->id); // Check that the state of the attempt is as expected. $this->assertEquals(1, $attemptobj->get_attempt_number()); $this->assertEquals(quiz_attempt::ABANDONED, $attemptobj->get_state()); $this->assertEquals($user1->id, $attemptobj->get_userid()); $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question()); // Check that the state of the attempt2 is as expected. $this->assertEquals(1, $attemptobj2->get_attempt_number()); $this->assertEquals(quiz_attempt::OVERDUE, $attemptobj2->get_state()); $this->assertEquals($user2->id, $attemptobj2->get_userid()); $this->assertTrue($attemptobj2->has_response_to_at_least_one_graded_question()); // Check that the state of the attempt3 is as expected. $this->assertEquals(1, $attemptobj3->get_attempt_number()); $this->assertEquals(quiz_attempt::OVERDUE, $attemptobj3->get_state()); $this->assertEquals($user3->id, $attemptobj3->get_userid()); $this->assertTrue($attemptobj3->has_response_to_at_least_one_graded_question()); // Force submit the attempts. $overviewreport = new quiz_overview_report_testable(); $overviewreport->forcesubmit_attempts($quiz, false, array(), array($attempt->id, $attempt3->id)); // Check that it is now finished. $attemptobj = quiz_attempt::create($attempt->id); $this->assertEquals(quiz_attempt::FINISHED, $attemptobj->get_state()); $attemptobj2 = quiz_attempt::create($attempt2->id); $this->assertEquals(quiz_attempt::OVERDUE, $attemptobj2->get_state()); $attemptobj3 = quiz_attempt::create($attempt3->id); $this->assertEquals(quiz_attempt::FINISHED, $attemptobj3->get_state()); }
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); }
/** * Test checking the completion state of a quiz. */ public function test_quiz_get_completion_state() { global $CFG, $DB; $this->resetAfterTest(true); // Enable completion before creating modules, otherwise the completion data is not written in DB. $CFG->enablecompletion = true; // Create a course and student. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => true)); $passstudent = $this->getDataGenerator()->create_user(); $failstudent = $this->getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); $this->assertNotEmpty($studentrole); // Enrol students. $this->assertTrue($this->getDataGenerator()->enrol_user($passstudent->id, $course->id, $studentrole->id)); $this->assertTrue($this->getDataGenerator()->enrol_user($failstudent->id, $course->id, $studentrole->id)); // Make a scale and an outcome. $scale = $this->getDataGenerator()->create_scale(); $data = array('courseid' => $course->id, 'fullname' => 'Team work', 'shortname' => 'Team work', 'scaleid' => $scale->id); $outcome = $this->getDataGenerator()->create_grade_outcome($data); // Make a quiz with the outcome on. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); $data = array('course' => $course->id, 'outcome_' . $outcome->id => 1, 'grade' => 100.0, 'questionsperpage' => 0, 'sumgrades' => 1, 'completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionpass' => 1); $quiz = $quizgenerator->create_instance($data); $cm = get_coursemodule_from_id('quiz', $quiz->cmid); // Create a couple of 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); $quizobj = quiz::create($quiz->id, $passstudent->id); // Set grade to pass. $item = grade_item::fetch(array('courseid' => $course->id, 'itemtype' => 'mod', 'itemmodule' => 'quiz', 'iteminstance' => $quiz->id, 'outcomeid' => null)); $item->gradepass = 80; $item->update(); // Start the passing 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, $passstudent->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); // Start the failing 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, $failstudent->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' => '0')); $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); // Check the results. $this->assertTrue(quiz_get_completion_state($course, $cm, $passstudent->id, 'return')); $this->assertFalse(quiz_get_completion_state($course, $cm, $failstudent->id, 'return')); }
/** * Test start_attempt */ public function test_start_attempt() { global $DB; // Create a new quiz with attempts. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); $data = array('course' => $this->course->id, 'sumgrades' => 1); $quiz = $quizgenerator->create_instance($data); $context = context_module::instance($quiz->cmid); try { mod_quiz_external::start_attempt($quiz->id); $this->fail('Exception expected due to missing questions.'); } catch (moodle_quiz_exception $e) { $this->assertEquals('noquestionsfound', $e->errorcode); } // Create a question. $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); $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); // Try to open attempt in closed quiz. $quiz->timeopen = time() - WEEKSECS; $quiz->timeclose = time() - DAYSECS; $DB->update_record('quiz', $quiz); $result = mod_quiz_external::start_attempt($quiz->id); $result = external_api::clean_returnvalue(mod_quiz_external::start_attempt_returns(), $result); $this->assertEquals([], $result['attempt']); $this->assertCount(1, $result['warnings']); // Now with a password. $quiz->timeopen = 0; $quiz->timeclose = 0; $quiz->password = '******'; $DB->update_record('quiz', $quiz); try { mod_quiz_external::start_attempt($quiz->id, array(array("name" => "quizpassword", "value" => 'bad'))); $this->fail('Exception expected due to invalid passwod.'); } catch (moodle_exception $e) { $this->assertEquals(get_string('passworderror', 'quizaccess_password'), $e->errorcode); } // Now, try everything correct. $result = mod_quiz_external::start_attempt($quiz->id, array(array("name" => "quizpassword", "value" => 'abc'))); $result = external_api::clean_returnvalue(mod_quiz_external::start_attempt_returns(), $result); $this->assertEquals(1, $result['attempt']['attempt']); $this->assertEquals($this->student->id, $result['attempt']['userid']); $this->assertEquals($quiz->id, $result['attempt']['quiz']); $this->assertCount(0, $result['warnings']); $attemptid = $result['attempt']['id']; // We are good, try to start a new attempt now. try { mod_quiz_external::start_attempt($quiz->id, array(array("name" => "quizpassword", "value" => 'abc'))); $this->fail('Exception expected due to attempt not finished.'); } catch (moodle_quiz_exception $e) { $this->assertEquals('attemptstillinprogress', $e->errorcode); } // Finish the started attempt. // Process some responses from the student. $timenow = time(); $attemptobj = quiz_attempt::create($attemptid); $tosubmit = array(1 => array('answer' => '3.14')); $attemptobj->process_submitted_actions($timenow, false, $tosubmit); // Finish the attempt. $attemptobj = quiz_attempt::create($attemptid); $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question()); $attemptobj->process_finish($timenow, false); // We should be able to start a new attempt. $result = mod_quiz_external::start_attempt($quiz->id, array(array("name" => "quizpassword", "value" => 'abc'))); $result = external_api::clean_returnvalue(mod_quiz_external::start_attempt_returns(), $result); $this->assertEquals(2, $result['attempt']['attempt']); $this->assertEquals($this->student->id, $result['attempt']['userid']); $this->assertEquals($quiz->id, $result['attempt']['quiz']); $this->assertCount(0, $result['warnings']); // Test user with no capabilities. // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles. assign_capability('mod/quiz:attempt', CAP_PROHIBIT, $this->studentrole->id, $context->id); // Empty all the caches that may be affected by this change. accesslib_clear_all_caches_for_unit_testing(); course_modinfo::clear_instance_cache(); try { mod_quiz_external::start_attempt($quiz->id); $this->fail('Exception expected due to missing capability.'); } catch (required_capability_exception $e) { $this->assertEquals('nopermissions', $e->errorcode); } }
/** * Return the potential question types that would be required for a given quiz. * Please note that for random question types we return the potential question types in the category choosen. * * @param int $quizid quiz instance id * @return array of warnings and the access information * @since Moodle 3.1 * @throws moodle_quiz_exception */ public static function get_quiz_required_qtypes($quizid) { global $DB, $USER; $warnings = array(); $params = array('quizid' => $quizid); $params = self::validate_parameters(self::get_quiz_required_qtypes_parameters(), $params); list($quiz, $course, $cm, $context) = self::validate_quiz($params['quizid']); $quizobj = quiz::create($cm->instance, $USER->id); $quizobj->preload_questions(); $quizobj->load_questions(); // Question types used. $result = array(); $result['questiontypes'] = $quizobj->get_all_question_types_used(true); $result['warnings'] = $warnings; return $result; }
/** * 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]); }
} if (!($cm = get_coursemodule_from_instance("quiz", $quiz->id, $course->id))) { print_error('invalidcoursemodule'); } } /// Check login and get context. require_login($course->id, false, $cm); $context = get_context_instance(CONTEXT_MODULE, $cm->id); require_capability('mod/quiz:view', $context); /// Cache some other capabilities we use several times. $canattempt = has_capability('mod/quiz:attempt', $context); $canreviewmine = has_capability('mod/quiz:reviewmyattempts', $context); $canpreview = has_capability('mod/quiz:preview', $context); /// Create an object to manage all the other (non-roles) access rules. $timenow = time(); $accessmanager = new quiz_access_manager(quiz::create($quiz->id, $USER->id), $timenow, has_capability('mod/quiz:ignoretimelimits', $context, NULL, false)); /// If no questions have been set up yet redirect to edit.php if (!$quiz->questions && has_capability('mod/quiz:manage', $context)) { redirect($CFG->wwwroot . '/mod/quiz/edit.php?cmid=' . $cm->id); } /// Log this request. add_to_log($course->id, "quiz", "view", "view.php?id={$cm->id}", $quiz->id, $cm->id); // Mark module as viewed $completion = new completion_info($course); $completion->set_module_viewed($cm); /// Initialize $PAGE, compute blocks $PAGE->set_url('/mod/quiz/view.php', array('id' => $cm->id)); $edit = optional_param('edit', -1, PARAM_BOOL); if ($edit != -1 && $PAGE->user_allowed_editing()) { $USER->editing = $edit; }
/** * Returns a list of quizzes in a provided list of courses, * if no list is provided all quizzes that the user can view will be returned. * * @param array $courseids Array of course ids * @return array of quizzes details * @since Moodle 3.1 */ public static function get_quizzes_by_courses($courseids = array()) { global $USER; $warnings = array(); $returnedquizzes = array(); $params = array('courseids' => $courseids); $params = self::validate_parameters(self::get_quizzes_by_courses_parameters(), $params); $mycourses = array(); if (empty($params['courseids'])) { $mycourses = enrol_get_my_courses(); $params['courseids'] = array_keys($mycourses); } // Ensure there are courseids to loop through. if (!empty($params['courseids'])) { list($courses, $warnings) = external_util::validate_courses($params['courseids'], $mycourses); // Get the quizzes in this course, this function checks users visibility permissions. // We can avoid then additional validate_context calls. $quizzes = get_all_instances_in_courses("quiz", $courses); foreach ($quizzes as $quiz) { $context = context_module::instance($quiz->coursemodule); // Update quiz with override information. $quiz = quiz_update_effective_access($quiz, $USER->id); // Entry to return. $quizdetails = array(); // First, we return information that any user can see in the web interface. $quizdetails['id'] = $quiz->id; $quizdetails['coursemodule'] = $quiz->coursemodule; $quizdetails['course'] = $quiz->course; $quizdetails['name'] = external_format_string($quiz->name, $context->id); if (has_capability('mod/quiz:view', $context)) { // Format intro. list($quizdetails['intro'], $quizdetails['introformat']) = external_format_text($quiz->intro, $quiz->introformat, $context->id, 'mod_quiz', 'intro', null); $viewablefields = array('timeopen', 'timeclose', 'grademethod', 'section', 'visible', 'groupmode', 'groupingid'); $timenow = time(); $quizobj = quiz::create($quiz->id, $USER->id); $accessmanager = new quiz_access_manager($quizobj, $timenow, has_capability('mod/quiz:ignoretimelimits', $context, null, false)); // Fields the user could see if have access to the quiz. if (!$accessmanager->prevent_access()) { // Some times this function returns just empty. $hasfeedback = quiz_has_feedback($quiz); $quizdetails['hasfeedback'] = !empty($hasfeedback) ? 1 : 0; $quizdetails['hasquestions'] = (int) $quizobj->has_questions(); $quizdetails['autosaveperiod'] = get_config('quiz', 'autosaveperiod'); $additionalfields = array('timelimit', 'attempts', 'attemptonlast', 'grademethod', 'decimalpoints', 'questiondecimalpoints', 'reviewattempt', 'reviewcorrectness', 'reviewmarks', 'reviewspecificfeedback', 'reviewgeneralfeedback', 'reviewrightanswer', 'reviewoverallfeedback', 'questionsperpage', 'navmethod', 'sumgrades', 'grade', 'browsersecurity', 'delay1', 'delay2', 'showuserpicture', 'showblocks', 'completionattemptsexhausted', 'completionpass', 'overduehandling', 'graceperiod', 'preferredbehaviour', 'canredoquestions'); $viewablefields = array_merge($viewablefields, $additionalfields); } // Fields only for managers. if (has_capability('moodle/course:manageactivities', $context)) { $additionalfields = array('shuffleanswers', 'timecreated', 'timemodified', 'password', 'subnet'); $viewablefields = array_merge($viewablefields, $additionalfields); } foreach ($viewablefields as $field) { $quizdetails[$field] = $quiz->{$field}; } } $returnedquizzes[] = $quizdetails; } } $result = array(); $result['quizzes'] = $returnedquizzes; $result['warnings'] = $warnings; return $result; }
} // Get the users enrolled $users = emarking_get_enroled_students($course->id); $pbar = new progress_bar(); $pbar->create(); if ($create) { quiz_delete_all_attempts($quiz); } $cur = 1; $total = count($users); // Insert answers or finish the attempt for each student foreach ($users as $user) { $pbar->update($cur, $total, get_string('processing', 'mod_emarking') . $user->lastname . $user->firstname); flush(); // Get the quiz instance for the specific student $quizobj = quiz::create($cm->instance, $user->id); // Get all the attempts $attempts = quiz_get_user_attempts($quizobj->get_quizid(), $user->id, 'all'); if ($create) { emarking_add_user_attempt($cm, $user); } else { // For each attempt insert the answers or finish foreach ($attempts as $attempt) { if ($finish) { emarking_finish_user_attempt($attempt->id); } } } $cur++; } $pbar->update_full(100, get_string('finished', 'mod_emarking'));
} } /// Check login and get context. require_login($course->id, false, $cm); $context = get_context_instance(CONTEXT_MODULE, $cm->id); require_capability('mod/quiz:view', $context); /// Cache some other capabilities we use several times. $canattempt = has_capability('mod/quiz:attempt', $context); $canreviewmine = has_capability('mod/quiz:reviewmyattempts', $context); $canpreview = has_capability('mod/quiz:preview', $context); /// Create an object to manage all the other (non-roles) access rules. $timenow = time(); $accessmanager = new quiz_access_manager(quiz::create($quiz->id, $USER->id), $timenow, has_capability('mod/quiz:ignoretimelimits', $context, NULL, false)); /// If no questions have been set up yet redirect to edit.php if (!$quiz->questions && has_capability('mod/quiz:manage', $context)) { redirect($CFG->wwwroot . '/mod/quiz/edit.php?cmid=' . $cm->id); } /// Log this request. add_to_log($course->id, "quiz", "view", "view.php?id=$cm->id", $quiz->id, $cm->id); /// Initialize $PAGE, compute blocks $PAGE->set_url('/mod/quiz/view.php', array('id' => $cm->id)); $edit = optional_param('edit', -1, PARAM_BOOL); if ($edit != -1 && $PAGE->user_allowed_editing()) {
/** * @param $steps PHPUnit_Extensions_Database_DataSet_ITable the step data from the csv file. * @return array attempt no as in csv file => the id of the quiz_attempt as stored in the db. */ protected function walkthrough_attempts($steps) { global $DB; $attemptids = array(); for ($rowno = 0; $rowno < $steps->getRowCount(); $rowno++) { $step = $this->explode_dot_separated_keys_to_make_subindexs($steps->getRow($rowno)); // Find existing user or make a new user to do the quiz. $username = array('firstname' => $step['firstname'], 'lastname' => $step['lastname']); if (!($user = $DB->get_record('user', $username))) { $user = $this->getDataGenerator()->create_user($username); } if (!isset($attemptids[$step['quizattempt']])) { // Start the attempt. $quizobj = quiz::create($this->quiz->id, $user->id); $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); $prevattempts = quiz_get_user_attempts($this->quiz->id, $user->id, 'all', true); $attemptnumber = count($prevattempts) + 1; $timenow = time(); $attempt = quiz_create_attempt($quizobj, $attemptnumber, false, $timenow, false, $user->id); // Select variant and / or random sub question. if (!isset($step['variants'])) { $step['variants'] = array(); } if (isset($step['randqs'])) { // Replace 'names' with ids. foreach ($step['randqs'] as $slotno => $randqname) { $step['randqs'][$slotno] = $this->randqids[$slotno][$randqname]; } } else { $step['randqs'] = array(); } quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow, $step['randqs'], $step['variants']); quiz_attempt_save_started($quizobj, $quba, $attempt); $attemptid = $attemptids[$step['quizattempt']] = $attempt->id; } else { $attemptid = $attemptids[$step['quizattempt']]; } // Process some responses from the student. $attemptobj = quiz_attempt::create($attemptid); $attemptobj->process_submitted_actions($timenow, false, $step['responses']); // Finish the attempt. if (!isset($step['finished']) || $step['finished'] == 1) { $attemptobj = quiz_attempt::create($attemptid); $attemptobj->process_finish($timenow, false); } } return $attemptids; }
function exportQuestionMedia() { global $DB, $CFG, $USER, $QUIZ_CACHE, $CFG; $cm = get_coursemodule_from_id('quiz', $this->id); $context = context_module::instance($cm->id); $quiz = $DB->get_record('quiz', array('id' => $cm->instance), '*', MUST_EXIST); $quizobj = quiz::create($cm->instance, $USER->id); try { $quizobj->preload_questions(); $quizobj->load_questions(); $qs = $quizobj->get_questions(); foreach ($qs as $q) { $this->extractMedia($q->id, $q->questiontext); } } catch (moodle_exception $me) { return; } }
function get_employeescore($id,$course,$userid) { $cm = get_coursemodule_from_instance("quiz", $id, $course); $quizobj = quiz::create($cm->instance, $userid); $quiz = $quizobj->get_quiz(); $viewobj = new mod_quiz_view_object(); $attempts = quiz_get_user_attempts($id, $userid, 'finished', true); $lastfinishedattempt = end($attempts); $numattempts = count($attempts); $viewobj->attempts = $attempts; $viewobj->attemptobjs = array(); foreach ($attempts as $attempt) { $viewobj->attemptobjs[] = new quiz_attempt($attempt, $quiz, $cm, $quiz->course, false); } /*Function to display attemps and grades */ $attemptgrade=''; foreach ($viewobj->attemptobjs as $attemptobj) { $attemptgrade = quiz_rescale_grade($attemptobj->get_sum_marks(), $quiz, false); } return $attemptgrade; }
function is_quiz_finished($cmid) { global $USER, $CFG; require_once $CFG->dirroot . '/mod/quiz/locallib.php'; require_once $CFG->dirroot . '/mod/quiz/lib.php'; $cm = get_coursemodule_from_id('quiz', $cmid); $quizobj = quiz::create($cm->instance, $USER->id); $attempts = quiz_get_user_attempts($quizobj->get_quizid(), $USER->id, 'all', true); foreach ($attempts as $attempt) { if ($attempt && $attempt->state == quiz_attempt::FINISHED && $attempt->sumgrades == 1) { return true; } } return false; }
/** * Obtains the automatic completion state for this quiz on any conditions * in quiz settings, such as if all attempts are used or a certain grade is achieved. * * @param object $course Course * @param object $cm Course-module * @param int $userid User ID * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) * @return bool True if completed, false if not. (If no conditions, then return * value depends on comparison type) */ function quiz_get_completion_state($course, $cm, $userid, $type) { global $DB; global $CFG; $quiz = $DB->get_record('quiz', array('id' => $cm->instance), '*', MUST_EXIST); if (!$quiz->completionattemptsexhausted && !$quiz->completionpass) { return $type; } // Check if the user has used up all attempts. if ($quiz->completionattemptsexhausted) { $attempts = quiz_get_user_attempts($quiz->id, $userid, 'finished', true); if ($attempts) { $lastfinishedattempt = end($attempts); $context = context_module::instance($cm->id); $quizobj = quiz::create($quiz->id, $userid); $accessmanager = new quiz_access_manager($quizobj, time(), has_capability('mod/quiz:ignoretimelimits', $context, $userid, false)); if ($accessmanager->is_finished(count($attempts), $lastfinishedattempt)) { return true; } } } // Check for passing grade. if ($quiz->completionpass) { require_once $CFG->libdir . '/gradelib.php'; $item = grade_item::fetch(array('courseid' => $course->id, 'itemtype' => 'mod', 'itemmodule' => 'quiz', 'iteminstance' => $cm->instance, 'outcomeid' => null)); if ($item) { $grades = grade_grade::fetch_users_grades($item, array($userid), false); if (!empty($grades[$userid])) { return $grades[$userid]->is_passed($item); } } } return false; }
/** * Starts an attempt and returns the object representing it. * * @param int $quizid * @param int $userid * @throws moodle_exception * @return \stdClass */ public function start_quiz_attempt($quizid, $userid) { global $DB; $quizobj = quiz::create($quizid, $userid); $timenow = time(); $attempt = quiz_create_attempt($quizobj->get_quiz(), 1, false, $timenow, false); // Taken from /mod/quiz/startattempt.php. $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); // Starting a normal, new, quiz attempt. // Fully load all the questions in this quiz. $quizobj->preload_questions(); $quizobj->load_questions(); // Add them all to the $quba. $idstoslots = array(); $questionsinuse = array_keys($quizobj->get_questions()); foreach ($quizobj->get_questions() as $i => $questiondata) { if ($questiondata->qtype != 'random') { if (!$quizobj->get_quiz()->shuffleanswers) { $questiondata->options->shuffleanswers = false; } $question = question_bank::make_question($questiondata); } else { $question = question_bank::get_qtype('random')->choose_other_question($questiondata, $questionsinuse, $quizobj->get_quiz()->shuffleanswers); if (is_null($question)) { throw new moodle_exception('notenoughrandomquestions', 'quiz', $quizobj->view_url(), $questiondata); } } $idstoslots[$i] = $quba->add_question($question, $questiondata->maxmark); $questionsinuse[] = $question->id; } // Start all the questions. if ($attempt->preview) { $variantoffset = rand(1, 100); } else { $variantoffset = 1; } $quba->start_all_questions(new question_variant_pseudorandom_no_repeats_strategy($variantoffset), $timenow); // Update attempt layout. $newlayout = array(); foreach (explode(',', $attempt->layout) as $qid) { if ($qid != 0) { $newlayout[] = $idstoslots[$qid]; } else { $newlayout[] = 0; } } $attempt->layout = implode(',', $newlayout); question_engine::save_questions_usage_by_activity($quba); $attempt->uniqueid = $quba->get_id(); $attempt->id = $DB->insert_record('quiz_attempts', $attempt); return $attempt; }
/** * Utility method to submit an attempt on a quiz. * @param $quiz * @param $user * @param $answers * @return testable_assign */ private function submit_quiz_attempt($quiz, $user, $answers) { // Create a quiz attempt for the user. $quizobj = quiz::create($quiz->id, $user->id); // Set up and start an 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, $user->id); quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow); quiz_attempt_save_started($quizobj, $quba, $attempt); $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_submitted_actions($timenow, false, $answers); $timefinish = time(); // Finish the attempt. $attemptobj->process_finish($timefinish, false); return $timefinish; }
/** * Check if the module has any update that affects the current user since a given time. * * @param cm_info $cm course module data * @param int $from the time to check updates from * @param array $filter if we need to check only specific updates * @return stdClass an object with the different type of areas indicating if they were updated or not * @since Moodle 3.2 */ function quiz_check_updates_since(cm_info $cm, $from, $filter = array()) { global $DB, $USER, $CFG; require_once $CFG->dirroot . '/mod/quiz/locallib.php'; $updates = course_check_module_updates_since($cm, $from, array(), $filter); // Check if questions were updated. $updates->questions = (object) array('updated' => false); $quizobj = quiz::create($cm->instance, $USER->id); $quizobj->preload_questions(); $quizobj->load_questions(); $questionids = array_keys($quizobj->get_questions()); if (!empty($questionids)) { list($questionsql, $params) = $DB->get_in_or_equal($questionids, SQL_PARAMS_NAMED); $select = 'id ' . $questionsql . ' AND (timemodified > :time1 OR timecreated > :time2)'; $params['time1'] = $from; $params['time2'] = $from; $questions = $DB->count_records_select('question', $select, $params) > 0; if (!empty($questions)) { $updates->questions->updated = true; $updates->questions->itemids = array_keys($questions); } } // Check for new attempts or grades. $updates->attempts = (object) array('updated' => false); $updates->grades = (object) array('updated' => false); $select = 'quiz = ? AND userid = ? AND timemodified > ?'; $params = array($cm->instance, $USER->id, $from); $attempts = $DB->get_records_select('quiz_attempts', $select, $params, '', 'id'); if (!empty($attempts)) { $updates->attempts->updated = true; $updates->attempts->itemids = array_keys($attempts); } $grades = $DB->get_records_select('quiz_grades', $select, $params, '', 'id'); if (!empty($grades)) { $updates->grades->updated = true; $updates->grades->itemids = array_keys($grades); } return $updates; }
function emarking_add_user_attempt($cm, $user) { global $DB; // Get the quiz object $quizobj = quiz::create($cm->instance, $user->id); // TODO get to know what usage by activity means $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 $attemptnumber = 1; $lastattempt = null; $timenow = time(); // Update time now, in case the server is running really slowly. $attempt = quiz_create_attempt($quizobj, $attemptnumber, $lastattempt, $timenow, false, $user->id); $attempt = quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow); $transaction = $DB->start_delegated_transaction(); $attempt = quiz_attempt_save_started($quizobj, $quba, $attempt); $DB->commit_delegated_transaction($transaction); }
/** * This function is a copy of code taken from attempt_walkthrough_test.php * that creates a sample quiz and has a student complete the quiz. * * If the test suddenly stops working, grab the new code from that file, then * adjust to required inputs/outputs. * * @param object $course The course object to create the quiz in * @param object $student The student object that takes the quiz * @return array {attempt ID (int), quiz ID (int)} * */ private function create_quiz_attempt($course, $student) { // 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)); // 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); $quizobj = quiz::create($quiz->id, $student->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, false, $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); $prefix1 = $quba->get_field_prefix(1); $prefix2 = $quba->get_field_prefix(2); $tosubmit = array(1 => array('answer' => 'frog'), 2 => array('answer' => '3.14')); $attemptobj->process_submitted_actions($timenow, false, $tosubmit); // Finish the attempt. $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_finish($timenow, false); // Re-load quiz attempt data. $attemptobj = quiz_attempt::create($attempt->id); return array($attempt->id, $quiz->id); }
/** * Create a quiz with a single question with variants and walk through quiz attempts. * * @dataProvider get_correct_response_for_variants */ public function test_quiz_with_question_with_variants_attempt_walkthrough($variantno, $correctresponse, $done = false) { global $SITE; $this->resetAfterTest($done); $this->setAdminUser(); if ($this->quizwithvariants === null) { // Make a quiz. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); $this->quizwithvariants = $quizgenerator->create_instance(array('course'=>$SITE->id, 'questionsperpage' => 0, 'grade' => 100.0, 'sumgrades' => 1)); $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); $calc = $questiongenerator->create_question('calculatedsimple', 'sumwithvariants', array('category' => $cat->id)); quiz_add_quiz_question($calc->id, $this->quizwithvariants, 0); } // Make a new user to do the quiz. $user1 = $this->getDataGenerator()->create_user(); $this->setUser($user1); $quizobj = quiz::create($this->quizwithvariants->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); // Select variant. quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow, array(), array(1 => $variantno)); $this->assertEquals('1,0', $attempt->layout); quiz_attempt_save_started($quizobj, $quba, $attempt); // Process some responses from the student. $attemptobj = quiz_attempt::create($attempt->id); $tosubmit = array(1 => array('answer' => $correctresponse)); $attemptobj->process_submitted_actions($timenow, false, $tosubmit); // Finish the attempt. $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_finish($timenow, false); // Re-load quiz attempt data. $attemptobj = quiz_attempt::create($attempt->id); // Check that results are stored as expected. $this->assertEquals(1, $attemptobj->get_attempt_number()); $this->assertEquals(1, $attemptobj->get_sum_marks()); $this->assertEquals(true, $attemptobj->is_finished()); $this->assertEquals($timenow, $attemptobj->get_submitted_date()); $this->assertEquals($user1->id, $attemptobj->get_userid()); // Check quiz grades. $grades = quiz_get_user_grades($this->quizwithvariants, $user1->id); $grade = array_shift($grades); $this->assertEquals(100.0, $grade->rawgrade); // Check grade book. $gradebookgrades = grade_get_grades($SITE->id, 'mod', 'quiz', $this->quizwithvariants->id, $user1->id); $gradebookitem = array_shift($gradebookgrades->items); $gradebookgrade = array_shift($gradebookitem->grades); $this->assertEquals(100, $gradebookgrade->grade); }
require_once $CFG->dirroot . '/mod/quiz/locallib.php'; /// Get submitted parameters. $id = required_param('cmid', PARAM_INT); // Course Module ID $forcenew = optional_param('forcenew', false, PARAM_BOOL); // Used to force a new preview if (!($cm = get_coursemodule_from_id('quiz', $id))) { print_error('invalidcoursemodule'); } if (!($course = $DB->get_record('course', array('id' => $cm->course)))) { print_error("coursemisconf"); } if (!($quiz = $DB->get_record('quiz', array('id' => $cm->instance)))) { print_error('invalidcoursemodule'); } $quizobj = quiz::create($quiz->id, $USER->id); // This script should only ever be posted to, so set page URL to the view page. $PAGE->set_url($quizobj->view_url()); /// Check login and sesskey. require_login($quizobj->get_courseid(), false, $quizobj->get_cm()); if (!confirm_sesskey()) { throw new moodle_exception('confirmsesskeybad', 'error', $quizobj->view_url()); } $PAGE->set_pagelayout('base'); /// if no questions have been set up yet redirect to edit.php if (!$quizobj->get_question_ids() && $quizobj->has_capability('mod/quiz:manage')) { redirect($quizobj->edit_url()); } /// Create an object to manage all the other (non-roles) access rules. $accessmanager = $quizobj->get_access_manager(time()); if ($quizobj->is_preview_user() && $forcenew) {
// GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Rest endpoint for ajax editing for paging operations on the quiz structure. * * @package mod_quiz * @copyright 2014 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once __DIR__ . '/../../config.php'; require_once $CFG->dirroot . '/mod/quiz/locallib.php'; $cmid = required_param('cmid', PARAM_INT); $quizid = required_param('quizid', PARAM_INT); $slotnumber = required_param('slot', PARAM_INT); $repagtype = required_param('repag', PARAM_INT); require_sesskey(); $quizobj = quiz::create($quizid); require_login($quizobj->get_course(), false, $quizobj->get_cm()); require_capability('mod/quiz:manage', $quizobj->get_context()); if (quiz_has_attempts($quizid)) { $reportlink = quiz_attempt_summary_link_to_reports($quizobj->get_quiz(), $quizobj->get_cm(), $quizobj->get_context()); throw new \moodle_exception('cannoteditafterattempts', 'quiz', new moodle_url('/mod/quiz/edit.php', array('cmid' => $cmid)), $reportlink); } $slotnumber++; $repage = new \mod_quiz\repaginate($quizid); $repage->repaginate_slots($slotnumber, $repagtype); $structure = $quizobj->get_structure(); $slots = $structure->refresh_page_numbers_and_update_db($structure->get_quiz()); redirect(new moodle_url('edit.php', array('cmid' => $quizobj->get_cmid())));
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); }
/** * Starts a new attempt at a quiz. * * @param int $quizid quiz instance id * @param array $preflightdata preflight required data (like passwords) * @param bool $forcenew Whether to force a new attempt or not. * @return array of warnings and the attempt basic data * @since Moodle 3.1 * @throws moodle_quiz_exception */ public static function start_attempt($quizid, $preflightdata = array(), $forcenew = false) { global $DB, $USER; $warnings = array(); $attempt = array(); $params = array('quizid' => $quizid, 'preflightdata' => $preflightdata, 'forcenew' => $forcenew); $params = self::validate_parameters(self::start_attempt_parameters(), $params); $forcenew = $params['forcenew']; // Request and permission validation. $quiz = $DB->get_record('quiz', array('id' => $params['quizid']), '*', MUST_EXIST); list($course, $cm) = get_course_and_cm_from_instance($quiz, 'quiz'); $context = context_module::instance($cm->id); self::validate_context($context); $quizobj = quiz::create($cm->instance, $USER->id); // Check questions. if (!$quizobj->has_questions()) { throw new moodle_quiz_exception($quizobj, 'noquestionsfound'); } // Create an object to manage all the other (non-roles) access rules. $timenow = time(); $accessmanager = $quizobj->get_access_manager($timenow); // Validate permissions for creating a new attempt and start a new preview attempt if required. list($currentattemptid, $attemptnumber, $lastattempt, $messages, $page) = quiz_validate_new_attempt($quizobj, $accessmanager, $forcenew, -1, false); // Check access. if (!$quizobj->is_preview_user() && $messages) { // Create warnings with the exact messages. foreach ($messages as $message) { $warnings[] = array('item' => 'quiz', 'itemid' => $quiz->id, 'warningcode' => '1', 'message' => clean_text($message, PARAM_TEXT)); } } else { if ($accessmanager->is_preflight_check_required($currentattemptid)) { // Need to do some checks before allowing the user to continue. $provideddata = array(); foreach ($params['preflightdata'] as $data) { $provideddata[$data['name']] = $data['value']; } $errors = $accessmanager->validate_preflight_check($provideddata, [], $currentattemptid); if (!empty($errors)) { throw new moodle_quiz_exception($quizobj, array_shift($errors)); } // Pre-flight check passed. $accessmanager->notify_preflight_check_passed($currentattemptid); } if ($currentattemptid) { if ($lastattempt->state == quiz_attempt::OVERDUE) { throw new moodle_quiz_exception($quizobj, 'stateoverdue'); } else { throw new moodle_quiz_exception($quizobj, 'attemptstillinprogress'); } } $attempt = quiz_prepare_and_start_new_attempt($quizobj, $attemptnumber, $lastattempt); } $result = array(); $result['attempt'] = $attempt; $result['warnings'] = $warnings; return $result; }
} } // Check login and get context. require_login($course, false, $cm); $context = get_context_instance(CONTEXT_MODULE, $cm->id); require_capability('mod/quiz:view', $context); // Cache some other capabilities we use several times. $canattempt = has_capability('mod/quiz:attempt', $context); $canreviewmine = has_capability('mod/quiz:reviewmyattempts', $context); $canpreview = has_capability('mod/quiz:preview', $context); // Create an object to manage all the other (non-roles) access rules. $timenow = time(); $quizobj = quiz::create($cm->instance, $USER->id); $accessmanager = new quiz_access_manager($quizobj, $timenow, has_capability('mod/quiz:ignoretimelimits', $context, null, false)); $quiz = $quizobj->get_quiz(); // Log this request. add_to_log($course->id, 'quiz', 'view', 'view.php?id=' . $cm->id, $quiz->id, $cm->id); $completion = new completion_info($course); $completion->set_module_viewed($cm); // Initialize $PAGE, compute blocks $PAGE->set_url('/mod/quiz/view.php', array('id' => $cm->id)); // Get this user's attempts. $attempts = quiz_get_user_attempts($quiz->id, $USER->id, 'finished', true);
private static function quiz_attempt_process($id, $step, $forcenew, $page, $uid, $request, $key, $startedOn) { global $DB, $USER; $USER->id = $uid; $response = new CliniqueServiceResponce(); $quizobj = ''; //$timenow = time(); // Update time now, in case the server is running really slowly. $timenow = $startedOn; if (!($cm = get_coursemodule_from_id('quiz', $id))) { print_error('invalidcoursemodule'); } $quizobj = quiz::create($cm->instance, $uid); $attempts_allowed = self::attempts_allowed($attempt, $quizobj); // Create an object to manage all the other (non-roles) access rules. $accessmanager = $quizobj->get_access_manager($timenow); $attempt_nums = self::accessmanager_process($quizobj, $accessmanager, $forcenew, $uid); if ($attempts_allowed != 0) { if ($attempts_allowed < $attempt_nums->attemptnumber) { $block_res = self::get_blocked_response($request, '', $key); $response->response(false, "", $block_res); die; // $response->response(false, "", $request); } } $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 $attempt = quiz_create_attempt($quizobj, $attempt_nums->attemptnumber, $attempt_nums->lastattempt, $timenow, $quizobj->is_preview_user()); self::quiz_attempt_stepone($attempt, $attempt_nums->lastattempt, $quizobj, $timenow, $quba, $attempt_nums->attemptnumber); // 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); // Trigger event. $res = self::trigger_event($attempt, $quizobj); $transaction->allow_commit(); return $res; }