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());
 }
예제 #2
0
파일: cronlib.php 프로젝트: nicusX/moodle
    /**
     * 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();
    }
예제 #3
0
파일: cronlib.php 프로젝트: JP-Git/moodle
    /**
     * 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);
    }
예제 #4
0
 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);
             }
         }
     }
 }
예제 #6
0
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();
 }
예제 #8
0
 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);
 }
예제 #9
0
 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;
 }
예제 #10
0
 public function test_quiz_get_user_attempts()
 {
     global $DB;
     $this->resetAfterTest();
     $dg = $this->getDataGenerator();
     $quizgen = $dg->get_plugin_generator('mod_quiz');
     $course = $dg->create_course();
     $u1 = $dg->create_user();
     $u2 = $dg->create_user();
     $u3 = $dg->create_user();
     $u4 = $dg->create_user();
     $role = $DB->get_record('role', ['shortname' => 'student']);
     $dg->enrol_user($u1->id, $course->id, $role->id);
     $dg->enrol_user($u2->id, $course->id, $role->id);
     $dg->enrol_user($u3->id, $course->id, $role->id);
     $dg->enrol_user($u4->id, $course->id, $role->id);
     $quiz1 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]);
     $quiz2 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]);
     // Questions.
     $questgen = $dg->get_plugin_generator('core_question');
     $quizcat = $questgen->create_question_category();
     $question = $questgen->create_question('numerical', null, ['category' => $quizcat->id]);
     quiz_add_quiz_question($question->id, $quiz1);
     quiz_add_quiz_question($question->id, $quiz2);
     $quizobj1a = quiz::create($quiz1->id, $u1->id);
     $quizobj1b = quiz::create($quiz1->id, $u2->id);
     $quizobj1c = quiz::create($quiz1->id, $u3->id);
     $quizobj1d = quiz::create($quiz1->id, $u4->id);
     $quizobj2a = quiz::create($quiz2->id, $u1->id);
     // Set attempts.
     $quba1a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1a->get_context());
     $quba1a->set_preferred_behaviour($quizobj1a->get_quiz()->preferredbehaviour);
     $quba1b = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1b->get_context());
     $quba1b->set_preferred_behaviour($quizobj1b->get_quiz()->preferredbehaviour);
     $quba1c = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1c->get_context());
     $quba1c->set_preferred_behaviour($quizobj1c->get_quiz()->preferredbehaviour);
     $quba1d = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1d->get_context());
     $quba1d->set_preferred_behaviour($quizobj1d->get_quiz()->preferredbehaviour);
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $timenow = time();
     // User 1 passes quiz 1.
     $attempt = quiz_create_attempt($quizobj1a, 1, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj1a, $quba1a, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1a, $quba1a, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_submitted_actions($timenow, false, [1 => ['answer' => '3.14']]);
     $attemptobj->process_finish($timenow, false);
     // User 2 goes overdue in quiz 1.
     $attempt = quiz_create_attempt($quizobj1b, 1, false, $timenow, false, $u2->id);
     quiz_start_new_attempt($quizobj1b, $quba1b, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1b, $quba1b, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_going_overdue($timenow, true);
     // User 3 does not finish quiz 1.
     $attempt = quiz_create_attempt($quizobj1c, 1, false, $timenow, false, $u3->id);
     quiz_start_new_attempt($quizobj1c, $quba1c, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1c, $quba1c, $attempt);
     // User 4 abandons the quiz 1.
     $attempt = quiz_create_attempt($quizobj1d, 1, false, $timenow, false, $u4->id);
     quiz_start_new_attempt($quizobj1d, $quba1d, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1d, $quba1d, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_abandon($timenow, true);
     // User 1 attempts the quiz three times (abandon, finish, in progress).
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $attempt = quiz_create_attempt($quizobj2a, 1, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_abandon($timenow, true);
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $attempt = quiz_create_attempt($quizobj2a, 2, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 2, $timenow);
     quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_finish($timenow, false);
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $attempt = quiz_create_attempt($quizobj2a, 3, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 3, $timenow);
     quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
     // Check for user 1.
     $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'finished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'unfinished');
     $this->assertCount(0, $attempts);
     // Check for user 2.
     $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state);
     $this->assertEquals($u2->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'finished');
     $this->assertCount(0, $attempts);
     $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'unfinished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state);
     $this->assertEquals($u2->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     // Check for user 3.
     $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u3->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'finished');
     $this->assertCount(0, $attempts);
     $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'unfinished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u3->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     // Check for user 4.
     $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u4->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'finished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u4->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'unfinished');
     $this->assertCount(0, $attempts);
     // Multiple attempts for user 1 in quiz 2.
     $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'all');
     $this->assertCount(3, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'finished');
     $this->assertCount(2, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'unfinished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     // Multiple quiz attempts fetched at once.
     $attempts = quiz_get_user_attempts([$quiz1->id, $quiz2->id], $u1->id, 'all');
     $this->assertCount(4, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
 }
예제 #11
0
    /**
     * 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;
    }
예제 #12
0
 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();
     }
 }
예제 #13
0
 /**
  * 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'));
 }
예제 #14
0
 /**
  * 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  '-';
     }
 }
예제 #15
0
// $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();
예제 #16
0
/**
 * 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;
 }
예제 #18
0
 * @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.
예제 #19
0
 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;
 }
예제 #21
0
 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();
 }
예제 #22
0
<?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));
}
예제 #23
0
 /**
  * Test get_attempt_access_information
  */
 public function test_get_attempt_access_information()
 {
     global $DB;
     // Create a new quiz with attempts.
     $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
     $data = array('course' => $this->course->id, 'sumgrades' => 2);
     $quiz = $quizgenerator->create_instance($data);
     // Create some questions.
     $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $questiongenerator->create_question_category();
     $question = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     $question = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     // Add new question types in the category (for the random one).
     $question = $questiongenerator->create_question('truefalse', null, array('category' => $cat->id));
     $question = $questiongenerator->create_question('essay', null, array('category' => $cat->id));
     $question = $questiongenerator->create_question('random', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     $quizobj = quiz::create($quiz->id, $this->student->id);
     // Set grade to pass.
     $item = grade_item::fetch(array('courseid' => $this->course->id, 'itemtype' => 'mod', 'itemmodule' => 'quiz', 'iteminstance' => $quiz->id, 'outcomeid' => null));
     $item->gradepass = 80;
     $item->update();
     $this->setUser($this->student);
     // Default restrictions (none).
     $result = mod_quiz_external::get_attempt_access_information($quiz->id);
     $result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_access_information_returns(), $result);
     $expected = array('isfinished' => false, 'preventnewattemptreasons' => [], 'warnings' => []);
     $this->assertEquals($expected, $result);
     // Limited attempts.
     $quiz->attempts = 1;
     $DB->update_record('quiz', $quiz);
     // Now, do one attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $this->student->id);
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     // Process some responses from the student.
     $attemptobj = quiz_attempt::create($attempt->id);
     $tosubmit = array(1 => array('answer' => '3.14'));
     $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
     // Finish the attempt.
     $attemptobj = quiz_attempt::create($attempt->id);
     $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
     $attemptobj->process_finish($timenow, false);
     // Can we start a new attempt? We shall not!
     $result = mod_quiz_external::get_attempt_access_information($quiz->id, $attempt->id);
     $result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_access_information_returns(), $result);
     // Now new attemps allowed.
     $this->assertCount(1, $result['preventnewattemptreasons']);
     $this->assertFalse($result['ispreflightcheckrequired']);
     $this->assertEquals(get_string('nomoreattempts', 'quiz'), $result['preventnewattemptreasons'][0]);
 }
 /**
  * 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);
 }
예제 #25
0
 */
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));
        }
    }
예제 #26
0
    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;
    }
예제 #27
0
 /**
  * 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;
 }
예제 #28
0
/**
 * 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);
}
예제 #29
0
파일: renderer.php 프로젝트: JP-Git/moodle
    /**
     * 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');
        }
    }
예제 #30
0
        $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(