Commit | Line | Data |
---|---|---|
83192608 | 1 | <?php |
ee1fb969 | 2 | /** |
f63a4ff2 | 3 | * This page prints a review of a particular quiz attempt |
4 | * | |
4fc3d7e5 | 5 | * @author Martin Dougiamas and many others. |
f63a4ff2 | 6 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License |
7 | * @package quiz | |
8 | */ | |
29d5d0b4 | 9 | |
4fc3d7e5 | 10 | require_once(dirname(__FILE__) . '/../../config.php'); |
c52c62d1 | 11 | require_once($CFG->dirroot . '/mod/quiz/locallib.php'); |
bbf4f440 | 12 | require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php'); |
29d5d0b4 | 13 | |
4fc3d7e5 | 14 | $attemptid = required_param('attempt', PARAM_INT); |
15 | $page = optional_param('page', 0, PARAM_INT); | |
ee1fb969 | 16 | $showall = optional_param('showall', 0, PARAM_BOOL); |
29d5d0b4 | 17 | |
a6855934 | 18 | $url = new moodle_url('/mod/quiz/review.php', array('attempt'=>$attemptid)); |
55f599f0 | 19 | if ($page !== 0) { |
20 | $url->param('page', $page); | |
21 | } | |
22 | if ($showall !== 0) { | |
23 | $url->param('showall', $showall); | |
24 | } | |
25 | $PAGE->set_url($url); | |
26 | ||
990650f9 | 27 | $attemptobj = quiz_attempt::create($attemptid); |
4fc3d7e5 | 28 | |
29 | /// Check login. | |
56ed242b | 30 | require_login($attemptobj->get_course(), false, $attemptobj->get_cm()); |
96c7d771 | 31 | $attemptobj->check_review_capability(); |
77ed3ba5 | 32 | |
c52c62d1 | 33 | /// Create an object to manage all the other (non-roles) access rules. |
4fc3d7e5 | 34 | $accessmanager = $attemptobj->get_access_manager(time()); |
35 | $options = $attemptobj->get_review_options(); | |
c52c62d1 | 36 | |
c52c62d1 | 37 | /// Permissions checks for normal users who do not have quiz:viewreports capability. |
4fc3d7e5 | 38 | if (!$attemptobj->has_capability('mod/quiz:viewreports')) { |
82fd2e8b | 39 | /// Can't review other users' attempts. |
40 | if (!$attemptobj->is_own_attempt()) { | |
41 | quiz_error($attemptobj->get_quiz(), 'notyourattempt'); | |
42 | } | |
c52c62d1 | 43 | /// Can't review during the attempt - send them back to the attempt page. |
4fc3d7e5 | 44 | if (!$attemptobj->is_finished()) { |
45 | redirect($attemptobj->attempt_url(0, $page)); | |
29d5d0b4 | 46 | } |
c52c62d1 | 47 | /// Can't review unless Students may review -> Responses option is turned on. |
a4faed69 | 48 | if (!$options->responses) { |
4fc3d7e5 | 49 | $accessmanager->back_to_view_page($attemptobj->is_preview_user(), |
c52c62d1 | 50 | $accessmanager->cannot_review_message($options)); |
34283aa8 | 51 | } |
29d5d0b4 | 52 | } |
53 | ||
f62040ed | 54 | /// Load the questions and states needed by this page. |
c52c62d1 | 55 | if ($showall) { |
4fc3d7e5 | 56 | $questionids = $attemptobj->get_question_ids(); |
c52c62d1 | 57 | } else { |
4fc3d7e5 | 58 | $questionids = $attemptobj->get_question_ids($page); |
83192608 | 59 | } |
4fc3d7e5 | 60 | $attemptobj->load_questions($questionids); |
61 | $attemptobj->load_question_states($questionids); | |
2d05b472 | 62 | |
f62040ed | 63 | /// Save the flag states, if they are being changed. |
64 | if ($options->flags == QUESTION_FLAGSEDITABLE && optional_param('savingflags', false, PARAM_BOOL)) { | |
82165a0c | 65 | require_sesskey(); |
f62040ed | 66 | $formdata = data_submitted(); |
67 | ||
68 | question_save_flags($formdata, $attemptid, $questionids); | |
69 | redirect($attemptobj->review_url(0, $page, $showall)); | |
70 | } | |
71 | ||
b55797b8 | 72 | /// Log this review. |
73 | add_to_log($attemptobj->get_courseid(), 'quiz', 'review', 'review.php?attempt=' . | |
74 | $attemptobj->get_attemptid(), $attemptobj->get_quizid(), $attemptobj->get_cmid()); | |
75 | ||
56ed242b | 76 | /// Work out appropriate title and whether blocks should be shown |
b55797b8 | 77 | if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) { |
56ed242b | 78 | // Normal blocks |
38e179a4 | 79 | $strreviewtitle = get_string('reviewofpreview', 'quiz'); |
73eba4be | 80 | navigation_node::override_active_url($attemptobj->start_attempt_url()); |
eb02301a | 81 | |
38e179a4 | 82 | } else { |
b9b3aa94 | 83 | $strreviewtitle = get_string('reviewofattempt', 'quiz', $attemptobj->get_attempt_number()); |
56ed242b SH |
84 | if (empty($attemptobj->get_quiz()->showblocks) && !$attemptobj->is_preview_user()) { |
85 | // Only show pretend blocks | |
86 | $PAGE->blocks->show_only_fake_blocks(); | |
87 | } | |
38e179a4 | 88 | } |
89 | ||
ff065f96 TH |
90 | // Initialise the JavaScript. |
91 | $headtags = $attemptobj->get_html_head_contributions($page); | |
92 | ||
93 | // Arrange for the navigation to be displayed. | |
d18675a8 | 94 | $navbc = $attemptobj->get_navigation_panel('quiz_review_nav_panel', $page, $showall); |
d4a03c00 | 95 | $firstregion = reset($PAGE->blocks->get_regions()); |
d9c26e21 | 96 | $PAGE->blocks->add_fake_block($navbc, $firstregion); |
d4a03c00 | 97 | |
c52c62d1 | 98 | /// Print the page header |
4fc3d7e5 | 99 | $headtags = $attemptobj->get_html_head_contributions($page); |
100 | if ($accessmanager->securewindow_required($attemptobj->is_preview_user())) { | |
f330327c | 101 | $accessmanager->setup_secure_page($attemptobj->get_course()->shortname.': '.format_string($attemptobj->get_quiz_name()), $headtags); |
7d4dfc48 | 102 | } elseif ($accessmanager->safebrowser_required($attemptobj->is_preview_user())) { |
a09f21d0 | 103 | $PAGE->set_title($attemptobj->get_course()->shortname . ': '.format_string($attemptobj->get_quiz_name())); |
56ed242b | 104 | $PAGE->set_heading($attemptobj->get_course()->fullname); |
a09f21d0 | 105 | $PAGE->set_cacheable(false); |
106 | echo $OUTPUT->header(); | |
ee1fb969 | 107 | } else { |
8f37f7fb | 108 | $PAGE->navbar->add($strreviewtitle); |
03da0c39 | 109 | $PAGE->set_title(format_string($attemptobj->get_quiz_name())); |
56ed242b | 110 | $PAGE->set_heading($attemptobj->get_course()->fullname); |
03da0c39 | 111 | echo $OUTPUT->header(); |
ee1fb969 | 112 | } |
b7f35820 | 113 | |
c52c62d1 | 114 | /// Print heading. |
b55797b8 | 115 | if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) { |
78e7a3dd | 116 | $attemptobj->print_restart_preview_button(); |
99a1bf3d | 117 | } |
90cd54cb | 118 | echo $OUTPUT->heading($strreviewtitle); |
99a1bf3d | 119 | |
4fc3d7e5 | 120 | /// Summary table start ============================================================================ |
121 | ||
9c22b42e | 122 | /// Work out some time-related things. |
4fc3d7e5 | 123 | $attempt = $attemptobj->get_attempt(); |
124 | $quiz = $attemptobj->get_quiz(); | |
235987c5 | 125 | $overtime = 0; |
d4961620 | 126 | |
ee1fb969 | 127 | if ($attempt->timefinish) { |
128 | if ($timetaken = ($attempt->timefinish - $attempt->timestart)) { | |
84e628a0 | 129 | if($quiz->timelimit && $timetaken > ($quiz->timelimit + 60)) { |
130 | $overtime = $timetaken - $quiz->timelimit; | |
ee1fb969 | 131 | $overtime = format_time($overtime); |
132 | } | |
133 | $timetaken = format_time($timetaken); | |
134 | } else { | |
135 | $timetaken = "-"; | |
d4961620 | 136 | } |
29d5d0b4 | 137 | } else { |
ee1fb969 | 138 | $timetaken = get_string('unfinished', 'quiz'); |
29d5d0b4 | 139 | } |
9c22b42e | 140 | |
141 | /// Print summary table about the whole attempt. | |
142 | /// First we assemble all the rows that are appopriate to the current situation in | |
143 | /// an array, then later we only output the table if there are any rows to show. | |
144 | $rows = array(); | |
a733c4b9 | 145 | if (!$attemptobj->get_quiz()->showuserpicture && $attemptobj->get_userid() <> $USER->id) { |
146 | /// If showuserpicture is true, the picture is shown elsewhere, so don't repeat it. | |
b9b3aa94 | 147 | $student = $DB->get_record('user', array('id' => $attemptobj->get_userid())); |
812dbaf7 | 148 | $picture = $OUTPUT->user_picture($student, array('courseid'=>$attemptobj->get_courseid())); |
9c22b42e | 149 | $rows[] = '<tr><th scope="row" class="cell">' . $picture . '</th><td class="cell"><a href="' . |
b9b3aa94 | 150 | $CFG->wwwroot . '/user/view.php?id=' . $student->id . '&course=' . $attemptobj->get_courseid() . '">' . |
9c22b42e | 151 | fullname($student, true) . '</a></td></tr>'; |
76cacec8 | 152 | } |
b55797b8 | 153 | if ($attemptobj->has_capability('mod/quiz:viewreports')) { |
154 | $attemptlist = $attemptobj->links_to_other_attempts($attemptobj->review_url(0, $page, $showall)); | |
155 | if ($attemptlist) { | |
156 | $rows[] = '<tr><th scope="row" class="cell">' . get_string('attempts', 'quiz') . | |
157 | '</th><td class="cell">' . $attemptlist . '</td></tr>'; | |
ee1fb969 | 158 | } |
ee1fb969 | 159 | } |
160 | ||
9c22b42e | 161 | /// Timing information. |
162 | $rows[] = '<tr><th scope="row" class="cell">' . get_string('startedon', 'quiz') . | |
163 | '</th><td class="cell">' . userdate($attempt->timestart) . '</td></tr>'; | |
ee1fb969 | 164 | if ($attempt->timefinish) { |
9c22b42e | 165 | $rows[] = '<tr><th scope="row" class="cell">' . get_string('completedon', 'quiz') . '</th><td class="cell">' . |
166 | userdate($attempt->timefinish) . '</td></tr>'; | |
167 | $rows[] = '<tr><th scope="row" class="cell">' . get_string('timetaken', 'quiz') . '</th><td class="cell">' . | |
168 | $timetaken . '</td></tr>'; | |
ee1fb969 | 169 | } |
3a00dbfd | 170 | if (!empty($overtime)) { |
9c22b42e | 171 | $rows[] = '<tr><th scope="row" class="cell">' . get_string('overdue', 'quiz') . '</th><td class="cell">' . $overtime . '</td></tr>'; |
d4961620 | 172 | } |
9c22b42e | 173 | |
174 | /// Show scores (if the user is allowed to see scores at the moment). | |
2b38499d | 175 | $grade = quiz_rescale_grade($attempt->sumgrades, $quiz, false); |
15db443c | 176 | if ($options->scores) { |
739b0711 | 177 | if (quiz_has_grades($quiz)) { |
15db443c | 178 | if($overtime) { |
179 | $result->sumgrades = "0"; | |
180 | $result->grade = "0.0"; | |
181 | } | |
77ed3ba5 | 182 | |
9c22b42e | 183 | /// Show raw marks only if they are different from the grade (like on the view page. |
184 | if ($quiz->grade != $quiz->sumgrades) { | |
185 | $a = new stdClass; | |
f88fb62c | 186 | $a->grade = quiz_format_grade($quiz, $attempt->sumgrades); |
6382910a | 187 | $a->maxgrade = quiz_format_grade($quiz, $quiz->sumgrades); |
9c22b42e | 188 | $rows[] = '<tr><th scope="row" class="cell">' . get_string('marks', 'quiz') . '</th><td class="cell">' . |
189 | get_string('outofshort', 'quiz', $a) . '</td></tr>'; | |
190 | } | |
191 | ||
192 | /// Now the scaled grade. | |
3b48ba9d | 193 | $a = new stdClass; |
2b38499d | 194 | $a->grade = '<b>' . quiz_format_grade($quiz, $grade) . '</b>'; |
f88fb62c | 195 | $a->maxgrade = quiz_format_grade($quiz, $quiz->grade); |
9c22b42e | 196 | $a->percent = '<b>' . round(($attempt->sumgrades/$quiz->sumgrades)*100, 0) . '</b>'; |
197 | $rows[] = '<tr><th scope="row" class="cell">' . get_string('grade') . '</th><td class="cell">' . | |
198 | get_string('outofpercent', 'quiz', $a) . '</td></tr>'; | |
d4961620 | 199 | } |
ee1fb969 | 200 | } |
9c22b42e | 201 | |
202 | /// Feedback if there is any, and the user is allowed to see it now. | |
fe6ce234 | 203 | $feedback = $attemptobj->get_overall_feedback($grade); |
77ed3ba5 | 204 | if ($options->overallfeedback && $feedback) { |
9c22b42e | 205 | $rows[] = '<tr><th scope="row" class="cell">' . get_string('feedback', 'quiz') . |
206 | '</th><td class="cell">' . $feedback . '</td></tr>'; | |
207 | } | |
208 | ||
209 | /// Now output the summary table, if there are any rows to be shown. | |
210 | if (!empty($rows)) { | |
211 | echo '<table class="generaltable generalbox quizreviewsummary"><tbody>', "\n"; | |
212 | echo implode("\n", $rows); | |
213 | echo "\n</tbody></table>\n"; | |
9bc2d82a | 214 | } |
215 | ||
4fc3d7e5 | 216 | /// Summary table end ============================================================================== |
217 | ||
f62040ed | 218 | /// Form for saving flags if necessary. |
219 | if ($options->flags == QUESTION_FLAGSEDITABLE) { | |
d4ad9adf | 220 | echo '<form action="' . s($attemptobj->review_url(0, $page, $showall)) . |
ff065f96 | 221 | '" method="post" class="questionflagsaveform"><div>'; |
f62040ed | 222 | echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />'; |
223 | } | |
224 | ||
225 | /// Print all the questions. | |
4fc3d7e5 | 226 | if ($showall) { |
baef998b | 227 | $thispage = 'all'; |
228 | $lastpage = true; | |
229 | } else { | |
230 | $thispage = $page; | |
231 | $lastpage = $attemptobj->is_last_page($page); | |
ee1fb969 | 232 | } |
baef998b | 233 | foreach ($attemptobj->get_question_ids($thispage) as $id) { |
aafdb447 | 234 | $attemptobj->print_question($id, true, $attemptobj->review_url($id, $page, $showall)); |
29d5d0b4 | 235 | } |
236 | ||
f62040ed | 237 | /// Close form if we opened it. |
238 | if ($options->flags == QUESTION_FLAGSEDITABLE) { | |
239 | echo '<div class="submitbtns">' . "\n" . | |
ff065f96 | 240 | '<input type="submit" class="questionflagsavebutton" name="savingflags" value="' . |
f62040ed | 241 | get_string('saveflags', 'question') . '" />' . |
242 | "</div>\n" . | |
29305001 | 243 | "\n</div></form>\n"; |
ff065f96 | 244 | $PAGE->requires->js_init_call('M.mod_quiz.init_review_form', null, false, quiz_get_js_module()); |
f62040ed | 245 | } |
246 | ||
baef998b | 247 | /// Print a link to the next page. |
248 | echo '<div class="submitbtns">'; | |
249 | if ($lastpage) { | |
4fc3d7e5 | 250 | $accessmanager->print_finish_review_link($attemptobj->is_preview_user()); |
baef998b | 251 | } else { |
d18675a8 | 252 | echo link_arrow_right(get_string('next'), s($attemptobj->review_url(0, $page + 1))); |
ee1fb969 | 253 | } |
baef998b | 254 | echo "</div>"; |
255 | ||
867847e3 | 256 | echo $OUTPUT->footer(); |
83192608 | 257 |