MDL-50516 mod_lesson: prevented deletion of previous attempts
[moodle.git] / mod / lesson / view.php
blob50a2bd272729533128e5a169212f371ac7d57bd1
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * This page prints a particular instance of lesson
21 * @package mod_lesson
22 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
24 **/
26 require_once(dirname(__FILE__) . '/../../config.php');
27 require_once($CFG->dirroot.'/mod/lesson/locallib.php');
28 require_once($CFG->dirroot.'/mod/lesson/view_form.php');
29 require_once($CFG->libdir . '/completionlib.php');
30 require_once($CFG->libdir . '/grade/constants.php');
32 $id = required_param('id', PARAM_INT); // Course Module ID
33 $pageid = optional_param('pageid', null, PARAM_INT); // Lesson Page ID
34 $edit = optional_param('edit', -1, PARAM_BOOL);
35 $userpassword = optional_param('userpassword','',PARAM_RAW);
36 $backtocourse = optional_param('backtocourse', false, PARAM_RAW);
38 $cm = get_coursemodule_from_id('lesson', $id, 0, false, MUST_EXIST);
39 $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
40 $lesson = new lesson($DB->get_record('lesson', array('id' => $cm->instance), '*', MUST_EXIST));
42 require_login($course, false, $cm);
44 if ($backtocourse) {
45 redirect(new moodle_url('/course/view.php', array('id'=>$course->id)));
48 // Apply overrides.
49 $lesson->update_effective_access($USER->id);
51 // Mark as viewed
52 $completion = new completion_info($course);
53 $completion->set_module_viewed($cm);
55 $url = new moodle_url('/mod/lesson/view.php', array('id'=>$id));
56 if ($pageid !== null) {
57 $url->param('pageid', $pageid);
59 $PAGE->set_url($url);
61 $context = context_module::instance($cm->id);
62 $canmanage = has_capability('mod/lesson:manage', $context);
64 $lessonoutput = $PAGE->get_renderer('mod_lesson');
66 $reviewmode = false;
67 $userhasgrade = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
68 if ($userhasgrade && !$lesson->retake) {
69 $reviewmode = true;
72 /// Check these for students only TODO: Find a better method for doing this!
73 /// Check lesson availability
74 /// Check for password
75 /// Check dependencies
76 if (!$canmanage) {
77 if (!$lesson->is_accessible()) { // Deadline restrictions
78 echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('notavailable'));
79 if ($lesson->deadline != 0 && time() > $lesson->deadline) {
80 echo $lessonoutput->lesson_inaccessible(get_string('lessonclosed', 'lesson', userdate($lesson->deadline)));
81 } else {
82 echo $lessonoutput->lesson_inaccessible(get_string('lessonopen', 'lesson', userdate($lesson->available)));
84 echo $lessonoutput->footer();
85 exit();
86 } else if ($lesson->usepassword && empty($USER->lessonloggedin[$lesson->id])) { // Password protected lesson code
87 $correctpass = false;
88 if (!empty($userpassword) && (($lesson->password == md5(trim($userpassword))) || ($lesson->password == trim($userpassword)))) {
89 // with or without md5 for backward compatibility (MDL-11090)
90 $correctpass = true;
91 $USER->lessonloggedin[$lesson->id] = true;
93 } else if (isset($lesson->extrapasswords)) {
94 // Group overrides may have additional passwords.
95 foreach ($lesson->extrapasswords as $password) {
96 if (strcmp($password, md5(trim($userpassword))) === 0 || strcmp($password, trim($userpassword)) === 0) {
97 $correctpass = true;
98 $USER->lessonloggedin[$lesson->id] = true;
102 if (!$correctpass) {
103 echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('passwordprotectedlesson', 'lesson', format_string($lesson->name)));
104 echo $lessonoutput->login_prompt($lesson, $userpassword !== '');
105 echo $lessonoutput->footer();
106 exit();
108 } else if ($lesson->dependency) { // check for dependencies
109 if ($dependentlesson = $DB->get_record('lesson', array('id' => $lesson->dependency))) {
110 // lesson exists, so we can proceed
111 $conditions = unserialize($lesson->conditions);
112 // assume false for all
113 $errors = array();
115 // check for the timespent condition
116 if ($conditions->timespent) {
117 $timespent = false;
118 if ($attempttimes = $DB->get_records('lesson_timer', array("userid"=>$USER->id, "lessonid"=>$dependentlesson->id))) {
119 // go through all the times and test to see if any of them satisfy the condition
120 foreach($attempttimes as $attempttime) {
121 $duration = $attempttime->lessontime - $attempttime->starttime;
122 if ($conditions->timespent < $duration/60) {
123 $timespent = true;
127 if (!$timespent) {
128 $errors[] = get_string('timespenterror', 'lesson', $conditions->timespent);
132 // check for the gradebetterthan condition
133 if($conditions->gradebetterthan) {
134 $gradebetterthan = false;
135 if ($studentgrades = $DB->get_records('lesson_grades', array("userid"=>$USER->id, "lessonid"=>$dependentlesson->id))) {
136 // go through all the grades and test to see if any of them satisfy the condition
137 foreach($studentgrades as $studentgrade) {
138 if ($studentgrade->grade >= $conditions->gradebetterthan) {
139 $gradebetterthan = true;
143 if (!$gradebetterthan) {
144 $errors[] = get_string('gradebetterthanerror', 'lesson', $conditions->gradebetterthan);
148 // check for the completed condition
149 if ($conditions->completed) {
150 if (!$DB->count_records('lesson_grades', array('userid'=>$USER->id, 'lessonid'=>$dependentlesson->id))) {
151 $errors[] = get_string('completederror', 'lesson');
155 if (!empty($errors)) { // print out the errors if any
156 echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('completethefollowingconditions', 'lesson', format_string($lesson->name)));
157 echo $lessonoutput->dependancy_errors($dependentlesson, $errors);
158 echo $lessonoutput->footer();
159 exit();
165 // this is called if a student leaves during a lesson
166 if ($pageid == LESSON_UNSEENBRANCHPAGE) {
167 $pageid = lesson_unseen_question_jump($lesson, $USER->id, $pageid);
170 // display individual pages and their sets of answers
171 // if pageid is EOL then the end of the lesson has been reached
172 // for flow, changed to simple echo for flow styles, michaelp, moved lesson name and page title down
173 $attemptflag = false;
174 if (empty($pageid)) {
175 // make sure there are pages to view
176 if (!$DB->get_field('lesson_pages', 'id', array('lessonid' => $lesson->id, 'prevpageid' => 0))) {
177 if (!$canmanage) {
178 $lesson->add_message(get_string('lessonnotready2', 'lesson')); // a nice message to the student
179 } else {
180 if (!$DB->count_records('lesson_pages', array('lessonid'=>$lesson->id))) {
181 redirect("$CFG->wwwroot/mod/lesson/edit.php?id=$cm->id"); // no pages - redirect to add pages
182 } else {
183 $lesson->add_message(get_string('lessonpagelinkingbroken', 'lesson')); // ok, bad mojo
188 // if no pageid given see if the lesson has been started
189 $retries = $DB->count_records('lesson_grades', array("lessonid" => $lesson->id, "userid" => $USER->id));
190 if ($retries > 0) {
191 $attemptflag = true;
194 if (isset($USER->modattempts[$lesson->id])) {
195 unset($USER->modattempts[$lesson->id]); // if no pageid, then student is NOT reviewing
198 // If there are any questions that have been answered correctly (or not) in this attempt.
199 $allattempts = $lesson->get_attempts($retries);
200 if (!empty($allattempts)) {
201 $attempt = end($allattempts);
202 $attemptpage = $lesson->load_page($attempt->pageid);
203 $jumpto = $DB->get_field('lesson_answers', 'jumpto', array('id' => $attempt->answerid));
204 // convert the jumpto to a proper page id
205 if ($jumpto == 0) {
206 // Check if a question has been incorrectly answered AND no more attempts at it are left.
207 $nattempts = $lesson->get_attempts($attempt->retry, false, $attempt->pageid, $USER->id);
208 if (count($nattempts) >= $lesson->maxattempts) {
209 $lastpageseen = $lesson->get_next_page($attemptpage->nextpageid);
210 } else {
211 $lastpageseen = $attempt->pageid;
213 } elseif ($jumpto == LESSON_NEXTPAGE) {
214 $lastpageseen = $lesson->get_next_page($attemptpage->nextpageid);
215 } else {
216 $lastpageseen = $jumpto;
220 if ($branchtables = $DB->get_records('lesson_branch', array("lessonid" => $lesson->id, "userid" => $USER->id, "retry" => $retries), 'timeseen DESC')) {
221 // in here, user has viewed a branch table
222 $lastbranchtable = current($branchtables);
223 if (count($allattempts) > 0) {
224 if ($lastbranchtable->timeseen > $attempt->timeseen) {
225 // This branch table was viewed more recently than the question page.
226 if (!empty($lastbranchtable->nextpageid)) {
227 $lastpageseen = $lastbranchtable->nextpageid;
228 } else {
229 // Next page ID did not exist prior to MDL-34006.
230 $lastpageseen = $lastbranchtable->pageid;
233 } else {
234 // Has not answered any questions but has viewed a branch table.
235 if (!empty($lastbranchtable->nextpageid)) {
236 $lastpageseen = $lastbranchtable->nextpageid;
237 } else {
238 // Next page ID did not exist prior to MDL-34006.
239 $lastpageseen = $lastbranchtable->pageid;
243 // Check to see if end of lesson was reached.
244 if ((isset($lastpageseen) && ($lastpageseen != LESSON_EOL))) {
245 if (($DB->count_records('lesson_attempts', array('lessonid' => $lesson->id, 'userid' => $USER->id, 'retry' => $retries)) > 0)
246 || $DB->count_records('lesson_branch', array("lessonid" => $lesson->id, "userid" => $USER->id, "retry" => $retries)) > 0) {
248 echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('leftduringtimedsession', 'lesson'));
249 if ($lesson->timelimit) {
250 if ($lesson->retake) {
251 $continuelink = new single_button(new moodle_url('/mod/lesson/view.php',
252 array('id' => $cm->id, 'pageid' => $lesson->firstpageid, 'startlastseen' => 'no')),
253 get_string('continue', 'lesson'), 'get');
255 echo html_writer::div($lessonoutput->message(get_string('leftduringtimed', 'lesson'), $continuelink),
256 'center leftduring');
258 } else {
259 $courselink = new single_button(new moodle_url('/course/view.php',
260 array('id' => $PAGE->course->id)), get_string('returntocourse', 'lesson'), 'get');
262 echo html_writer::div($lessonoutput->message(get_string('leftduringtimednoretake', 'lesson'), $courselink),
263 'center leftduring');
265 } else {
266 echo $lessonoutput->continue_links($lesson, $lastpageseen);
268 echo $lessonoutput->footer();
269 exit();
273 if ($attemptflag) {
274 if (!$lesson->retake) {
275 echo $lessonoutput->header($lesson, $cm, 'view', '', null, get_string("noretake", "lesson"));
276 $courselink = new single_button(new moodle_url('/course/view.php', array('id'=>$PAGE->course->id)), get_string('returntocourse', 'lesson'), 'get');
277 echo $lessonoutput->message(get_string("noretake", "lesson"), $courselink);
278 echo $lessonoutput->footer();
279 exit();
282 // start at the first page
283 if (!$pageid = $DB->get_field('lesson_pages', 'id', array('lessonid' => $lesson->id, 'prevpageid' => 0))) {
284 print_error('cannotfindfirstpage', 'lesson');
286 /// This is the code for starting a timed test
287 if(!isset($USER->startlesson[$lesson->id]) && !$canmanage) {
288 $lesson->start_timer();
292 $currenttab = 'view';
293 $extraeditbuttons = false;
294 $lessonpageid = null;
295 $timer = null;
297 if ($pageid != LESSON_EOL) {
298 /// This is the code updates the lessontime for a timed test
299 $startlastseen = optional_param('startlastseen', '', PARAM_ALPHA);
301 $page = $lesson->load_page($pageid);
302 // Check if the page is of a special type and if so take any nessecary action
303 $newpageid = $page->callback_on_view($canmanage);
304 if (is_numeric($newpageid)) {
305 $page = $lesson->load_page($newpageid);
308 // Trigger module viewed event.
309 $event = \mod_lesson\event\course_module_viewed::create(array(
310 'objectid' => $lesson->id,
311 'context' => $context
313 $event->add_record_snapshot('course_modules', $cm);
314 $event->add_record_snapshot('course', $course);
315 $event->trigger();
317 // This is where several messages (usually warnings) are displayed
318 // all of this is displayed above the actual page
320 // check to see if the user can see the left menu
321 if (!$canmanage) {
322 $lesson->displayleft = lesson_displayleftif($lesson);
324 $continue = ($startlastseen !== '');
325 $restart = ($continue && $startlastseen == 'yes');
326 $timer = $lesson->update_timer($continue, $restart);
328 if ($lesson->timelimit) {
329 $timeleft = $timer->starttime + $lesson->timelimit - time();
330 if ($timeleft <= 0) {
331 // Out of time
332 $lesson->add_message(get_string('eolstudentoutoftime', 'lesson'));
333 redirect(new moodle_url('/mod/lesson/view.php', array('id'=>$cm->id,'pageid'=>LESSON_EOL, 'outoftime'=>'normal')));
334 die; // Shouldn't be reached, but make sure
335 } else if ($timeleft < 60) {
336 // One minute warning
337 $lesson->add_message(get_string('studentoneminwarning', 'lesson'));
341 if ($page->qtype == LESSON_PAGE_BRANCHTABLE && $lesson->minquestions) {
342 // tell student how many questions they have seen, how many are required and their grade
343 $ntries = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
344 $gradeinfo = lesson_grade($lesson, $ntries);
345 if ($gradeinfo->attempts) {
346 if ($gradeinfo->nquestions < $lesson->minquestions) {
347 $a = new stdClass;
348 $a->nquestions = $gradeinfo->nquestions;
349 $a->minquestions = $lesson->minquestions;
350 $lesson->add_message(get_string('numberofpagesviewednotice', 'lesson', $a));
353 if (!$reviewmode && !$lesson->retake){
354 $lesson->add_message(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'notify');
355 if ($lesson->grade != GRADE_TYPE_NONE) {
356 $a = new stdClass;
357 $a->grade = number_format($gradeinfo->grade * $lesson->grade / 100, 1);
358 $a->total = $lesson->grade;
359 $lesson->add_message(get_string('yourcurrentgradeisoutof', 'lesson', $a), 'notify');
364 } else {
365 $timer = null;
366 if ($lesson->timelimit) {
367 $lesson->add_message(get_string('teachertimerwarning', 'lesson'));
369 if (lesson_display_teacher_warning($lesson)) {
370 // This is the warning msg for teachers to inform them that cluster
371 // and unseen does not work while logged in as a teacher
372 $warningvars = new stdClass();
373 $warningvars->cluster = get_string('clusterjump', 'lesson');
374 $warningvars->unseen = get_string('unseenpageinbranch', 'lesson');
375 $lesson->add_message(get_string('teacherjumpwarning', 'lesson', $warningvars));
379 $PAGE->set_subpage($page->id);
380 $currenttab = 'view';
381 $extraeditbuttons = true;
382 $lessonpageid = $page->id;
383 $extrapagetitle = $page->title;
385 if (($edit != -1) && $PAGE->user_allowed_editing()) {
386 $USER->editing = $edit;
389 if (is_array($page->answers) && count($page->answers)>0) {
390 // this is for modattempts option. Find the users previous answer to this page,
391 // and then display it below in answer processing
392 if (isset($USER->modattempts[$lesson->id])) {
393 $retries = $DB->count_records('lesson_grades', array("lessonid"=>$lesson->id, "userid"=>$USER->id));
394 if (!$attempts = $lesson->get_attempts($retries-1, false, $page->id)) {
395 print_error('cannotfindpreattempt', 'lesson');
397 $attempt = end($attempts);
398 $USER->modattempts[$lesson->id] = $attempt;
399 } else {
400 $attempt = false;
402 $lessoncontent = $lessonoutput->display_page($lesson, $page, $attempt);
403 } else {
404 $data = new stdClass;
405 $data->id = $PAGE->cm->id;
406 $data->pageid = $page->id;
407 $data->newpageid = $lesson->get_next_page($page->nextpageid);
409 $customdata = array(
410 'title' => $page->title,
411 'contents' => $page->get_contents()
413 $mform = new lesson_page_without_answers($CFG->wwwroot.'/mod/lesson/continue.php', $customdata);
414 $mform->set_data($data);
415 ob_start();
416 $mform->display();
417 $lessoncontent = ob_get_contents();
418 ob_end_clean();
421 lesson_add_fake_blocks($PAGE, $cm, $lesson, $timer);
422 echo $lessonoutput->header($lesson, $cm, $currenttab, $extraeditbuttons, $lessonpageid, $extrapagetitle);
423 if ($attemptflag) {
424 // We are using level 3 header because attempt heading is a sub-heading of lesson title (MDL-30911).
425 echo $OUTPUT->heading(get_string('attempt', 'lesson', $retries), 3);
427 /// This calculates and prints the ongoing score
428 if ($lesson->ongoing && !empty($pageid) && !$reviewmode) {
429 echo $lessonoutput->ongoing_score($lesson);
431 if ($lesson->displayleft) {
432 echo '<a name="maincontent" id="maincontent" title="' . get_string('anchortitle', 'lesson') . '"></a>';
434 echo $lessoncontent;
435 echo $lessonoutput->progress_bar($lesson);
436 echo $lessonoutput->footer();
438 } else {
440 $lessoncontent = '';
441 // end of lesson reached work out grade
442 // Used to check to see if the student ran out of time
443 $outoftime = optional_param('outoftime', '', PARAM_ALPHA);
445 // We are using level 3 header because the page title is a sub-heading of lesson title (MDL-30911).
446 $lessoncontent .= $OUTPUT->heading(get_string("congratulations", "lesson"), 3);
447 $lessoncontent .= $OUTPUT->box_start('generalbox boxaligncenter');
448 $ntries = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
449 if (isset($USER->modattempts[$lesson->id])) {
450 $ntries--; // need to look at the old attempts :)
452 if (!$canmanage) {
453 // Store this now before any modifications to pages viewed.
454 $progressbar = $lessonoutput->progress_bar($lesson);
455 // Update the clock / get time information for this user.
456 $lesson->stop_timer();
457 $gradeinfo = lesson_grade($lesson, $ntries);
459 // Update completion state.
460 $completion = new completion_info($course);
461 if ($completion->is_enabled($cm) && $lesson->completionendreached) {
462 $completion->update_state($cm, COMPLETION_COMPLETE);
465 if ($lesson->completiontimespent > 0) {
466 $duration = $DB->get_field_sql(
467 "SELECT SUM(lessontime - starttime)
468 FROM {lesson_timer}
469 WHERE lessonid = :lessonid
470 AND userid = :userid",
471 array('userid' => $USER->id, 'lessonid' => $lesson->id));
472 if (!$duration) {
473 $duration = 0;
476 // If student has not spend enough time in the lesson, display a message.
477 if ($duration < $lesson->completiontimespent) {
478 $a = new stdClass;
479 $a->timespent = format_time($duration);
480 $a->timerequired = format_time($lesson->completiontimespent);
481 $lessoncontent .= $lessonoutput->paragraph(get_string("notenoughtimespent", "lesson", $a), 'center');
486 if ($gradeinfo->attempts) {
487 if (!$lesson->custom) {
488 $lessoncontent .= $lessonoutput->paragraph(get_string("numberofpagesviewed", "lesson", $gradeinfo->nquestions), 'center');
489 if ($lesson->minquestions) {
490 if ($gradeinfo->nquestions < $lesson->minquestions) {
491 // print a warning and set nviewed to minquestions
492 $lessoncontent .= $lessonoutput->paragraph(get_string("youshouldview", "lesson", $lesson->minquestions), 'center');
495 $lessoncontent .= $lessonoutput->paragraph(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'center');
497 $a = new stdClass;
498 $a->score = $gradeinfo->earned;
499 $a->grade = $gradeinfo->total;
500 if ($gradeinfo->nmanual) {
501 $a->tempmaxgrade = $gradeinfo->total - $gradeinfo->manualpoints;
502 $a->essayquestions = $gradeinfo->nmanual;
503 $lessoncontent .= $OUTPUT->box(get_string("displayscorewithessays", "lesson", $a), 'center');
504 } else {
505 $lessoncontent .= $OUTPUT->box(get_string("displayscorewithoutessays", "lesson", $a), 'center');
507 if ($lesson->grade != GRADE_TYPE_NONE) {
508 $a = new stdClass;
509 $a->grade = number_format($gradeinfo->grade * $lesson->grade / 100, 1);
510 $a->total = $lesson->grade;
511 $lessoncontent .= $lessonoutput->paragraph(get_string("yourcurrentgradeisoutof", "lesson", $a), 'center');
514 $grade = new stdClass();
515 $grade->lessonid = $lesson->id;
516 $grade->userid = $USER->id;
517 $grade->grade = $gradeinfo->grade;
518 $grade->completed = time();
519 if (isset($USER->modattempts[$lesson->id])) { // If reviewing, make sure update old grade record.
520 if (!$grades = $DB->get_records("lesson_grades",
521 array("lessonid" => $lesson->id, "userid" => $USER->id), "completed DESC", '*', 0, 1)) {
522 print_error('cannotfindgrade', 'lesson');
524 $oldgrade = array_shift($grades);
525 $grade->id = $oldgrade->id;
526 $DB->update_record("lesson_grades", $grade);
527 } else {
528 $newgradeid = $DB->insert_record("lesson_grades", $grade);
530 } else {
531 if ($lesson->timelimit) {
532 if ($outoftime == 'normal') {
533 $grade = new stdClass();
534 $grade->lessonid = $lesson->id;
535 $grade->userid = $USER->id;
536 $grade->grade = 0;
537 $grade->completed = time();
538 $newgradeid = $DB->insert_record("lesson_grades", $grade);
539 $lessoncontent .= $lessonoutput->paragraph(get_string("eolstudentoutoftimenoanswers", "lesson"));
541 } else {
542 $lessoncontent .= $lessonoutput->paragraph(get_string("welldone", "lesson"));
546 // update central gradebook
547 lesson_update_grades($lesson, $USER->id);
548 $lessoncontent .= $progressbar;
550 } else {
551 // display for teacher
552 if ($lesson->grade != GRADE_TYPE_NONE) {
553 $lessoncontent .= $lessonoutput->paragraph(get_string("displayofgrade", "lesson"), 'center');
556 $lessoncontent .= $OUTPUT->box_end(); //End of Lesson button to Continue.
558 if ($lesson->modattempts && !$canmanage) {
559 // make sure if the student is reviewing, that he/she sees the same pages/page path that he/she saw the first time
560 // look at the attempt records to find the first QUESTION page that the user answered, then use that page id
561 // to pass to view again. This is slick cause it wont call the empty($pageid) code
562 // $ntries is decremented above
563 if (!$attempts = $lesson->get_attempts($ntries)) {
564 $attempts = array();
565 $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id));
566 } else {
567 $firstattempt = current($attempts);
568 $pageid = $firstattempt->pageid;
569 // IF the student wishes to review, need to know the last question page that the student answered. This will help to make
570 // sure that the student can leave the lesson via pushing the continue button.
571 $lastattempt = end($attempts);
572 $USER->modattempts[$lesson->id] = $lastattempt->pageid;
574 $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$pageid));
576 $lessoncontent .= html_writer::link($url, get_string('reviewlesson', 'lesson'), array('class' => 'centerpadded lessonbutton standardbutton'));
577 } elseif ($lesson->modattempts && $canmanage) {
578 $lessoncontent .= $lessonoutput->paragraph(get_string("modattemptsnoteacher", "lesson"), 'centerpadded');
581 if ($lesson->activitylink) {
582 $lessoncontent .= $lesson->link_for_activitylink();
585 $url = new moodle_url('/course/view.php', array('id'=>$course->id));
586 $lessoncontent .= html_writer::link($url, get_string('returnto', 'lesson', format_string($course->fullname, true)), array('class'=>'centerpadded lessonbutton standardbutton'));
588 if (has_capability('gradereport/user:view', context_course::instance($course->id))
589 && $course->showgrades && $lesson->grade != 0 && !$lesson->practice) {
590 $url = new moodle_url('/grade/index.php', array('id' => $course->id));
591 $lessoncontent .= html_writer::link($url, get_string('viewgrades', 'lesson'),
592 array('class' => 'centerpadded lessonbutton standardbutton'));
595 lesson_add_fake_blocks($PAGE, $cm, $lesson, $timer);
596 echo $lessonoutput->header($lesson, $cm, $currenttab, $extraeditbuttons, $lessonpageid, get_string("congratulations", "lesson"));
597 echo $lessoncontent;
598 echo $lessonoutput->footer();