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()); }
/** * Do the processing required. * @param int $timenow the time to consider as 'now' during the processing. * @param int $processfrom the value of $processupto the last time update_overdue_attempts was * called called and completed successfully. * @param int $processto only process attempt modifed longer ago than this. */ public function update_overdue_attempts($timenow, $processfrom, $processto) { global $DB; $attemptstoprocess = $this->get_list_of_overdue_attempts($processfrom, $processto); $course = null; $quiz = null; $cm = null; foreach ($attemptstoprocess as $attempt) { // If we have moved on to a different quiz, fetch the new data. if (!$quiz || $attempt->quiz != $quiz->id) { $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz), '*', MUST_EXIST); $cm = get_coursemodule_from_instance('quiz', $attempt->quiz); } // If we have moved on to a different course, fetch the new data. if (!$course || $course->id != $quiz->course) { $course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST); } // Make a specialised version of the quiz settings, with the relevant overrides. $quizforuser = clone($quiz); $quizforuser->timeclose = $attempt->usertimeclose; $quizforuser->timelimit = $attempt->usertimelimit; // Trigger any transitions that are required. $attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course); $attemptobj->handle_if_time_expired($timenow, false); } $attemptstoprocess->close(); }
/** * Do the processing required. * @param int $timenow the time to consider as 'now' during the processing. * @param int $processfrom the value of $processupto the last time update_overdue_attempts was * called called and completed successfully. * @param int $processto only process attempt modifed longer ago than this. * @return array with two elements, the number of attempt considered, and how many different quizzes that was. */ public function update_overdue_attempts($timenow, $processfrom, $processto) { global $DB; $attemptstoprocess = $this->get_list_of_overdue_attempts($processfrom, $processto); $course = null; $quiz = null; $cm = null; $count = 0; $quizcount = 0; foreach ($attemptstoprocess as $attempt) { try { // If we have moved on to a different quiz, fetch the new data. if (!$quiz || $attempt->quiz != $quiz->id) { $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz), '*', MUST_EXIST); $cm = get_coursemodule_from_instance('quiz', $attempt->quiz); $quizcount += 1; } // If we have moved on to a different course, fetch the new data. if (!$course || $course->id != $quiz->course) { $course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST); } // Make a specialised version of the quiz settings, with the relevant overrides. $quizforuser = clone($quiz); $quizforuser->timeclose = $attempt->usertimeclose; $quizforuser->timelimit = $attempt->usertimelimit; // Trigger any transitions that are required. $attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course); $attemptobj->handle_if_time_expired($timenow, false); $count += 1; } catch (moodle_exception $e) { // If an error occurs while processing one attempt, don't let that kill cron. mtrace("Error while processing attempt {$attempt->id} at {$attempt->quiz} quiz:"); mtrace($e->getMessage()); mtrace($e->getTraceAsString()); } } $attemptstoprocess->close(); return array($count, $quizcount); }
private static function quiz_attempt_finish($timenow, $attemptid, $toolate, $uid, $request, $key) { global $USER; $attemptobj = ''; $USER->id = $uid; $attemptobj = quiz_attempt::create($attemptid); $postarray = array("attempt" => "{$attemptid}", "finishattempt" => "1", "timeup" => "0", "slots" => "", "sesskey" => "{$USER->sesskey}"); $attemptobj->process_finish($timenow, !$toolate, $postarray); $output = self::get_completed_response($request, $attemptid, $key); }
protected function assert_response_test($quizattemptid, $responses) { $quizattempt = quiz_attempt::create($quizattemptid); foreach ($responses['slot'] as $slot => $tests) { $slothastests = false; foreach ($tests as $test) { if ('' !== $test) { $slothastests = true; } } if (!$slothastests) { continue; } $qa = $quizattempt->get_question_attempt($slot); $stepswithsubmit = $qa->get_steps_with_submitted_response_iterator(); $step = $stepswithsubmit[$responses['submittedstepno']]; if (null === $step) { throw new coding_exception("There is no step no {$responses['submittedstepno']} " . "for slot {$slot} in quizattempt {$responses['quizattempt']}!"); } foreach (array('responsesummary', 'fraction', 'state') as $column) { if (isset($tests[$column]) && $tests[$column] != '') { switch ($column) { case 'responsesummary': $actual = $qa->get_question()->summarise_response($step->get_qt_data()); break; case 'fraction': if (count($stepswithsubmit) == $responses['submittedstepno']) { // If this is the last step then we need to look at the fraction after the question has been // finished. $actual = $qa->get_fraction(); } else { $actual = $step->get_fraction(); } break; case 'state': if (count($stepswithsubmit) == $responses['submittedstepno']) { // If this is the last step then we need to look at the state after the question has been // finished. $state = $qa->get_state(); } else { $state = $step->get_state(); } $actual = substr(get_class($state), strlen('question_state_')); } $expected = $tests[$column]; $failuremessage = "Error in quizattempt {$responses['quizattempt']} in {$column}, slot {$slot}, " . "submittedstepno {$responses['submittedstepno']}"; $this->assertEquals($expected, $actual, $failuremessage); } } } }
if (!$attemptobj->get_quiz()->showuserpicture && $attemptobj->get_userid() != $USER->id) { // If showuserpicture is true, the picture is shown elsewhere, so don't repeat it. $student = $DB->get_record('user', array('id' => $attemptobj->get_userid())); $usrepicture = new user_picture($student); $usrepicture->courseid = $attemptobj->get_courseid(); $summarydata['user'] = array('title' => $usrepicture, 'content' => new action_link(new moodle_url('/user/view.php', array('id' => $student->id, 'course' => $attemptobj->get_courseid())), fullname($student, true))); } if ($attemptobj->has_capability('mod/quiz:viewreports')) { $attemptlist = $attemptobj->links_to_other_attempts($attemptobj->review_url(null, $page, $showall)); if ($attemptlist) { $summarydata['attemptlist'] = array('title' => get_string('attempts', 'quiz'), 'content' => $attemptlist); } } // Timing information. $summarydata['startedon'] = array('title' => get_string('startedon', 'quiz'), 'content' => userdate($attempt->timestart)); $summarydata['state'] = array('title' => get_string('attemptstate', 'quiz'), 'content' => quiz_attempt::state_name($attempt->state)); if ($attempt->state == quiz_attempt::FINISHED) { $summarydata['completedon'] = array('title' => get_string('completedon', 'quiz'), 'content' => userdate($attempt->timefinish)); $summarydata['timetaken'] = array('title' => get_string('timetaken', 'quiz'), 'content' => $timetaken); } if (!empty($overtime)) { $summarydata['overdue'] = array('title' => get_string('overdue', 'quiz'), 'content' => $overtime); } // Show marks (if the user is allowed to see marks at the moment). $grade = quiz_rescale_grade($attempt->sumgrades, $quiz, false); if ($options->marks >= question_display_options::MARK_AND_MAX && quiz_has_grades($quiz)) { if ($attempt->state != quiz_attempt::FINISHED) { // Cannot display grade. } else { if (is_null($grade)) { $summarydata['grade'] = array('title' => get_string('grade', 'quiz'), 'content' => quiz_format_grade($quiz, $grade));
/** * This method changes to the desired user and attempts to review * the quiz. The message is returned to the caller. * * @param object $user The user object for the person attempting to review * @param int $attemptid The ID of the attempt to review * @return mixed {false|message indicating reason} * */ private function check_ipaddress_review($user, $attemptid) { $this->setUser($user); // Create new attempt object from ID to reload from database. $attemptobj = quiz_attempt::create($attemptid); $accessmanager = $attemptobj->get_access_manager(time()); return $accessmanager->prevent_review_ipaddress(); }
public function test_attempt_abandoned() { list($quizobj, $quba, $attempt) = $this->prepare_quiz_data(); $attemptobj = quiz_attempt::create($attempt->id); // Catch the event. $sink = $this->redirectEvents(); $timefinish = time(); $attemptobj->process_abandon($timefinish, false); $events = $sink->get_events(); $sink->close(); $this->assertCount(1, $events); $event = $events[0]; $this->assertInstanceOf('\\mod_quiz\\event\\attempt_abandoned', $event); $this->assertEquals('quiz_attempts', $event->objecttable); $this->assertEquals($quizobj->get_context(), $event->get_context()); $this->assertEquals($attempt->userid, $event->relateduserid); // Submitterid should be the user, but as we are in PHP Unit, CLI_SCRIPT is set to true which sets null in submitterid. $this->assertEquals(null, $event->other['submitterid']); $this->assertEquals('quiz_attempt_abandoned', $event->get_legacy_eventname()); $legacydata = new stdClass(); $legacydata->component = 'mod_quiz'; $legacydata->attemptid = (string) $attempt->id; $legacydata->timestamp = $timefinish; $legacydata->userid = $attempt->userid; $legacydata->cmid = $quizobj->get_cmid(); $legacydata->courseid = $quizobj->get_courseid(); $legacydata->quizid = $quizobj->get_quizid(); $legacydata->submitterid = null; // Should be the user, but PHP Unit complains... $this->assertEventLegacyData($legacydata, $event); $this->assertEventContextNotUsed($event); }
public function user_picture() { global $DB; if ($this->attemptobj->get_quiz()->showuserpicture == QUIZ_SHOWIMAGE_NONE) { return null; } $user = $DB->get_record('user', array('id' => $this->attemptobj->get_userid())); $userpicture = new user_picture($user); $userpicture->courseid = $this->attemptobj->get_courseid(); if ($this->attemptobj->get_quiz()->showuserpicture == QUIZ_SHOWIMAGE_LARGE) { $userpicture->size = true; } return $userpicture; }
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); }
/** * Creates any controls a the page should have. * * @param quiz_attempt $attemptobj */ public function summary_page_controls($attemptobj) { $output = ''; // countdown timer $output .= $this->countdown_timer(); // Finish attempt button. $options = array( 'attempt' => $attemptobj->get_attemptid(), 'finishattempt' => 1, 'timeup' => 0, 'slots' => '', 'sesskey' => sesskey(), ); $button = new single_button( new moodle_url($attemptobj->processattempt_url(), $options), get_string('submitallandfinish', 'quiz')); $button->id = 'responseform'; $button->add_action(new confirm_action(get_string('confirmclose', 'quiz'), null, get_string('submitallandfinish', 'quiz'))); $output .= $this->container($this->container($this->render($button), 'controls'), 'submitbtns mdl-align'); return $output; }
protected function process_submitted_data() { global $DB; $qubaids = optional_param('qubaids', null, PARAM_SEQUENCE); $assumedslotforevents = optional_param('slot', null, PARAM_INT); if (!$qubaids) { return; } $qubaids = clean_param_array(explode(',', $qubaids), PARAM_INT); $attempts = $this->load_attempts_by_usage_ids($qubaids); $events = array(); $transaction = $DB->start_delegated_transaction(); foreach ($qubaids as $qubaid) { $attempt = $attempts[$qubaid]; $attemptobj = new quiz_attempt($attempt, $this->quiz, $this->cm, $this->course); $attemptobj->process_submitted_actions(time()); // Add the event we will trigger later. $params = array('objectid' => $attemptobj->get_question_attempt($assumedslotforevents)->get_question()->id, 'courseid' => $attemptobj->get_courseid(), 'context' => context_module::instance($attemptobj->get_cmid()), 'other' => array('quizid' => $attemptobj->get_quizid(), 'attemptid' => $attemptobj->get_attemptid(), 'slot' => $assumedslotforevents)); $events[] = \mod_quiz\event\question_manually_graded::create($params); } $transaction->allow_commit(); // Trigger events for all the questions we manually marked. foreach ($events as $event) { $event->trigger(); } }
/** * 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')); }
/** * Generate the display of the attempt state column. * @param object $attempt the table row being output. * @return string HTML content to go inside the td. */ public function col_state($attempt) { if (!is_null($attempt->attempt)) { return quiz_attempt::state_name($attempt->state); } else { return '-'; } }
// $Id: comment.php,v 1.15 2008/12/10 09:11:30 tjhunt Exp $ /** * This page allows the teacher to enter a manual grade for a particular question. * This page is expected to only be used in a popup window. * * * @license http://www.gnu.org/copyleft/gpl.html GNU Public License * @package quiz */ require_once '../../config.php'; require_once 'locallib.php'; $attemptid = required_param('attempt', PARAM_INT); // attempt id $questionid = required_param('question', PARAM_INT); // question id $attemptobj = new quiz_attempt($attemptid); /// Can only grade finished attempts. if (!$attemptobj->is_finished()) { print_error('attemptclosed', 'quiz'); } /// Check login and permissions. require_login($attemptobj->get_courseid(), false, $attemptobj->get_cm()); $attemptobj->require_capability('mod/quiz:grade'); /// Load the questions and states. $questionids = array($questionid); $attemptobj->load_questions($questionids); $attemptobj->load_question_states($questionids); /// Log this action. add_to_log($attemptobj->get_courseid(), 'quiz', 'manualgrade', 'comment.php?attempt=' . $attemptobj->get_attemptid() . '&question=' . $questionid, $attemptobj->get_quizid(), $attemptobj->get_cmid()); /// Print the page header print_header();
/** * Send the notification message when a quiz attempt becomes overdue. * * @param quiz_attempt $attemptobj all the data about the quiz attempt. */ function quiz_send_overdue_message($attemptobj) { global $CFG, $DB; $submitter = $DB->get_record('user', array('id' => $attemptobj->get_userid()), '*', MUST_EXIST); if (!$attemptobj->has_capability('mod/quiz:emailwarnoverdue', $submitter->id, false)) { return; // Message not required. } if (!$attemptobj->has_response_to_at_least_one_graded_question()) { return; // Message not required. } // Prepare lots of useful information that admins might want to include in // the email message. $quizname = format_string($attemptobj->get_quiz_name()); $deadlines = array(); if ($attemptobj->get_quiz()->timelimit) { $deadlines[] = $attemptobj->get_attempt()->timestart + $attemptobj->get_quiz()->timelimit; } if ($attemptobj->get_quiz()->timeclose) { $deadlines[] = $attemptobj->get_quiz()->timeclose; } $duedate = min($deadlines); $graceend = $duedate + $attemptobj->get_quiz()->graceperiod; $a = new stdClass(); // Course info. $a->coursename = format_string($attemptobj->get_course()->fullname); $a->courseshortname = format_string($attemptobj->get_course()->shortname); // Quiz info. $a->quizname = $quizname; $a->quizurl = $attemptobj->view_url(); $a->quizlink = '<a href="' . $a->quizurl . '">' . $quizname . '</a>'; // Attempt info. $a->attemptduedate = userdate($duedate); $a->attemptgraceend = userdate($graceend); $a->attemptsummaryurl = $attemptobj->summary_url()->out(false); $a->attemptsummarylink = '<a href="' . $a->attemptsummaryurl . '">' . $quizname . ' review</a>'; // Student's info. $a->studentidnumber = $submitter->idnumber; $a->studentname = fullname($submitter); $a->studentusername = $submitter->username; // Prepare the message. $eventdata = new stdClass(); $eventdata->component = 'mod_quiz'; $eventdata->name = 'attempt_overdue'; $eventdata->notification = 1; $eventdata->userfrom = core_user::get_noreply_user(); $eventdata->userto = $submitter; $eventdata->subject = get_string('emailoverduesubject', 'quiz', $a); $eventdata->fullmessage = get_string('emailoverduebody', 'quiz', $a); $eventdata->fullmessageformat = FORMAT_PLAIN; $eventdata->fullmessagehtml = ''; $eventdata->smallmessage = get_string('emailoverduesmall', 'quiz', $a); $eventdata->contexturl = $a->quizurl; $eventdata->contexturlname = $a->quizname; // Send the message. return message_send($eventdata); }
/** * Creates a normal quiz attempt from a (typically paper copy) usage, so the student can view the results of a paper test * as though they had taken it on Moodle, including feedback. This also allows one to theoretically allow subsequent attempts * at the same quiz on Moodle, using options such as "each attempt buiilds on the last", building on the paper copies. * * @param question_usage_by_actvitity $usage The question_usage_by_activity object which composes the paper copy. * @param int $user_id If provided, the attempt will be owned by the user with the given ID, instead of the current user. * @param bool $finished If set, the attempt will finished and committed to the database as soon as it is created; this assumes the QUBA has already been populated with responses. * @param bool $commit If set, the attempt will be committed to the database after creation. If $finished is set, the value of $commit will be ignored, and the row will be committed regardless. * * @return array Returns the newly created attempt's raw data. (In other words, does not return a quiz_attempt object.) */ protected function build_attempt_from_usage($usage, $user_id = null, $finished = false, $commit = false, $attempt_number = null) { global $DB, $USER; //get the current time $time_now = time(); //start a new attempt $attempt = new stdClass(); $attempt->quiz = $this->quiz->id; $attempt->preview = 0; $attempt->timestart = $time_now; $attempt->timefinish = 0; $attempt->timemodified = $time_now; //associate the attempt with the usage $attempt->uniqueid = $usage->get_id(); //and set the attempt's owner, if specified if ($user_id !== null) { $attempt->userid = $user_id; } else { $attempt->userid = $USER->id; } //if no attempt number was specified, automatically detect one if ($attempt_number === null) { //determine the maximum attempt value for that user/quiz combo $max_attempt = $DB->get_records_sql('SELECT max("attempt") AS max FROM {quiz_attempts} WHERE "userid" = ? AND "quiz" = ?', array($user_id, $this->quiz->id)); $max_attempt = reset($max_attempt); //if no attempts exist, let this be the first attempt if (empty($max_attempt->max)) { $attempt_number = 1; } else { $attempt_number = $max_attempt->max + 1; } } //set the attempt number $attempt->attempt = $attempt_number; //build the attempt layout $attempt->layout = implode(',', $usage->get_slots()); //if requested, commit the attempt to the database if ($commit || $finished) { //and use it to save the usage and attempt question_engine::save_questions_usage_by_activity($usage); $attempt->id = $DB->insert_record('quiz_attempts', $attempt); } //if requested, finish the attempt immediately if ($finished) { $raw_course = $DB->get_record('course', array('id' => $this->course->id)); //wrap the attempt data in an quiz_attempt object, and ask it to finish $attempt->currentpage = 0; $attempt_object = new quiz_attempt($attempt, $this->quiz, $this->cm, $this->course, true); // $attempt_object->finish_attempt($time_now); // $attempt_object->process_submitted_actions($time_now, false); $attempt_object->process_finish($time_now, $finished); } //return the attempt object return $attempt; }
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License * @package quiz */ require_once dirname(__FILE__) . '/../../config.php'; require_once $CFG->dirroot . '/mod/quiz/locallib.php'; /// Remember the current time as the time any responses were submitted /// (so as to make sure students don't get penalized for slow processing on this page) $timenow = time(); /// Get submitted parameters. $attemptid = required_param('attempt', PARAM_INT); $nextpage = optional_param('nextpage', 0, PARAM_INT); $submittedquestionids = required_param('questionids', PARAM_SEQUENCE); $finishattempt = optional_param('finishattempt', 0, PARAM_BOOL); $timeup = optional_param('timeup', 0, PARAM_BOOL); // True if form was submitted by timer. $attemptobj = new quiz_attempt($attemptid); /// Set $nexturl now. It will be updated if a particular question was sumbitted in /// adaptive mode. if ($nextpage == -1) { $nexturl = $attemptobj->summary_url(); } else { $nexturl = $attemptobj->attempt_url(0, $nextpage); } /// We treat automatically closed attempts just like normally closed attempts if ($timeup) { $finishattempt = 1; } /// Check login. require_login($attemptobj->get_courseid(), false, $attemptobj->get_cm()); confirm_sesskey(); /// Check that this attempt belongs to this user.
public function test_attempt_started() { global $USER; list($quizobj, $quba, $attempt) = $this->prepare_quiz_data(); $attemptobj = quiz_attempt::create($attempt->id); // Catch the event. $sink = $this->redirectEvents(); quiz_fire_attempt_started_event($attempt, $quizobj); $events = $sink->get_events(); $sink->close(); // Legacy event data. $legacydata = new stdClass(); $legacydata->component = 'mod_quiz'; $legacydata->attemptid = $attempt->id; $legacydata->timestart = $attempt->timestart; $legacydata->timestamp = $attempt->timestart; $legacydata->userid = $attempt->userid; $legacydata->quizid = $quizobj->get_quizid(); $legacydata->cmid = $quizobj->get_cmid(); $legacydata->courseid = $quizobj->get_courseid(); // Validate the event. $this->assertCount(1, $events); $event = $events[0]; $this->assertInstanceOf('\\mod_quiz\\event\\attempt_started', $event); $this->assertEquals('quiz_attempts', $event->objecttable); $this->assertEquals($attempt->id, $event->objectid); $this->assertEquals($attempt->userid, $event->relateduserid); $this->assertEquals($quizobj->get_context(), $event->get_context()); $this->assertEquals('quiz_attempt_started', $event->get_legacy_eventname()); $this->assertEventLegacyData($legacydata, $event); }
/** * Deals with data coming in from the grading pop up * * @param object $data the form data * @param $params * @return mixed true on success or an error. */ public function process_data($data, $params) { global $DB; // Get all attempts on all questions that were unmarked. // Slight chance that someone else will have marked the questions since this user opened // the pop up, which could lead to these grades being ignored, or the other person's // being overwritten. Not much we can do about that. $questionattempts = $this->get_question_attempts($params); // We will have duplicates as there could be multiple questions per attempt. $processedattempts = array(); // This will get all of the attempts to pull the relevant data from all the POST stuff // and process it. The quiz adds lots of prefix stuff, so we won't have collisions. foreach ($questionattempts as $attempt) { $id = $attempt->quizattemptid; if (isset($processedattempts[$id])) { continue; } $processedattempts[$id] = quiz_attempt::create($id); $transaction = $DB->start_delegated_transaction(); $processedattempts[$id]->process_all_actions(time()); $transaction->allow_commit(); } return true; }
protected function process_submitted_data() { global $DB; $qubaids = optional_param('qubaids', null, PARAM_SEQUENCE); if (!$qubaids) { return; } $qubaids = clean_param_array(explode(',', $qubaids), PARAM_INT); $attempts = $this->load_attempts_by_usage_ids($qubaids); $transaction = $DB->start_delegated_transaction(); foreach ($qubaids as $qubaid) { $attempt = $attempts[$qubaid]; $attemptobj = new quiz_attempt($attempt, $this->quiz, $this->cm, $this->course); $attemptobj->process_submitted_actions(time()); } $transaction->allow_commit(); }
<?php // $Id: summary.php,v 1.8 2009/03/11 07:10:57 tjhunt Exp $ /** * This page prints a summary of a quiz attempt before it is submitted. * * @author Tim Hunt others. * @license http://www.gnu.org/copyleft/gpl.html GNU Public License * @package quiz */ require_once dirname(__FILE__) . '/../../config.php'; require_once $CFG->dirroot . '/mod/quiz/locallib.php'; $attemptid = required_param('attempt', PARAM_INT); // The attempt to summarise. $attemptobj = new quiz_attempt($attemptid); /// Check login. require_login($attemptobj->get_courseid(), false, $attemptobj->get_cm()); /// If this is not our own attempt, display an error. if ($attemptobj->get_userid() != $USER->id) { print_error('notyourattempt', 'quiz', $attemptobj->view_url()); } /// If the attempt is alreadyuj closed, redirect them to the review page. if ($attemptobj->is_finished()) { redirect($attemptobj->review_url()); } /// Check access. $accessmanager = $attemptobj->get_access_manager(time()); $messages = $accessmanager->prevent_access(); if (!$attemptobj->is_preview_user() && $messages) { print_error('attempterror', 'quiz', $attemptobj->view_url(), $accessmanager->print_messages($messages, true)); }
/** * 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]); }
/** * Stops the attempt and saves the grade. */ public function end_quiz_attmept($attempt) { $timenow = time(); $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_finish($timenow, true); }
*/ require_once dirname(__FILE__) . '/../../config.php'; require_once $CFG->dirroot . '/mod/quiz/locallib.php'; require_once $CFG->dirroot . '/mod/quiz/report/reportlib.php'; $attemptid = required_param('attempt', PARAM_INT); $page = optional_param('page', 0, PARAM_INT); $showall = optional_param('showall', 0, PARAM_BOOL); $url = new moodle_url('/mod/quiz/review.php', array('attempt' => $attemptid)); if ($page !== 0) { $url->param('page', $page); } if ($showall !== 0) { $url->param('showall', $showall); } $PAGE->set_url($url); $attemptobj = quiz_attempt::create($attemptid); /// Check login. require_login($attemptobj->get_course(), false, $attemptobj->get_cm()); $attemptobj->check_review_capability(); /// Create an object to manage all the other (non-roles) access rules. $accessmanager = $attemptobj->get_access_manager(time()); $options = $attemptobj->get_review_options(); // Check permissions. if ($attemptobj->is_own_attempt()) { if (!$attemptobj->is_finished()) { redirect($attemptobj->attempt_url(0, $page)); } else { if (!$options->responses) { $accessmanager->back_to_view_page($attemptobj->is_preview_user(), $accessmanager->cannot_review_message($options)); } }
public function user_picture() { global $DB; if (!$this->attemptobj->get_quiz()->showuserpicture) { return null; } $user = $DB->get_record('user', array('id' => $this->attemptobj->get_userid())); $userpicture = new user_picture($user); $userpicture->courseid = $this->attemptobj->get_courseid(); return $userpicture; }
/** * Return access information for a given attempt in a quiz. * * @param int $quizid quiz instance id * @param int $attemptid attempt id, 0 for the user last attempt if exists * @return array of warnings and the access information * @since Moodle 3.1 * @throws moodle_quiz_exception */ public static function get_attempt_access_information($quizid, $attemptid = 0) { global $DB, $USER; $warnings = array(); $params = array('quizid' => $quizid, 'attemptid' => $attemptid); $params = self::validate_parameters(self::get_attempt_access_information_parameters(), $params); list($quiz, $course, $cm, $context) = self::validate_quiz($params['quizid']); $attempttocheck = 0; if (!empty($params['attemptid'])) { $attemptobj = quiz_attempt::create($params['attemptid']); if ($attemptobj->get_userid() != $USER->id) { throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'notyourattempt'); } $attempttocheck = $attemptobj->get_attempt(); } // Access manager now. $quizobj = quiz::create($cm->instance, $USER->id); $ignoretimelimits = has_capability('mod/quiz:ignoretimelimits', $context, null, false); $timenow = time(); $accessmanager = new quiz_access_manager($quizobj, $timenow, $ignoretimelimits); $attempts = quiz_get_user_attempts($quiz->id, $USER->id, 'finished', true); $lastfinishedattempt = end($attempts); if ($unfinishedattempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) { $attempts[] = $unfinishedattempt; // Check if the attempt is now overdue. In that case the state will change. $quizobj->create_attempt_object($unfinishedattempt)->handle_if_time_expired(time(), false); if ($unfinishedattempt->state != quiz_attempt::IN_PROGRESS and $unfinishedattempt->state != quiz_attempt::OVERDUE) { $lastfinishedattempt = $unfinishedattempt; } } $numattempts = count($attempts); if (!$attempttocheck) { $attempttocheck = $unfinishedattempt ? $unfinishedattempt : $lastfinishedattempt; } $result = array(); $result['isfinished'] = $accessmanager->is_finished($numattempts, $lastfinishedattempt); $result['preventnewattemptreasons'] = $accessmanager->prevent_new_attempt($numattempts, $lastfinishedattempt); if ($attempttocheck) { $endtime = $accessmanager->get_end_time($attempttocheck); $result['endtime'] = $endtime === false ? 0 : $endtime; $attemptid = $unfinishedattempt ? $unfinishedattempt->id : null; $result['ispreflightcheckrequired'] = $accessmanager->is_preflight_check_required($attemptid); } $result['warnings'] = $warnings; return $result; }
/** * Called via pluginfile.php -> question_pluginfile to serve files belonging to * a question in a question_attempt when that attempt is a quiz attempt. * * @package mod_quiz * @category files * @param stdClass $course course settings object * @param stdClass $context context object * @param string $component the name of the component we are serving files for. * @param string $filearea the name of the file area. * @param int $qubaid the attempt usage id. * @param int $slot the id of a question in this quiz attempt. * @param array $args the remaining bits of the file path. * @param bool $forcedownload whether the user must be forced to download the file. * @param array $options additional options affecting the file serving * @return bool false if file not found, does not return if found - justsend the file */ function quiz_question_pluginfile($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload, array $options=array()) { global $CFG; require_once($CFG->dirroot . '/mod/quiz/locallib.php'); $attemptobj = quiz_attempt::create_from_usage_id($qubaid); require_login($attemptobj->get_course(), false, $attemptobj->get_cm()); if ($attemptobj->is_own_attempt() && !$attemptobj->is_finished()) { // In the middle of an attempt. if (!$attemptobj->is_preview_user()) { $attemptobj->require_capability('mod/quiz:attempt'); } $isreviewing = false; } else { // Reviewing an attempt. $attemptobj->check_review_capability(); $isreviewing = true; } if (!$attemptobj->check_file_access($slot, $isreviewing, $context->id, $component, $filearea, $args, $forcedownload)) { send_file_not_found(); } $fs = get_file_storage(); $relativepath = implode('/', $args); $fullpath = "/$context->id/$component/$filearea/$relativepath"; if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { send_file_not_found(); } send_stored_file($file, 0, 0, $forcedownload, $options); }
/** * Generate a brief textual desciption of the current state of an attempt. * @param quiz_attempt $attemptobj the attempt * @param int $timenow the time to use as 'now'. * @return string the appropriate lang string to describe the state. */ public function attempt_state($attemptobj) { switch ($attemptobj->get_state()) { case quiz_attempt::IN_PROGRESS: return get_string('stateinprogress', 'quiz'); case quiz_attempt::OVERDUE: return get_string('stateoverdue', 'quiz') . html_writer::tag('span', get_string('stateoverduedetails', 'quiz', userdate($attemptobj->get_due_date())), array('class' => 'statedetails')); case quiz_attempt::FINISHED: return get_string('statefinished', 'quiz') . html_writer::tag('span', get_string('statefinisheddetails', 'quiz', userdate($attemptobj->get_submitted_date())), array('class' => 'statedetails')); case quiz_attempt::ABANDONED: return get_string('stateabandoned', 'quiz'); } }
$summarydata['attemptlist'] = array( 'title' => get_string('attempts', 'quiz'), 'content' => $attemptlist, ); } } // Timing information. $summarydata['startedon'] = array( 'title' => get_string('startedon', 'quiz'), 'content' => userdate($attempt->timestart), ); $summarydata['state'] = array( 'title' => get_string('attemptstate', 'quiz'), 'content' => quiz_attempt::state_name($attempt->state), ); if ($attempt->state == quiz_attempt::FINISHED) { $summarydata['completedon'] = array( 'title' => get_string('completedon', 'quiz'), 'content' => userdate($attempt->timefinish), ); $summarydata['timetaken'] = array( 'title' => get_string('timetaken', 'quiz'), 'content' => $timetaken, ); } if (!empty($overtime)) { $summarydata['overdue'] = array(