MDL-56670 mod_lesson: adds padding to end of lesson links
[moodle.git] / mod / lesson / view.php
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.
14 //
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
20  *
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(__DIR__ . '/../../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)));
46 }
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);
58 }
59 $PAGE->set_url($url);
60 $PAGE->force_settings_menu();
62 $context = context_module::instance($cm->id);
63 $canmanage = has_capability('mod/lesson:manage', $context);
65 $lessonoutput = $PAGE->get_renderer('mod_lesson');
67 $reviewmode = false;
68 $userhasgrade = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
69 if ($userhasgrade && !$lesson->retake) {
70     $reviewmode = true;
71 }
73 /// Check these for students only TODO: Find a better method for doing this!
74 ///     Check lesson availability
75 ///     Check for password
76 ///     Check dependencies
77 if (!$canmanage) {
78     if (!$lesson->is_accessible()) {  // Deadline restrictions
79         echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('notavailable'));
80         if ($lesson->deadline != 0 && time() > $lesson->deadline) {
81             echo $lessonoutput->lesson_inaccessible(get_string('lessonclosed', 'lesson', userdate($lesson->deadline)));
82         } else {
83             echo $lessonoutput->lesson_inaccessible(get_string('lessonopen', 'lesson', userdate($lesson->available)));
84         }
85         echo $lessonoutput->footer();
86         exit();
87     } else if ($lesson->usepassword && empty($USER->lessonloggedin[$lesson->id])) { // Password protected lesson code
88         $correctpass = false;
89         if (!empty($userpassword) && (($lesson->password == md5(trim($userpassword))) || ($lesson->password == trim($userpassword)))) {
90             require_sesskey();
91             // with or without md5 for backward compatibility (MDL-11090)
92             $correctpass = true;
93             $USER->lessonloggedin[$lesson->id] = true;
95         } else if (isset($lesson->extrapasswords)) {
97             // Group overrides may have additional passwords.
98             foreach ($lesson->extrapasswords as $password) {
99                 if (strcmp($password, md5(trim($userpassword))) === 0 || strcmp($password, trim($userpassword)) === 0) {
100                     require_sesskey();
101                     $correctpass = true;
102                     $USER->lessonloggedin[$lesson->id] = true;
103                 }
104             }
105         }
106         if (!$correctpass) {
107             echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('passwordprotectedlesson', 'lesson', format_string($lesson->name)));
108             echo $lessonoutput->login_prompt($lesson, $userpassword !== '');
109             echo $lessonoutput->footer();
110             exit();
111         }
112     } else if ($lesson->dependency) { // check for dependencies
113         if ($dependentlesson = $DB->get_record('lesson', array('id' => $lesson->dependency))) {
114             // lesson exists, so we can proceed
115             $conditions = unserialize($lesson->conditions);
116             // assume false for all
117             $errors = array();
119             // check for the timespent condition
120             if ($conditions->timespent) {
121                 $timespent = false;
122                 if ($attempttimes = $DB->get_records('lesson_timer', array("userid"=>$USER->id, "lessonid"=>$dependentlesson->id))) {
123                     // go through all the times and test to see if any of them satisfy the condition
124                     foreach($attempttimes as $attempttime) {
125                         $duration = $attempttime->lessontime - $attempttime->starttime;
126                         if ($conditions->timespent < $duration/60) {
127                             $timespent = true;
128                         }
129                     }
130                 }
131                 if (!$timespent) {
132                     $errors[] = get_string('timespenterror', 'lesson', $conditions->timespent);
133                 }
134             }
136             // check for the gradebetterthan condition
137             if($conditions->gradebetterthan) {
138                 $gradebetterthan = false;
139                 if ($studentgrades = $DB->get_records('lesson_grades', array("userid"=>$USER->id, "lessonid"=>$dependentlesson->id))) {
140                     // go through all the grades and test to see if any of them satisfy the condition
141                     foreach($studentgrades as $studentgrade) {
142                         if ($studentgrade->grade >= $conditions->gradebetterthan) {
143                             $gradebetterthan = true;
144                         }
145                     }
146                 }
147                 if (!$gradebetterthan) {
148                     $errors[] = get_string('gradebetterthanerror', 'lesson', $conditions->gradebetterthan);
149                 }
150             }
152             // check for the completed condition
153             if ($conditions->completed) {
154                 if (!$DB->count_records('lesson_grades', array('userid'=>$USER->id, 'lessonid'=>$dependentlesson->id))) {
155                     $errors[] = get_string('completederror', 'lesson');
156                 }
157             }
159             if (!empty($errors)) {  // print out the errors if any
160                 echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('completethefollowingconditions', 'lesson', format_string($lesson->name)));
161                 echo $lessonoutput->dependancy_errors($dependentlesson, $errors);
162                 echo $lessonoutput->footer();
163                 exit();
164             }
165         }
166     }
169     // this is called if a student leaves during a lesson
170 if ($pageid == LESSON_UNSEENBRANCHPAGE) {
171     $pageid = lesson_unseen_question_jump($lesson, $USER->id, $pageid);
174 // display individual pages and their sets of answers
175 // if pageid is EOL then the end of the lesson has been reached
176 // for flow, changed to simple echo for flow styles, michaelp, moved lesson name and page title down
177 $attemptflag = false;
178 if (empty($pageid)) {
179     // make sure there are pages to view
180     if (!$DB->get_field('lesson_pages', 'id', array('lessonid' => $lesson->id, 'prevpageid' => 0))) {
181         if (!$canmanage) {
182             $lesson->add_message(get_string('lessonnotready2', 'lesson')); // a nice message to the student
183         } else {
184             if (!$DB->count_records('lesson_pages', array('lessonid'=>$lesson->id))) {
185                 redirect("$CFG->wwwroot/mod/lesson/edit.php?id=$cm->id"); // no pages - redirect to add pages
186             } else {
187                 $lesson->add_message(get_string('lessonpagelinkingbroken', 'lesson'));  // ok, bad mojo
188             }
189         }
190     }
192     // if no pageid given see if the lesson has been started
193     $retries = $DB->count_records('lesson_grades', array("lessonid" => $lesson->id, "userid" => $USER->id));
194     if ($retries > 0) {
195         $attemptflag = true;
196     }
198     if (isset($USER->modattempts[$lesson->id])) {
199         unset($USER->modattempts[$lesson->id]);  // if no pageid, then student is NOT reviewing
200     }
202     // If there are any questions that have been answered correctly (or not) in this attempt.
203     $allattempts = $lesson->get_attempts($retries);
204     if (!empty($allattempts)) {
205         $attempt = end($allattempts);
206         $attemptpage = $lesson->load_page($attempt->pageid);
207         $jumpto = $DB->get_field('lesson_answers', 'jumpto', array('id' => $attempt->answerid));
208         // convert the jumpto to a proper page id
209         if ($jumpto == 0) {
210             // Check if a question has been incorrectly answered AND no more attempts at it are left.
211             $nattempts = $lesson->get_attempts($attempt->retry, false, $attempt->pageid, $USER->id);
212             if (count($nattempts) >= $lesson->maxattempts) {
213                 $lastpageseen = $lesson->get_next_page($attemptpage->nextpageid);
214             } else {
215                 $lastpageseen = $attempt->pageid;
216             }
217         } elseif ($jumpto == LESSON_NEXTPAGE) {
218             $lastpageseen = $lesson->get_next_page($attemptpage->nextpageid);
219         } else if ($jumpto == LESSON_CLUSTERJUMP) {
220             $lastpageseen = $lesson->cluster_jump($attempt->pageid);
221         } else {
222             $lastpageseen = $jumpto;
223         }
224     }
226     if ($branchtables = $DB->get_records('lesson_branch', array("lessonid" => $lesson->id, "userid" => $USER->id, "retry" => $retries), 'timeseen DESC')) {
227         // in here, user has viewed a branch table
228         $lastbranchtable = current($branchtables);
229         if (count($allattempts) > 0) {
230             if ($lastbranchtable->timeseen > $attempt->timeseen) {
231                 // This branch table was viewed more recently than the question page.
232                 if (!empty($lastbranchtable->nextpageid)) {
233                     $lastpageseen = $lastbranchtable->nextpageid;
234                 } else {
235                     // Next page ID did not exist prior to MDL-34006.
236                     $lastpageseen = $lastbranchtable->pageid;
237                 }
238             }
239         } else {
240             // Has not answered any questions but has viewed a branch table.
241             if (!empty($lastbranchtable->nextpageid)) {
242                 $lastpageseen = $lastbranchtable->nextpageid;
243             } else {
244                 // Next page ID did not exist prior to MDL-34006.
245                 $lastpageseen = $lastbranchtable->pageid;
246             }
247         }
248     }
249     // Check to see if end of lesson was reached.
250     if ((isset($lastpageseen) && ($lastpageseen != LESSON_EOL))) {
251         if (($DB->count_records('lesson_attempts', array('lessonid' => $lesson->id, 'userid' => $USER->id, 'retry' => $retries)) > 0)
252                 || $DB->count_records('lesson_branch', array("lessonid" => $lesson->id, "userid" => $USER->id, "retry" => $retries)) > 0) {
254             echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('leftduringtimedsession', 'lesson'));
255             if ($lesson->timelimit) {
256                 if ($lesson->retake) {
257                     $continuelink = new single_button(new moodle_url('/mod/lesson/view.php',
258                             array('id' => $cm->id, 'pageid' => $lesson->firstpageid, 'startlastseen' => 'no')),
259                             get_string('continue', 'lesson'), 'get');
261                     echo html_writer::div($lessonoutput->message(get_string('leftduringtimed', 'lesson'), $continuelink),
262                             'center leftduring');
264                 } else {
265                     $courselink = new single_button(new moodle_url('/course/view.php',
266                             array('id' => $PAGE->course->id)), get_string('returntocourse', 'lesson'), 'get');
268                     echo html_writer::div($lessonoutput->message(get_string('leftduringtimednoretake', 'lesson'), $courselink),
269                             'center leftduring');
270                 }
271             } else {
272                 echo $lessonoutput->continue_links($lesson, $lastpageseen);
273             }
274             echo $lessonoutput->footer();
275             exit();
276         }
277     }
279     if ($attemptflag) {
280         if (!$lesson->retake) {
281             echo $lessonoutput->header($lesson, $cm, 'view', '', null, get_string("noretake", "lesson"));
282             $courselink = new single_button(new moodle_url('/course/view.php', array('id'=>$PAGE->course->id)), get_string('returntocourse', 'lesson'), 'get');
283             echo $lessonoutput->message(get_string("noretake", "lesson"), $courselink);
284             echo $lessonoutput->footer();
285             exit();
286         }
287     }
288     // start at the first page
289     if (!$pageid = $DB->get_field('lesson_pages', 'id', array('lessonid' => $lesson->id, 'prevpageid' => 0))) {
290         echo $lessonoutput->header($lesson, $cm, 'view', '', null);
291         // Lesson currently has no content. A message for display has been prepared and will be displayed by the header method
292         // of the lesson renderer.
293         echo $lessonoutput->footer();
294         exit();
295     }
296     /// This is the code for starting a timed test
297     if(!isset($USER->startlesson[$lesson->id]) && !$canmanage) {
298         $lesson->start_timer();
299     }
302 $currenttab = 'view';
303 $extraeditbuttons = false;
304 $lessonpageid = null;
305 $timer = null;
307 if ($pageid != LESSON_EOL) {
308     /// This is the code updates the lessontime for a timed test
309     $startlastseen = optional_param('startlastseen', '', PARAM_ALPHA);
311     $page = $lesson->load_page($pageid);
312     // Check if the page is of a special type and if so take any nessecary action
313     $newpageid = $page->callback_on_view($canmanage);
314     if (is_numeric($newpageid)) {
315         $page = $lesson->load_page($newpageid);
316     }
318     // Trigger module viewed event.
319     $event = \mod_lesson\event\course_module_viewed::create(array(
320         'objectid' => $lesson->id,
321         'context' => $context
322     ));
323     $event->add_record_snapshot('course_modules', $cm);
324     $event->add_record_snapshot('course', $course);
325     $event->trigger();
327     // This is where several messages (usually warnings) are displayed
328     // all of this is displayed above the actual page
330     // check to see if the user can see the left menu
331     if (!$canmanage) {
332         $lesson->displayleft = lesson_displayleftif($lesson);
334         $continue = ($startlastseen !== '');
335         $restart  = ($continue && $startlastseen == 'yes');
336         $timer = $lesson->update_timer($continue, $restart);
338         if ($lesson->timelimit) {
339             $timeleft = $timer->starttime + $lesson->timelimit - time();
340             if ($timeleft <= 0) {
341                 // Out of time
342                 $lesson->add_message(get_string('eolstudentoutoftime', 'lesson'));
343                 redirect(new moodle_url('/mod/lesson/view.php', array('id'=>$cm->id,'pageid'=>LESSON_EOL, 'outoftime'=>'normal')));
344                 die; // Shouldn't be reached, but make sure
345             } else if ($timeleft < 60) {
346                 // One minute warning
347                 $lesson->add_message(get_string('studentoneminwarning', 'lesson'));
348             }
349         }
351         if ($page->qtype == LESSON_PAGE_BRANCHTABLE && $lesson->minquestions) {
352             // tell student how many questions they have seen, how many are required and their grade
353             $ntries = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
354             $gradeinfo = lesson_grade($lesson, $ntries);
355             if ($gradeinfo->attempts) {
356                 if ($gradeinfo->nquestions < $lesson->minquestions) {
357                     $a = new stdClass;
358                     $a->nquestions   = $gradeinfo->nquestions;
359                     $a->minquestions = $lesson->minquestions;
360                     $lesson->add_message(get_string('numberofpagesviewednotice', 'lesson', $a));
361                 }
363                 if (!$reviewmode && !$lesson->retake){
364                     $lesson->add_message(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'notify');
365                     if ($lesson->grade != GRADE_TYPE_NONE) {
366                         $a = new stdClass;
367                         $a->grade = number_format($gradeinfo->grade * $lesson->grade / 100, 1);
368                         $a->total = $lesson->grade;
369                         $lesson->add_message(get_string('yourcurrentgradeisoutof', 'lesson', $a), 'notify');
370                     }
371                 }
372             }
373         }
374     } else {
375         $timer = null;
376         if ($lesson->timelimit) {
377             $lesson->add_message(get_string('teachertimerwarning', 'lesson'));
378         }
379         if (lesson_display_teacher_warning($lesson)) {
380             // This is the warning msg for teachers to inform them that cluster
381             // and unseen does not work while logged in as a teacher
382             $warningvars = new stdClass();
383             $warningvars->cluster = get_string('clusterjump', 'lesson');
384             $warningvars->unseen = get_string('unseenpageinbranch', 'lesson');
385             $lesson->add_message(get_string('teacherjumpwarning', 'lesson', $warningvars));
386         }
387     }
389     $PAGE->set_subpage($page->id);
390     $currenttab = 'view';
391     $extraeditbuttons = true;
392     $lessonpageid = $page->id;
393     $extrapagetitle = $page->title;
395     if (($edit != -1) && $PAGE->user_allowed_editing()) {
396         $USER->editing = $edit;
397     }
399     if (is_array($page->answers) && count($page->answers)>0) {
400         // this is for modattempts option.  Find the users previous answer to this page,
401         //   and then display it below in answer processing
402         if (isset($USER->modattempts[$lesson->id])) {
403             $retries = $DB->count_records('lesson_grades', array("lessonid"=>$lesson->id, "userid"=>$USER->id));
404             if (!$attempts = $lesson->get_attempts($retries-1, false, $page->id)) {
405                 print_error('cannotfindpreattempt', 'lesson');
406             }
407             $attempt = end($attempts);
408             $USER->modattempts[$lesson->id] = $attempt;
409         } else {
410             $attempt = false;
411         }
412         $lessoncontent = $lessonoutput->display_page($lesson, $page, $attempt);
413     } else {
414         $data = new stdClass;
415         $data->id = $PAGE->cm->id;
416         $data->pageid = $page->id;
417         $data->newpageid = $lesson->get_next_page($page->nextpageid);
419         $customdata = array(
420             'title'     => $page->title,
421             'contents'  => $page->get_contents()
422         );
423         $mform = new lesson_page_without_answers($CFG->wwwroot.'/mod/lesson/continue.php', $customdata);
424         $mform->set_data($data);
425         ob_start();
426         $mform->display();
427         $lessoncontent = ob_get_contents();
428         ob_end_clean();
429     }
431     lesson_add_fake_blocks($PAGE, $cm, $lesson, $timer);
432     echo $lessonoutput->header($lesson, $cm, $currenttab, $extraeditbuttons, $lessonpageid, $extrapagetitle);
433     if ($attemptflag) {
434         // We are using level 3 header because attempt heading is a sub-heading of lesson title (MDL-30911).
435         echo $OUTPUT->heading(get_string('attempt', 'lesson', $retries), 3);
436     }
437     /// This calculates and prints the ongoing score
438     if ($lesson->ongoing && !empty($pageid) && !$reviewmode) {
439         echo $lessonoutput->ongoing_score($lesson);
440     }
441     if ($lesson->displayleft) {
442         echo '<a name="maincontent" id="maincontent" title="' . get_string('anchortitle', 'lesson') . '"></a>';
443     }
444     echo $lessoncontent;
445     echo $lessonoutput->progress_bar($lesson);
446     echo $lessonoutput->footer();
448 } else {
450     $lessoncontent = '';
451     // end of lesson reached work out grade
452     // Used to check to see if the student ran out of time
453     $outoftime = optional_param('outoftime', '', PARAM_ALPHA);
455     $ntries = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
456     if (isset($USER->modattempts[$lesson->id])) {
457         $ntries--;  // need to look at the old attempts :)
458     }
459     $gradelesson = true;
460     $gradeinfo = lesson_grade($lesson, $ntries);
461     if ($lesson->custom && !$canmanage) {
462         // Before we calculate the custom score make sure they answered the minimum
463         // number of questions. We only need to do this for custom scoring as we can
464         // not get the miniumum score the user should achieve. If we are not using
465         // custom scoring (so all questions are valued as 1) then we simply check if
466         // they answered more than the minimum questions, if not, we mark it out of the
467         // number specified in the minimum questions setting - which is done in lesson_grade().
468         // Get the number of answers given.
469         if ($gradeinfo->nquestions < $lesson->minquestions) {
470             $gradelesson = false;
471             $a = new stdClass;
472             $a->nquestions = $gradeinfo->nquestions;
473             $a->minquestions = $lesson->minquestions;
474             $lessoncontent .= $OUTPUT->box_start('generalbox boxaligncenter');
475             $lesson->add_message(get_string('numberofpagesviewednotice', 'lesson', $a));
476         }
477     }
478     if ($gradelesson) {
479         // We are using level 3 header because the page title is a sub-heading of lesson title (MDL-30911).
480         $lessoncontent .= $OUTPUT->heading(get_string("congratulations", "lesson"), 3);
481         $lessoncontent .= $OUTPUT->box_start('generalbox boxaligncenter');
482     }
483     if (!$canmanage) {
484         if ($gradelesson) {
485             // Store this now before any modifications to pages viewed.
486             $progressbar = $lessonoutput->progress_bar($lesson);
487             // Update the clock / get time information for this user.
488             $lesson->stop_timer();
490             // Update completion state.
491             $completion = new completion_info($course);
492             if ($completion->is_enabled($cm) && $lesson->completionendreached) {
493                 $completion->update_state($cm, COMPLETION_COMPLETE);
494             }
496             if ($lesson->completiontimespent > 0) {
497                 $duration = $DB->get_field_sql(
498                     "SELECT SUM(lessontime - starttime)
499                                    FROM {lesson_timer}
500                                   WHERE lessonid = :lessonid
501                                     AND userid = :userid",
502                     array('userid' => $USER->id, 'lessonid' => $lesson->id));
503                 if (!$duration) {
504                     $duration = 0;
505                 }
507                 // If student has not spend enough time in the lesson, display a message.
508                 if ($duration < $lesson->completiontimespent) {
509                     $a = new stdClass;
510                     $a->timespent = format_time($duration);
511                     $a->timerequired = format_time($lesson->completiontimespent);
512                     $lessoncontent .= $lessonoutput->paragraph(get_string("notenoughtimespent", "lesson", $a), 'center');
513                 }
514             }
517             if ($gradeinfo->attempts) {
518                 if (!$lesson->custom) {
519                     $lessoncontent .= $lessonoutput->paragraph(get_string("numberofpagesviewed", "lesson", $gradeinfo->nquestions), 'center');
520                     if ($lesson->minquestions) {
521                         if ($gradeinfo->nquestions < $lesson->minquestions) {
522                             // print a warning and set nviewed to minquestions
523                             $lessoncontent .= $lessonoutput->paragraph(get_string("youshouldview", "lesson", $lesson->minquestions), 'center');
524                         }
525                     }
526                     $lessoncontent .= $lessonoutput->paragraph(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'center');
527                 }
528                 $a = new stdClass;
529                 $a->score = $gradeinfo->earned;
530                 $a->grade = $gradeinfo->total;
531                 if ($gradeinfo->nmanual) {
532                     $a->tempmaxgrade = $gradeinfo->total - $gradeinfo->manualpoints;
533                     $a->essayquestions = $gradeinfo->nmanual;
534                     $lessoncontent .= $OUTPUT->box(get_string("displayscorewithessays", "lesson", $a), 'center');
535                 } else {
536                     $lessoncontent .= $OUTPUT->box(get_string("displayscorewithoutessays", "lesson", $a), 'center');
537                 }
538                 if ($lesson->grade != GRADE_TYPE_NONE) {
539                     $a = new stdClass;
540                     $a->grade = number_format($gradeinfo->grade * $lesson->grade / 100, 1);
541                     $a->total = $lesson->grade;
542                     $lessoncontent .= $lessonoutput->paragraph(get_string("yourcurrentgradeisoutof", "lesson", $a), 'center');
543                 }
545                 $grade = new stdClass();
546                 $grade->lessonid = $lesson->id;
547                 $grade->userid = $USER->id;
548                 $grade->grade = $gradeinfo->grade;
549                 $grade->completed = time();
550                 if (isset($USER->modattempts[$lesson->id])) { // If reviewing, make sure update old grade record.
551                     if (!$grades = $DB->get_records("lesson_grades",
552                         array("lessonid" => $lesson->id, "userid" => $USER->id), "completed DESC", '*', 0, 1)) {
553                         print_error('cannotfindgrade', 'lesson');
554                     }
555                     $oldgrade = array_shift($grades);
556                     $grade->id = $oldgrade->id;
557                     $DB->update_record("lesson_grades", $grade);
558                 } else {
559                     $newgradeid = $DB->insert_record("lesson_grades", $grade);
560                 }
561             } else {
562                 if ($lesson->timelimit) {
563                     if ($outoftime == 'normal') {
564                         $grade = new stdClass();
565                         $grade->lessonid = $lesson->id;
566                         $grade->userid = $USER->id;
567                         $grade->grade = 0;
568                         $grade->completed = time();
569                         $newgradeid = $DB->insert_record("lesson_grades", $grade);
570                         $lessoncontent .= $lessonoutput->paragraph(get_string("eolstudentoutoftimenoanswers", "lesson"));
571                     }
572                 } else {
573                     $lessoncontent .= $lessonoutput->paragraph(get_string("welldone", "lesson"));
574                 }
575             }
577             // update central gradebook
578             lesson_update_grades($lesson, $USER->id);
579             $lessoncontent .= $progressbar;
580         }
581     } else {
582         // display for teacher
583         if ($lesson->grade != GRADE_TYPE_NONE) {
584             $lessoncontent .= $lessonoutput->paragraph(get_string("displayofgrade", "lesson"), 'center');
585         }
586     }
587     $lessoncontent .= $OUTPUT->box_end(); //End of Lesson button to Continue.
589     if ($lesson->modattempts && !$canmanage) {
590         // make sure if the student is reviewing, that he/she sees the same pages/page path that he/she saw the first time
591         // look at the attempt records to find the first QUESTION page that the user answered, then use that page id
592         // to pass to view again.  This is slick cause it wont call the empty($pageid) code
593         // $ntries is decremented above
594         if (!$attempts = $lesson->get_attempts($ntries)) {
595             $attempts = array();
596             $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id));
597         } else {
598             $firstattempt = current($attempts);
599             $pageid = $firstattempt->pageid;
600             // IF the student wishes to review, need to know the last question page that the student answered.  This will help to make
601             // sure that the student can leave the lesson via pushing the continue button.
602             $lastattempt = end($attempts);
603             $USER->modattempts[$lesson->id] = $lastattempt->pageid;
605             $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$pageid));
606         }
607         $lessoncontent .= html_writer::link($url, get_string('reviewlesson', 'lesson'),
608                 array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
609     } elseif ($lesson->modattempts && $canmanage) {
610         $lessoncontent .= $lessonoutput->paragraph(get_string("modattemptsnoteacher", "lesson"), 'centerpadded');
611     }
613     if ($lesson->activitylink) {
614         $lessoncontent .= $lesson->link_for_activitylink();
615     }
617     $url = new moodle_url('/course/view.php', array('id'=>$course->id));
618     $lessoncontent .= html_writer::link($url, get_string('returnto', 'lesson', format_string($course->fullname, true)),
619             array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
621     if (has_capability('gradereport/user:view', context_course::instance($course->id))
622             && $course->showgrades && $lesson->grade != 0 && !$lesson->practice) {
623         $url = new moodle_url('/grade/index.php', array('id' => $course->id));
624         $lessoncontent .= html_writer::link($url, get_string('viewgrades', 'lesson'),
625             array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
626     }
628     lesson_add_fake_blocks($PAGE, $cm, $lesson, $timer);
629     echo $lessonoutput->header($lesson, $cm, $currenttab, $extraeditbuttons, $lessonpageid, get_string("congratulations", "lesson"));
630     echo $lessoncontent;
631     echo $lessonoutput->footer();