2009-11-04 11:58:30 +00:00
|
|
|
<?php
|
2011-02-09 16:56:44 +00:00
|
|
|
// This file is part of Moodle - http://moodle.org/
|
|
|
|
//
|
|
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2005-05-06 06:24:04 +00:00
|
|
|
/**
|
2007-11-07 15:26:37 +00:00
|
|
|
* This page prints a review of a particular quiz attempt
|
|
|
|
*
|
2011-02-09 16:56:44 +00:00
|
|
|
* It is used either by the student whose attempts this is, after the attempt,
|
|
|
|
* or by a teacher reviewing another's attempt during or afterwards.
|
|
|
|
*
|
MDL-3030 quiz overdue handling: trigger automatic state transitions.
Here, we catch all the places where a student might be accessing their
own attempts, and make sure any automatic state transitions that
should happen, do happen, before the student sees the attempt.
The places where we need to check this are view.php, startattempt.php
and processattempt.php.
We do not really need to check attempt.php or summary.php, because if
the student is on one of those pages, the JavaScript timer will
auto-submit when time expires, taking them to processattempt.php,
which will do the acutal work.
We intentionally do not trigger state transition when a teacher is
looking at a student's quiz attemp. We will trigger state transitions
on cron, but that is still to do.
Also, the body of the process_... methods still needs to be written.
2012-04-18 19:18:55 +01:00
|
|
|
* @package mod_quiz
|
|
|
|
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2007-11-07 15:26:37 +00:00
|
|
|
*/
|
2003-07-24 05:18:00 +00:00
|
|
|
|
2011-02-21 16:13:25 +00:00
|
|
|
|
2011-02-09 16:56:44 +00:00
|
|
|
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);
|
2012-07-27 11:42:03 +01:00
|
|
|
$page = optional_param('page', 0, PARAM_INT);
|
|
|
|
$showall = optional_param('showall', 0, PARAM_BOOL);
|
2011-02-09 16:56:44 +00:00
|
|
|
|
|
|
|
$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);
|
2012-07-27 11:42:03 +01:00
|
|
|
$page = $attemptobj->force_page_number_into_range($page);
|
2011-02-09 16:56:44 +00:00
|
|
|
|
|
|
|
// 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());
|
2012-07-12 18:39:01 +01:00
|
|
|
$accessmanager->setup_attempt_page($PAGE);
|
|
|
|
|
2011-02-09 16:56:44 +00:00
|
|
|
$options = $attemptobj->get_display_options(true);
|
|
|
|
|
2011-02-18 16:32:49 +00:00
|
|
|
// Check permissions.
|
|
|
|
if ($attemptobj->is_own_attempt()) {
|
2011-02-09 16:56:44 +00:00
|
|
|
if (!$attemptobj->is_finished()) {
|
2011-08-17 14:40:05 +01:00
|
|
|
redirect($attemptobj->attempt_url(null, $page));
|
2011-10-05 20:58:38 +01:00
|
|
|
|
2011-02-18 16:32:49 +00:00
|
|
|
} else if (!$options->attempt) {
|
2011-10-05 20:58:38 +01:00
|
|
|
$accessmanager->back_to_view_page($PAGE->get_renderer('mod_quiz'),
|
|
|
|
$attemptobj->cannot_review_message());
|
2009-11-04 11:58:30 +00:00
|
|
|
}
|
2011-02-18 16:32:49 +00:00
|
|
|
|
|
|
|
} else if (!$attemptobj->is_review_allowed()) {
|
|
|
|
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'noreviewattempt');
|
2011-02-09 16:56:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Load the questions and states needed by this page.
|
|
|
|
if ($showall) {
|
|
|
|
$questionids = $attemptobj->get_slots();
|
|
|
|
} else {
|
|
|
|
$questionids = $attemptobj->get_slots($page);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save the flag states, if they are being changed.
|
2011-05-03 14:18:04 +01:00
|
|
|
if ($options->flags == question_display_options::EDITABLE && optional_param('savingflags', false,
|
|
|
|
PARAM_BOOL)) {
|
2011-02-09 16:56:44 +00:00
|
|
|
require_sesskey();
|
|
|
|
$attemptobj->save_question_flags();
|
2011-08-25 10:50:00 +01:00
|
|
|
redirect($attemptobj->review_url(null, $page, $showall));
|
2011-02-09 16:56:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Log this review.
|
|
|
|
add_to_log($attemptobj->get_courseid(), 'quiz', 'review', 'review.php?attempt=' .
|
|
|
|
$attemptobj->get_attemptid(), $attemptobj->get_quizid(), $attemptobj->get_cmid());
|
|
|
|
|
2012-05-04 12:40:21 +01:00
|
|
|
// Work out appropriate title and whether blocks should be shown.
|
2011-02-09 16:56:44 +00:00
|
|
|
if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) {
|
|
|
|
$strreviewtitle = get_string('reviewofpreview', 'quiz');
|
|
|
|
navigation_node::override_active_url($attemptobj->start_attempt_url());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
$strreviewtitle = get_string('reviewofattempt', 'quiz', $attemptobj->get_attempt_number());
|
|
|
|
if (empty($attemptobj->get_quiz()->showblocks) && !$attemptobj->is_preview_user()) {
|
|
|
|
$PAGE->blocks->show_only_fake_blocks();
|
2008-09-03 08:32:29 +00:00
|
|
|
}
|
2011-02-09 16:56:44 +00:00
|
|
|
}
|
|
|
|
|
2012-05-04 12:40:21 +01:00
|
|
|
// Set up the page header.
|
2011-02-09 16:56:44 +00:00
|
|
|
$headtags = $attemptobj->get_html_head_contributions($page, $showall);
|
2011-10-05 20:58:38 +01:00
|
|
|
$PAGE->set_title(format_string($attemptobj->get_quiz_name()));
|
|
|
|
$PAGE->set_heading($attemptobj->get_course()->fullname);
|
2011-02-09 16:56:44 +00:00
|
|
|
|
2012-05-04 12:40:21 +01:00
|
|
|
// Summary table start. ============================================================================
|
2011-02-09 16:56:44 +00:00
|
|
|
|
|
|
|
// Work out some time-related things.
|
|
|
|
$attempt = $attemptobj->get_attempt();
|
|
|
|
$quiz = $attemptobj->get_quiz();
|
|
|
|
$overtime = 0;
|
|
|
|
|
2011-11-16 16:37:14 +00:00
|
|
|
if ($attempt->state == quiz_attempt::FINISHED) {
|
2011-02-09 16:56:44 +00:00
|
|
|
if ($timetaken = ($attempt->timefinish - $attempt->timestart)) {
|
2011-04-15 18:26:35 +01:00
|
|
|
if ($quiz->timelimit && $timetaken > ($quiz->timelimit + 60)) {
|
2011-02-09 16:56:44 +00:00
|
|
|
$overtime = $timetaken - $quiz->timelimit;
|
|
|
|
$overtime = format_time($overtime);
|
2010-05-21 03:15:48 +00:00
|
|
|
}
|
2011-02-09 16:56:44 +00:00
|
|
|
$timetaken = format_time($timetaken);
|
2005-05-06 06:24:04 +00:00
|
|
|
} else {
|
2011-02-09 16:56:44 +00:00
|
|
|
$timetaken = "-";
|
2007-07-06 16:37:06 +00:00
|
|
|
}
|
2011-02-09 16:56:44 +00:00
|
|
|
} else {
|
|
|
|
$timetaken = get_string('unfinished', 'quiz');
|
|
|
|
}
|
|
|
|
|
2011-06-17 15:27:41 +01:00
|
|
|
// Prepare summary informat about the whole attempt.
|
2011-04-15 18:26:35 +01:00
|
|
|
$summarydata = array();
|
2011-02-09 16:56:44 +00:00
|
|
|
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()));
|
2011-04-15 18:26:35 +01:00
|
|
|
$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)),
|
|
|
|
);
|
2011-02-09 16:56:44 +00:00
|
|
|
}
|
2011-11-16 16:37:14 +00:00
|
|
|
|
2011-02-09 16:56:44 +00:00
|
|
|
if ($attemptobj->has_capability('mod/quiz:viewreports')) {
|
2011-08-25 10:50:00 +01:00
|
|
|
$attemptlist = $attemptobj->links_to_other_attempts($attemptobj->review_url(null, $page,
|
2011-05-03 14:18:04 +01:00
|
|
|
$showall));
|
2011-02-09 16:56:44 +00:00
|
|
|
if ($attemptlist) {
|
2011-04-15 18:26:35 +01:00
|
|
|
$summarydata['attemptlist'] = array(
|
|
|
|
'title' => get_string('attempts', 'quiz'),
|
|
|
|
'content' => $attemptlist,
|
|
|
|
);
|
2003-07-24 05:18:00 +00:00
|
|
|
}
|
2011-02-09 16:56:44 +00:00
|
|
|
}
|
|
|
|
|
2011-04-15 18:26:35 +01:00
|
|
|
// Timing information.
|
|
|
|
$summarydata['startedon'] = array(
|
|
|
|
'title' => get_string('startedon', 'quiz'),
|
|
|
|
'content' => userdate($attempt->timestart),
|
|
|
|
);
|
2011-02-09 16:56:44 +00:00
|
|
|
|
2011-11-16 16:37:14 +00:00
|
|
|
$summarydata['state'] = array(
|
|
|
|
'title' => get_string('attemptstate', 'quiz'),
|
|
|
|
'content' => quiz_attempt::state_name($attempt->state),
|
|
|
|
);
|
|
|
|
|
|
|
|
if ($attempt->state == quiz_attempt::FINISHED) {
|
2011-04-15 18:26:35 +01:00
|
|
|
$summarydata['completedon'] = array(
|
|
|
|
'title' => get_string('completedon', 'quiz'),
|
|
|
|
'content' => userdate($attempt->timefinish),
|
|
|
|
);
|
|
|
|
$summarydata['timetaken'] = array(
|
|
|
|
'title' => get_string('timetaken', 'quiz'),
|
2011-08-04 14:11:32 +01:00
|
|
|
'content' => $timetaken,
|
2011-04-15 18:26:35 +01:00
|
|
|
);
|
|
|
|
}
|
2011-02-09 16:56:44 +00:00
|
|
|
|
2011-04-15 18:26:35 +01:00
|
|
|
if (!empty($overtime)) {
|
|
|
|
$summarydata['overdue'] = array(
|
|
|
|
'title' => get_string('overdue', 'quiz'),
|
2011-10-19 09:09:40 +01:00
|
|
|
'content' => $overtime,
|
2011-04-15 18:26:35 +01:00
|
|
|
);
|
|
|
|
}
|
2008-05-15 15:32:43 +00:00
|
|
|
|
2011-04-15 18:26:35 +01:00
|
|
|
// 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)) {
|
2008-07-08 17:47:57 +00:00
|
|
|
|
2012-04-24 15:01:12 +01:00
|
|
|
if ($attempt->state != quiz_attempt::FINISHED) {
|
2013-10-25 20:08:17 +01:00
|
|
|
// Cannot display grade.
|
2011-04-15 18:26:35 +01:00
|
|
|
|
|
|
|
} else if (is_null($grade)) {
|
|
|
|
$summarydata['grade'] = array(
|
|
|
|
'title' => get_string('grade', 'quiz'),
|
|
|
|
'content' => quiz_format_grade($quiz, $grade),
|
|
|
|
);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Show raw marks only if they are different from the grade (like on the view page).
|
|
|
|
if ($quiz->grade != $quiz->sumgrades) {
|
2011-02-25 12:24:55 +00:00
|
|
|
$a = new stdClass();
|
2011-04-15 18:26:35 +01:00
|
|
|
$a->grade = quiz_format_grade($quiz, $attempt->sumgrades);
|
|
|
|
$a->maxgrade = quiz_format_grade($quiz, $quiz->sumgrades);
|
|
|
|
$summarydata['marks'] = array(
|
|
|
|
'title' => get_string('marks', 'quiz'),
|
|
|
|
'content' => get_string('outofshort', 'quiz', $a),
|
|
|
|
);
|
2011-02-09 16:56:44 +00:00
|
|
|
}
|
|
|
|
|
2011-04-15 18:26:35 +01:00
|
|
|
// Now the scaled grade.
|
|
|
|
$a = new stdClass();
|
|
|
|
$a->grade = html_writer::tag('b', quiz_format_grade($quiz, $grade));
|
|
|
|
$a->maxgrade = quiz_format_grade($quiz, $quiz->grade);
|
|
|
|
if ($quiz->grade != 100) {
|
|
|
|
$a->percent = html_writer::tag('b', format_float(
|
|
|
|
$attempt->sumgrades * 100 / $quiz->sumgrades, 0));
|
|
|
|
$formattedgrade = get_string('outofpercent', 'quiz', $a);
|
|
|
|
} else {
|
|
|
|
$formattedgrade = get_string('outof', 'quiz', $a);
|
|
|
|
}
|
|
|
|
$summarydata['grade'] = array(
|
|
|
|
'title' => get_string('grade', 'quiz'),
|
|
|
|
'content' => $formattedgrade,
|
|
|
|
);
|
2011-02-25 12:24:55 +00:00
|
|
|
}
|
2011-02-09 16:56:44 +00:00
|
|
|
}
|
|
|
|
|
2012-08-16 14:18:58 +01:00
|
|
|
// Any additional summary data from the behaviour.
|
|
|
|
$summarydata = array_merge($summarydata, $attemptobj->get_additional_summary_data($options));
|
|
|
|
|
2011-04-15 18:26:35 +01:00
|
|
|
// Feedback if there is any, and the user is allowed to see it now.
|
|
|
|
$feedback = $attemptobj->get_overall_feedback($grade);
|
|
|
|
if ($options->overallfeedback && $feedback) {
|
|
|
|
$summarydata['feedback'] = array(
|
|
|
|
'title' => get_string('feedback', 'quiz'),
|
|
|
|
'content' => $feedback,
|
|
|
|
);
|
2011-02-09 16:56:44 +00:00
|
|
|
}
|
|
|
|
|
2012-05-04 12:40:21 +01:00
|
|
|
// Summary table end. ==============================================================================
|
2011-02-09 16:56:44 +00:00
|
|
|
|
|
|
|
if ($showall) {
|
2011-04-15 18:26:35 +01:00
|
|
|
$slots = $attemptobj->get_slots();
|
2011-02-09 16:56:44 +00:00
|
|
|
$lastpage = true;
|
|
|
|
} else {
|
2011-04-15 18:26:35 +01:00
|
|
|
$slots = $attemptobj->get_slots($page);
|
2011-02-09 16:56:44 +00:00
|
|
|
$lastpage = $attemptobj->is_last_page($page);
|
|
|
|
}
|
|
|
|
|
2011-04-15 18:26:35 +01:00
|
|
|
$output = $PAGE->get_renderer('mod_quiz');
|
2011-02-09 16:56:44 +00:00
|
|
|
|
2011-04-15 18:26:35 +01:00
|
|
|
// Arrange for the navigation to be displayed.
|
|
|
|
$navbc = $attemptobj->get_navigation_panel($output, 'quiz_review_nav_panel', $page, $showall);
|
2012-04-18 08:55:12 +01:00
|
|
|
$regions = $PAGE->blocks->get_regions();
|
|
|
|
$PAGE->blocks->add_fake_block($navbc, reset($regions));
|
2011-04-15 18:26:35 +01:00
|
|
|
|
|
|
|
echo $output->review_page($attemptobj, $slots, $page, $showall, $lastpage, $options, $summarydata);
|