[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/mod/lesson/ -> lib.php (source)

   1  <?php
   2  
   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/>.
  17  
  18  /**
  19   * Standard library of functions and constants for 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 later
  24   **/
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /* Do not include any libraries here! */
  29  
  30  /**
  31   * Given an object containing all the necessary data,
  32   * (defined by the form in mod_form.php) this function
  33   * will create a new instance and return the id number
  34   * of the new instance.
  35   *
  36   * @global object
  37   * @global object
  38   * @param object $lesson Lesson post data from the form
  39   * @return int
  40   **/
  41  function lesson_add_instance($data, $mform) {
  42      global $DB;
  43  
  44      $cmid = $data->coursemodule;
  45      $draftitemid = $data->mediafile;
  46      $context = context_module::instance($cmid);
  47  
  48      lesson_process_pre_save($data);
  49  
  50      unset($data->mediafile);
  51      $lessonid = $DB->insert_record("lesson", $data);
  52      $data->id = $lessonid;
  53  
  54      lesson_update_media_file($lessonid, $context, $draftitemid);
  55  
  56      lesson_process_post_save($data);
  57  
  58      lesson_grade_item_update($data);
  59  
  60      return $lessonid;
  61  }
  62  
  63  /**
  64   * Given an object containing all the necessary data,
  65   * (defined by the form in mod_form.php) this function
  66   * will update an existing instance with new data.
  67   *
  68   * @global object
  69   * @param object $lesson Lesson post data from the form
  70   * @return boolean
  71   **/
  72  function lesson_update_instance($data, $mform) {
  73      global $DB;
  74  
  75      $data->id = $data->instance;
  76      $cmid = $data->coursemodule;
  77      $draftitemid = $data->mediafile;
  78      $context = context_module::instance($cmid);
  79  
  80      lesson_process_pre_save($data);
  81  
  82      unset($data->mediafile);
  83      $DB->update_record("lesson", $data);
  84  
  85      lesson_update_media_file($data->id, $context, $draftitemid);
  86  
  87      lesson_process_post_save($data);
  88  
  89      // update grade item definition
  90      lesson_grade_item_update($data);
  91  
  92      // update grades - TODO: do it only when grading style changes
  93      lesson_update_grades($data, 0, false);
  94  
  95      return true;
  96  }
  97  
  98  /**
  99   * This function updates the events associated to the lesson.
 100   * If $override is non-zero, then it updates only the events
 101   * associated with the specified override.
 102   *
 103   * @uses LESSON_MAX_EVENT_LENGTH
 104   * @param object $lesson the lesson object.
 105   * @param object $override (optional) limit to a specific override
 106   */
 107  function lesson_update_events($lesson, $override = null) {
 108      global $CFG, $DB;
 109  
 110      require_once($CFG->dirroot . '/calendar/lib.php');
 111  
 112      // Load the old events relating to this lesson.
 113      $conds = array('modulename' => 'lesson',
 114                     'instance' => $lesson->id);
 115      if (!empty($override)) {
 116          // Only load events for this override.
 117          if (isset($override->userid)) {
 118              $conds['userid'] = $override->userid;
 119          } else {
 120              $conds['groupid'] = $override->groupid;
 121          }
 122      }
 123      $oldevents = $DB->get_records('event', $conds);
 124  
 125      // Now make a todo list of all that needs to be updated.
 126      if (empty($override)) {
 127          // We are updating the primary settings for the lesson, so we
 128          // need to add all the overrides.
 129          $overrides = $DB->get_records('lesson_overrides', array('lessonid' => $lesson->id));
 130          // As well as the original lesson (empty override).
 131          $overrides[] = new stdClass();
 132      } else {
 133          // Just do the one override.
 134          $overrides = array($override);
 135      }
 136  
 137      foreach ($overrides as $current) {
 138          $groupid   = isset($current->groupid) ? $current->groupid : 0;
 139          $userid    = isset($current->userid) ? $current->userid : 0;
 140          $available  = isset($current->available) ? $current->available : $lesson->available;
 141          $deadline = isset($current->deadline) ? $current->deadline : $lesson->deadline;
 142  
 143          // Only add open/close events for an override if they differ from the lesson default.
 144          $addopen  = empty($current->id) || !empty($current->available);
 145          $addclose = empty($current->id) || !empty($current->deadline);
 146  
 147          if (!empty($lesson->coursemodule)) {
 148              $cmid = $lesson->coursemodule;
 149          } else {
 150              $cmid = get_coursemodule_from_instance('lesson', $lesson->id, $lesson->course)->id;
 151          }
 152  
 153          $event = new stdClass();
 154          $event->description = format_module_intro('lesson', $lesson, $cmid);
 155          // Events module won't show user events when the courseid is nonzero.
 156          $event->courseid    = ($userid) ? 0 : $lesson->course;
 157          $event->groupid     = $groupid;
 158          $event->userid      = $userid;
 159          $event->modulename  = 'lesson';
 160          $event->instance    = $lesson->id;
 161          $event->timestart   = $available;
 162          $event->timeduration = max($deadline - $available, 0);
 163          $event->visible     = instance_is_visible('lesson', $lesson);
 164          $event->eventtype   = 'open';
 165  
 166          // Determine the event name.
 167          if ($groupid) {
 168              $params = new stdClass();
 169              $params->lesson = $lesson->name;
 170              $params->group = groups_get_group_name($groupid);
 171              if ($params->group === false) {
 172                  // Group doesn't exist, just skip it.
 173                  continue;
 174              }
 175              $eventname = get_string('overridegroupeventname', 'lesson', $params);
 176          } else if ($userid) {
 177              $params = new stdClass();
 178              $params->lesson = $lesson->name;
 179              $eventname = get_string('overrideusereventname', 'lesson', $params);
 180          } else {
 181              $eventname = $lesson->name;
 182          }
 183          if ($addopen or $addclose) {
 184              if ($deadline and $available and $event->timeduration <= LESSON_MAX_EVENT_LENGTH) {
 185                  // Single event for the whole lesson.
 186                  if ($oldevent = array_shift($oldevents)) {
 187                      $event->id = $oldevent->id;
 188                  } else {
 189                      unset($event->id);
 190                  }
 191                  $event->name = $eventname;
 192                  // The method calendar_event::create will reuse a db record if the id field is set.
 193                  calendar_event::create($event);
 194              } else {
 195                  // Separate start and end events.
 196                  $event->timeduration  = 0;
 197                  if ($available && $addopen) {
 198                      if ($oldevent = array_shift($oldevents)) {
 199                          $event->id = $oldevent->id;
 200                      } else {
 201                          unset($event->id);
 202                      }
 203                      $event->name = $eventname.' ('.get_string('lessonopens', 'lesson').')';
 204                      // The method calendar_event::create will reuse a db record if the id field is set.
 205                      calendar_event::create($event);
 206                  }
 207                  if ($deadline && $addclose) {
 208                      if ($oldevent = array_shift($oldevents)) {
 209                          $event->id = $oldevent->id;
 210                      } else {
 211                          unset($event->id);
 212                      }
 213                      $event->name      = $eventname.' ('.get_string('lessoncloses', 'lesson').')';
 214                      $event->timestart = $deadline;
 215                      $event->eventtype = 'close';
 216                      calendar_event::create($event);
 217                  }
 218              }
 219          }
 220      }
 221  
 222      // Delete any leftover events.
 223      foreach ($oldevents as $badevent) {
 224          $badevent = calendar_event::load($badevent);
 225          $badevent->delete();
 226      }
 227  }
 228  
 229  /**
 230   * This standard function will check all instances of this module
 231   * and make sure there are up-to-date events created for each of them.
 232   * If courseid = 0, then every lesson event in the site is checked, else
 233   * only lesson events belonging to the course specified are checked.
 234   * This function is used, in its new format, by restore_refresh_events()
 235   *
 236   * @param int $courseid
 237   * @return bool
 238   */
 239  function lesson_refresh_events($courseid = 0) {
 240      global $DB;
 241  
 242      if ($courseid == 0) {
 243          if (!$lessons = $DB->get_records('lessons')) {
 244              return true;
 245          }
 246      } else {
 247          if (!$lessons = $DB->get_records('lesson', array('course' => $courseid))) {
 248              return true;
 249          }
 250      }
 251  
 252      foreach ($lessons as $lesson) {
 253          lesson_update_events($lesson);
 254      }
 255  
 256      return true;
 257  }
 258  
 259  /**
 260   * Given an ID of an instance of this module,
 261   * this function will permanently delete the instance
 262   * and any data that depends on it.
 263   *
 264   * @global object
 265   * @param int $id
 266   * @return bool
 267   */
 268  function lesson_delete_instance($id) {
 269      global $DB, $CFG;
 270      require_once($CFG->dirroot . '/mod/lesson/locallib.php');
 271  
 272      $lesson = $DB->get_record("lesson", array("id"=>$id), '*', MUST_EXIST);
 273      $lesson = new lesson($lesson);
 274      return $lesson->delete();
 275  }
 276  
 277  /**
 278   * Return a small object with summary information about what a
 279   * user has done with a given particular instance of this module
 280   * Used for user activity reports.
 281   * $return->time = the time they did it
 282   * $return->info = a short text description
 283   *
 284   * @global object
 285   * @param object $course
 286   * @param object $user
 287   * @param object $mod
 288   * @param object $lesson
 289   * @return object
 290   */
 291  function lesson_user_outline($course, $user, $mod, $lesson) {
 292      global $CFG, $DB;
 293  
 294      require_once("$CFG->libdir/gradelib.php");
 295      $grades = grade_get_grades($course->id, 'mod', 'lesson', $lesson->id, $user->id);
 296      $return = new stdClass();
 297  
 298      if (empty($grades->items[0]->grades)) {
 299          $return->info = get_string("nolessonattempts", "lesson");
 300      } else {
 301          $grade = reset($grades->items[0]->grades);
 302          if (empty($grade->grade)) {
 303  
 304              // Check to see if it an ungraded / incomplete attempt.
 305              $sql = "SELECT *
 306                        FROM {lesson_timer}
 307                       WHERE lessonid = :lessonid
 308                         AND userid = :userid
 309                    ORDER BY starttime DESC";
 310              $params = array('lessonid' => $lesson->id, 'userid' => $user->id);
 311  
 312              if ($attempts = $DB->get_records_sql($sql, $params, 0, 1)) {
 313                  $attempt = reset($attempts);
 314                  if ($attempt->completed) {
 315                      $return->info = get_string("completed", "lesson");
 316                  } else {
 317                      $return->info = get_string("notyetcompleted", "lesson");
 318                  }
 319                  $return->time = $attempt->lessontime;
 320              } else {
 321                  $return->info = get_string("nolessonattempts", "lesson");
 322              }
 323          } else {
 324              $return->info = get_string("grade") . ': ' . $grade->str_long_grade;
 325  
 326              // Datesubmitted == time created. dategraded == time modified or time overridden.
 327              // If grade was last modified by the user themselves use date graded. Otherwise use date submitted.
 328              // TODO: move this copied & pasted code somewhere in the grades API. See MDL-26704.
 329              if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) {
 330                  $return->time = $grade->dategraded;
 331              } else {
 332                  $return->time = $grade->datesubmitted;
 333              }
 334          }
 335      }
 336      return $return;
 337  }
 338  
 339  /**
 340   * Print a detailed representation of what a  user has done with
 341   * a given particular instance of this module, for user activity reports.
 342   *
 343   * @global object
 344   * @param object $course
 345   * @param object $user
 346   * @param object $mod
 347   * @param object $lesson
 348   * @return bool
 349   */
 350  function lesson_user_complete($course, $user, $mod, $lesson) {
 351      global $DB, $OUTPUT, $CFG;
 352  
 353      require_once("$CFG->libdir/gradelib.php");
 354  
 355      $grades = grade_get_grades($course->id, 'mod', 'lesson', $lesson->id, $user->id);
 356  
 357      // Display the grade and feedback.
 358      if (empty($grades->items[0]->grades)) {
 359          echo $OUTPUT->container(get_string("nolessonattempts", "lesson"));
 360      } else {
 361          $grade = reset($grades->items[0]->grades);
 362          if (empty($grade->grade)) {
 363              // Check to see if it an ungraded / incomplete attempt.
 364              $sql = "SELECT *
 365                        FROM {lesson_timer}
 366                       WHERE lessonid = :lessonid
 367                         AND userid = :userid
 368                       ORDER by starttime desc";
 369              $params = array('lessonid' => $lesson->id, 'userid' => $user->id);
 370  
 371              if ($attempt = $DB->get_record_sql($sql, $params, IGNORE_MULTIPLE)) {
 372                  if ($attempt->completed) {
 373                      $status = get_string("completed", "lesson");
 374                  } else {
 375                      $status = get_string("notyetcompleted", "lesson");
 376                  }
 377              } else {
 378                  $status = get_string("nolessonattempts", "lesson");
 379              }
 380          } else {
 381              $status = get_string("grade") . ': ' . $grade->str_long_grade;
 382          }
 383  
 384          // Display the grade or lesson status if there isn't one.
 385          echo $OUTPUT->container($status);
 386  
 387          if ($grade->str_feedback) {
 388              echo $OUTPUT->container(get_string('feedback').': '.$grade->str_feedback);
 389          }
 390      }
 391  
 392      // Display the lesson progress.
 393      // Attempt, pages viewed, questions answered, correct answers, time.
 394      $params = array ("lessonid" => $lesson->id, "userid" => $user->id);
 395      $attempts = $DB->get_records_select("lesson_attempts", "lessonid = :lessonid AND userid = :userid", $params, "retry, timeseen");
 396      $branches = $DB->get_records_select("lesson_branch", "lessonid = :lessonid AND userid = :userid", $params, "retry, timeseen");
 397      if (!empty($attempts) or !empty($branches)) {
 398          echo $OUTPUT->box_start();
 399          $table = new html_table();
 400          // Table Headings.
 401          $table->head = array (get_string("attemptheader", "lesson"),
 402              get_string("totalpagesviewedheader", "lesson"),
 403              get_string("numberofpagesviewedheader", "lesson"),
 404              get_string("numberofcorrectanswersheader", "lesson"),
 405              get_string("time"));
 406          $table->width = "100%";
 407          $table->align = array ("center", "center", "center", "center", "center");
 408          $table->size = array ("*", "*", "*", "*", "*");
 409          $table->cellpadding = 2;
 410          $table->cellspacing = 0;
 411  
 412          $retry = 0;
 413          $nquestions = 0;
 414          $npages = 0;
 415          $ncorrect = 0;
 416  
 417          // Filter question pages (from lesson_attempts).
 418          foreach ($attempts as $attempt) {
 419              if ($attempt->retry == $retry) {
 420                  $npages++;
 421                  $nquestions++;
 422                  if ($attempt->correct) {
 423                      $ncorrect++;
 424                  }
 425                  $timeseen = $attempt->timeseen;
 426              } else {
 427                  $table->data[] = array($retry + 1, $npages, $nquestions, $ncorrect, userdate($timeseen));
 428                  $retry++;
 429                  $nquestions = 1;
 430                  $npages = 1;
 431                  if ($attempt->correct) {
 432                      $ncorrect = 1;
 433                  } else {
 434                      $ncorrect = 0;
 435                  }
 436              }
 437          }
 438  
 439          // Filter content pages (from lesson_branch).
 440          foreach ($branches as $branch) {
 441              if ($branch->retry == $retry) {
 442                  $npages++;
 443  
 444                  $timeseen = $branch->timeseen;
 445              } else {
 446                  $table->data[] = array($retry + 1, $npages, $nquestions, $ncorrect, userdate($timeseen));
 447                  $retry++;
 448                  $npages = 1;
 449              }
 450          }
 451          if ($npages > 0) {
 452                  $table->data[] = array($retry + 1, $npages, $nquestions, $ncorrect, userdate($timeseen));
 453          }
 454          echo html_writer::table($table);
 455          echo $OUTPUT->box_end();
 456      }
 457  
 458      return true;
 459  }
 460  
 461  /**
 462   * Prints lesson summaries on MyMoodle Page
 463   *
 464   * Prints lesson name, due date and attempt information on
 465   * lessons that have a deadline that has not already passed
 466   * and it is available for taking.
 467   *
 468   * @global object
 469   * @global stdClass
 470   * @global object
 471   * @uses CONTEXT_MODULE
 472   * @param array $courses An array of course objects to get lesson instances from
 473   * @param array $htmlarray Store overview output array( course ID => 'lesson' => HTML output )
 474   * @return void
 475   */
 476  function lesson_print_overview($courses, &$htmlarray) {
 477      global $USER, $CFG, $DB, $OUTPUT;
 478  
 479      if (!$lessons = get_all_instances_in_courses('lesson', $courses)) {
 480          return;
 481      }
 482  
 483      // Get all of the current users attempts on all lessons.
 484      $params = array($USER->id);
 485      $sql = 'SELECT lessonid, userid, count(userid) as attempts
 486                FROM {lesson_grades}
 487               WHERE userid = ?
 488            GROUP BY lessonid, userid';
 489      $allattempts = $DB->get_records_sql($sql, $params);
 490      $completedattempts = array();
 491      foreach ($allattempts as $myattempt) {
 492          $completedattempts[$myattempt->lessonid] = $myattempt->attempts;
 493      }
 494  
 495      // Get the current course ID.
 496      $listoflessons = array();
 497      foreach ($lessons as $lesson) {
 498          $listoflessons[] = $lesson->id;
 499      }
 500      // Get the last page viewed by the current user for every lesson in this course.
 501      list($insql, $inparams) = $DB->get_in_or_equal($listoflessons, SQL_PARAMS_NAMED);
 502      $dbparams = array_merge($inparams, array('userid' => $USER->id));
 503  
 504      // Get the lesson attempts for the user that have the maximum 'timeseen' value.
 505      $select = "SELECT l.id, l.timeseen, l.lessonid, l.userid, l.retry, l.pageid, l.answerid as nextpageid, p.qtype ";
 506      $from = "FROM {lesson_attempts} l
 507               JOIN (
 508                     SELECT idselect.lessonid, idselect.userid, MAX(idselect.id) AS id
 509                       FROM {lesson_attempts} idselect
 510                       JOIN (
 511                             SELECT lessonid, userid, MAX(timeseen) AS timeseen
 512                               FROM {lesson_attempts}
 513                              WHERE userid = :userid
 514                                AND lessonid $insql
 515                           GROUP BY userid, lessonid
 516                             ) timeselect
 517                         ON timeselect.timeseen = idselect.timeseen
 518                        AND timeselect.userid = idselect.userid
 519                        AND timeselect.lessonid = idselect.lessonid
 520                   GROUP BY idselect.userid, idselect.lessonid
 521                     ) aid
 522                 ON l.id = aid.id
 523               JOIN {lesson_pages} p
 524                 ON l.pageid = p.id ";
 525      $lastattempts = $DB->get_records_sql($select . $from, $dbparams);
 526  
 527      // Now, get the lesson branches for the user that have the maximum 'timeseen' value.
 528      $select = "SELECT l.id, l.timeseen, l.lessonid, l.userid, l.retry, l.pageid, l.nextpageid, p.qtype ";
 529      $from = str_replace('{lesson_attempts}', '{lesson_branch}', $from);
 530      $lastbranches = $DB->get_records_sql($select . $from, $dbparams);
 531  
 532      $lastviewed = array();
 533      foreach ($lastattempts as $lastattempt) {
 534          $lastviewed[$lastattempt->lessonid] = $lastattempt;
 535      }
 536  
 537      // Go through the branch times and record the 'timeseen' value if it doesn't exist
 538      // for the lesson, or replace it if it exceeds the current recorded time.
 539      foreach ($lastbranches as $lastbranch) {
 540          if (!isset($lastviewed[$lastbranch->lessonid])) {
 541              $lastviewed[$lastbranch->lessonid] = $lastbranch;
 542          } else if ($lastviewed[$lastbranch->lessonid]->timeseen < $lastbranch->timeseen) {
 543              $lastviewed[$lastbranch->lessonid] = $lastbranch;
 544          }
 545      }
 546  
 547      // Since we have lessons in this course, now include the constants we need.
 548      require_once($CFG->dirroot . '/mod/lesson/locallib.php');
 549  
 550      $now = time();
 551      foreach ($lessons as $lesson) {
 552          if ($lesson->deadline != 0                                         // The lesson has a deadline
 553              and $lesson->deadline >= $now                                  // And it is before the deadline has been met
 554              and ($lesson->available == 0 or $lesson->available <= $now)) { // And the lesson is available
 555  
 556              // Visibility.
 557              $class = (!$lesson->visible) ? 'dimmed' : '';
 558  
 559              // Context.
 560              $context = context_module::instance($lesson->coursemodule);
 561  
 562              // Link to activity.
 563              $url = new moodle_url('/mod/lesson/view.php', array('id' => $lesson->coursemodule));
 564              $url = html_writer::link($url, format_string($lesson->name, true, array('context' => $context)), array('class' => $class));
 565              $str = $OUTPUT->box(get_string('lessonname', 'lesson', $url), 'name');
 566  
 567              // Deadline.
 568              $str .= $OUTPUT->box(get_string('lessoncloseson', 'lesson', userdate($lesson->deadline)), 'info');
 569  
 570              // Attempt information.
 571              if (has_capability('mod/lesson:manage', $context)) {
 572                  // This is a teacher, Get the Number of user attempts.
 573                  $attempts = $DB->count_records('lesson_grades', array('lessonid' => $lesson->id));
 574                  $str     .= $OUTPUT->box(get_string('xattempts', 'lesson', $attempts), 'info');
 575                  $str      = $OUTPUT->box($str, 'lesson overview');
 576              } else {
 577                  // This is a student, See if the user has at least started the lesson.
 578                  if (isset($lastviewed[$lesson->id]->timeseen)) {
 579                      // See if the user has finished this attempt.
 580                      if (isset($completedattempts[$lesson->id]) &&
 581                               ($completedattempts[$lesson->id] == ($lastviewed[$lesson->id]->retry + 1))) {
 582                          // Are additional attempts allowed?
 583                          if ($lesson->retake) {
 584                              // User can retake the lesson.
 585                              $str .= $OUTPUT->box(get_string('additionalattemptsremaining', 'lesson'), 'info');
 586                              $str = $OUTPUT->box($str, 'lesson overview');
 587                          } else {
 588                              // User has completed the lesson and no retakes are allowed.
 589                              $str = '';
 590                          }
 591  
 592                      } else {
 593                          // The last attempt was not finished or the lesson does not contain questions.
 594                          // See if the last page viewed was a branchtable.
 595                          require_once($CFG->dirroot . '/mod/lesson/pagetypes/branchtable.php');
 596                          if ($lastviewed[$lesson->id]->qtype == LESSON_PAGE_BRANCHTABLE) {
 597                              // See if the next pageid is the end of lesson.
 598                              if ($lastviewed[$lesson->id]->nextpageid == LESSON_EOL) {
 599                                  // The last page viewed was the End of Lesson.
 600                                  if ($lesson->retake) {
 601                                      // User can retake the lesson.
 602                                      $str .= $OUTPUT->box(get_string('additionalattemptsremaining', 'lesson'), 'info');
 603                                      $str = $OUTPUT->box($str, 'lesson overview');
 604                                  } else {
 605                                      // User has completed the lesson and no retakes are allowed.
 606                                      $str = '';
 607                                  }
 608  
 609                              } else {
 610                                  // The last page viewed was NOT the end of lesson.
 611                                  $str .= $OUTPUT->box(get_string('notyetcompleted', 'lesson'), 'info');
 612                                  $str = $OUTPUT->box($str, 'lesson overview');
 613                              }
 614  
 615                          } else {
 616                              // Last page was a question page, so the attempt is not completed yet.
 617                              $str .= $OUTPUT->box(get_string('notyetcompleted', 'lesson'), 'info');
 618                              $str = $OUTPUT->box($str, 'lesson overview');
 619                          }
 620                      }
 621  
 622                  } else {
 623                      // User has not yet started this lesson.
 624                      $str .= $OUTPUT->box(get_string('nolessonattempts', 'lesson'), 'info');
 625                      $str = $OUTPUT->box($str, 'lesson overview');
 626                  }
 627              }
 628              if (!empty($str)) {
 629                  if (empty($htmlarray[$lesson->course]['lesson'])) {
 630                      $htmlarray[$lesson->course]['lesson'] = $str;
 631                  } else {
 632                      $htmlarray[$lesson->course]['lesson'] .= $str;
 633                  }
 634              }
 635          }
 636      }
 637  }
 638  
 639  /**
 640   * Function to be run periodically according to the moodle cron
 641   * This function searches for things that need to be done, such
 642   * as sending out mail, toggling flags etc ...
 643   * @global stdClass
 644   * @return bool true
 645   */
 646  function lesson_cron () {
 647      global $CFG;
 648  
 649      return true;
 650  }
 651  
 652  /**
 653   * Return grade for given user or all users.
 654   *
 655   * @global stdClass
 656   * @global object
 657   * @param int $lessonid id of lesson
 658   * @param int $userid optional user id, 0 means all users
 659   * @return array array of grades, false if none
 660   */
 661  function lesson_get_user_grades($lesson, $userid=0) {
 662      global $CFG, $DB;
 663  
 664      $params = array("lessonid" => $lesson->id,"lessonid2" => $lesson->id);
 665  
 666      if (!empty($userid)) {
 667          $params["userid"] = $userid;
 668          $params["userid2"] = $userid;
 669          $user = "AND u.id = :userid";
 670          $fuser = "AND uu.id = :userid2";
 671      }
 672      else {
 673          $user="";
 674          $fuser="";
 675      }
 676  
 677      if ($lesson->retake) {
 678          if ($lesson->usemaxgrade) {
 679              $sql = "SELECT u.id, u.id AS userid, MAX(g.grade) AS rawgrade
 680                        FROM {user} u, {lesson_grades} g
 681                       WHERE u.id = g.userid AND g.lessonid = :lessonid
 682                             $user
 683                    GROUP BY u.id";
 684          } else {
 685              $sql = "SELECT u.id, u.id AS userid, AVG(g.grade) AS rawgrade
 686                        FROM {user} u, {lesson_grades} g
 687                       WHERE u.id = g.userid AND g.lessonid = :lessonid
 688                             $user
 689                    GROUP BY u.id";
 690          }
 691          unset($params['lessonid2']);
 692          unset($params['userid2']);
 693      } else {
 694          // use only first attempts (with lowest id in lesson_grades table)
 695          $firstonly = "SELECT uu.id AS userid, MIN(gg.id) AS firstcompleted
 696                          FROM {user} uu, {lesson_grades} gg
 697                         WHERE uu.id = gg.userid AND gg.lessonid = :lessonid2
 698                               $fuser
 699                         GROUP BY uu.id";
 700  
 701          $sql = "SELECT u.id, u.id AS userid, g.grade AS rawgrade
 702                    FROM {user} u, {lesson_grades} g, ($firstonly) f
 703                   WHERE u.id = g.userid AND g.lessonid = :lessonid
 704                         AND g.id = f.firstcompleted AND g.userid=f.userid
 705                         $user";
 706      }
 707  
 708      return $DB->get_records_sql($sql, $params);
 709  }
 710  
 711  /**
 712   * Update grades in central gradebook
 713   *
 714   * @category grade
 715   * @param object $lesson
 716   * @param int $userid specific user only, 0 means all
 717   * @param bool $nullifnone
 718   */
 719  function lesson_update_grades($lesson, $userid=0, $nullifnone=true) {
 720      global $CFG, $DB;
 721      require_once($CFG->libdir.'/gradelib.php');
 722  
 723      if ($lesson->grade == 0 || $lesson->practice) {
 724          lesson_grade_item_update($lesson);
 725  
 726      } else if ($grades = lesson_get_user_grades($lesson, $userid)) {
 727          lesson_grade_item_update($lesson, $grades);
 728  
 729      } else if ($userid and $nullifnone) {
 730          $grade = new stdClass();
 731          $grade->userid   = $userid;
 732          $grade->rawgrade = null;
 733          lesson_grade_item_update($lesson, $grade);
 734  
 735      } else {
 736          lesson_grade_item_update($lesson);
 737      }
 738  }
 739  
 740  /**
 741   * Create grade item for given lesson
 742   *
 743   * @category grade
 744   * @uses GRADE_TYPE_VALUE
 745   * @uses GRADE_TYPE_NONE
 746   * @param object $lesson object with extra cmidnumber
 747   * @param array|object $grades optional array/object of grade(s); 'reset' means reset grades in gradebook
 748   * @return int 0 if ok, error code otherwise
 749   */
 750  function lesson_grade_item_update($lesson, $grades=null) {
 751      global $CFG;
 752      if (!function_exists('grade_update')) { //workaround for buggy PHP versions
 753          require_once($CFG->libdir.'/gradelib.php');
 754      }
 755  
 756      if (array_key_exists('cmidnumber', $lesson)) { //it may not be always present
 757          $params = array('itemname'=>$lesson->name, 'idnumber'=>$lesson->cmidnumber);
 758      } else {
 759          $params = array('itemname'=>$lesson->name);
 760      }
 761  
 762      if (!$lesson->practice and $lesson->grade > 0) {
 763          $params['gradetype']  = GRADE_TYPE_VALUE;
 764          $params['grademax']   = $lesson->grade;
 765          $params['grademin']   = 0;
 766      } else if (!$lesson->practice and $lesson->grade < 0) {
 767          $params['gradetype']  = GRADE_TYPE_SCALE;
 768          $params['scaleid']   = -$lesson->grade;
 769  
 770          // Make sure current grade fetched correctly from $grades
 771          $currentgrade = null;
 772          if (!empty($grades)) {
 773              if (is_array($grades)) {
 774                  $currentgrade = reset($grades);
 775              } else {
 776                  $currentgrade = $grades;
 777              }
 778          }
 779  
 780          // When converting a score to a scale, use scale's grade maximum to calculate it.
 781          if (!empty($currentgrade) && $currentgrade->rawgrade !== null) {
 782              $grade = grade_get_grades($lesson->course, 'mod', 'lesson', $lesson->id, $currentgrade->userid);
 783              $params['grademax']   = reset($grade->items)->grademax;
 784          }
 785      } else {
 786          $params['gradetype']  = GRADE_TYPE_NONE;
 787      }
 788  
 789      if ($grades  === 'reset') {
 790          $params['reset'] = true;
 791          $grades = null;
 792      } else if (!empty($grades)) {
 793          // Need to calculate raw grade (Note: $grades has many forms)
 794          if (is_object($grades)) {
 795              $grades = array($grades->userid => $grades);
 796          } else if (array_key_exists('userid', $grades)) {
 797              $grades = array($grades['userid'] => $grades);
 798          }
 799          foreach ($grades as $key => $grade) {
 800              if (!is_array($grade)) {
 801                  $grades[$key] = $grade = (array) $grade;
 802              }
 803              //check raw grade isnt null otherwise we erroneously insert a grade of 0
 804              if ($grade['rawgrade'] !== null) {
 805                  $grades[$key]['rawgrade'] = ($grade['rawgrade'] * $params['grademax'] / 100);
 806              } else {
 807                  //setting rawgrade to null just in case user is deleting a grade
 808                  $grades[$key]['rawgrade'] = null;
 809              }
 810          }
 811      }
 812  
 813      return grade_update('mod/lesson', $lesson->course, 'mod', 'lesson', $lesson->id, 0, $grades, $params);
 814  }
 815  
 816  /**
 817   * List the actions that correspond to a view of this module.
 818   * This is used by the participation report.
 819   *
 820   * Note: This is not used by new logging system. Event with
 821   *       crud = 'r' and edulevel = LEVEL_PARTICIPATING will
 822   *       be considered as view action.
 823   *
 824   * @return array
 825   */
 826  function lesson_get_view_actions() {
 827      return array('view','view all');
 828  }
 829  
 830  /**
 831   * List the actions that correspond to a post of this module.
 832   * This is used by the participation report.
 833   *
 834   * Note: This is not used by new logging system. Event with
 835   *       crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
 836   *       will be considered as post action.
 837   *
 838   * @return array
 839   */
 840  function lesson_get_post_actions() {
 841      return array('end','start');
 842  }
 843  
 844  /**
 845   * Runs any processes that must run before
 846   * a lesson insert/update
 847   *
 848   * @global object
 849   * @param object $lesson Lesson form data
 850   * @return void
 851   **/
 852  function lesson_process_pre_save(&$lesson) {
 853      global $DB;
 854  
 855      $lesson->timemodified = time();
 856  
 857      if (empty($lesson->timelimit)) {
 858          $lesson->timelimit = 0;
 859      }
 860      if (empty($lesson->timespent) or !is_numeric($lesson->timespent) or $lesson->timespent < 0) {
 861          $lesson->timespent = 0;
 862      }
 863      if (!isset($lesson->completed)) {
 864          $lesson->completed = 0;
 865      }
 866      if (empty($lesson->gradebetterthan) or !is_numeric($lesson->gradebetterthan) or $lesson->gradebetterthan < 0) {
 867          $lesson->gradebetterthan = 0;
 868      } else if ($lesson->gradebetterthan > 100) {
 869          $lesson->gradebetterthan = 100;
 870      }
 871  
 872      if (empty($lesson->width)) {
 873          $lesson->width = 640;
 874      }
 875      if (empty($lesson->height)) {
 876          $lesson->height = 480;
 877      }
 878      if (empty($lesson->bgcolor)) {
 879          $lesson->bgcolor = '#FFFFFF';
 880      }
 881  
 882      // Conditions for dependency
 883      $conditions = new stdClass;
 884      $conditions->timespent = $lesson->timespent;
 885      $conditions->completed = $lesson->completed;
 886      $conditions->gradebetterthan = $lesson->gradebetterthan;
 887      $lesson->conditions = serialize($conditions);
 888      unset($lesson->timespent);
 889      unset($lesson->completed);
 890      unset($lesson->gradebetterthan);
 891  
 892      if (empty($lesson->password)) {
 893          unset($lesson->password);
 894      }
 895  }
 896  
 897  /**
 898   * Runs any processes that must be run
 899   * after a lesson insert/update
 900   *
 901   * @global object
 902   * @param object $lesson Lesson form data
 903   * @return void
 904   **/
 905  function lesson_process_post_save(&$lesson) {
 906      // Update the events relating to this lesson.
 907      lesson_update_events($lesson);
 908  }
 909  
 910  
 911  /**
 912   * Implementation of the function for printing the form elements that control
 913   * whether the course reset functionality affects the lesson.
 914   *
 915   * @param $mform form passed by reference
 916   */
 917  function lesson_reset_course_form_definition(&$mform) {
 918      $mform->addElement('header', 'lessonheader', get_string('modulenameplural', 'lesson'));
 919      $mform->addElement('advcheckbox', 'reset_lesson', get_string('deleteallattempts','lesson'));
 920      $mform->addElement('advcheckbox', 'reset_lesson_user_overrides',
 921              get_string('removealluseroverrides', 'lesson'));
 922      $mform->addElement('advcheckbox', 'reset_lesson_group_overrides',
 923              get_string('removeallgroupoverrides', 'lesson'));
 924  }
 925  
 926  /**
 927   * Course reset form defaults.
 928   * @param object $course
 929   * @return array
 930   */
 931  function lesson_reset_course_form_defaults($course) {
 932      return array('reset_lesson' => 1,
 933              'reset_lesson_group_overrides' => 1,
 934              'reset_lesson_user_overrides' => 1);
 935  }
 936  
 937  /**
 938   * Removes all grades from gradebook
 939   *
 940   * @global stdClass
 941   * @global object
 942   * @param int $courseid
 943   * @param string optional type
 944   */
 945  function lesson_reset_gradebook($courseid, $type='') {
 946      global $CFG, $DB;
 947  
 948      $sql = "SELECT l.*, cm.idnumber as cmidnumber, l.course as courseid
 949                FROM {lesson} l, {course_modules} cm, {modules} m
 950               WHERE m.name='lesson' AND m.id=cm.module AND cm.instance=l.id AND l.course=:course";
 951      $params = array ("course" => $courseid);
 952      if ($lessons = $DB->get_records_sql($sql,$params)) {
 953          foreach ($lessons as $lesson) {
 954              lesson_grade_item_update($lesson, 'reset');
 955          }
 956      }
 957  }
 958  
 959  /**
 960   * Actual implementation of the reset course functionality, delete all the
 961   * lesson attempts for course $data->courseid.
 962   *
 963   * @global stdClass
 964   * @global object
 965   * @param object $data the data submitted from the reset course.
 966   * @return array status array
 967   */
 968  function lesson_reset_userdata($data) {
 969      global $CFG, $DB;
 970  
 971      $componentstr = get_string('modulenameplural', 'lesson');
 972      $status = array();
 973  
 974      if (!empty($data->reset_lesson)) {
 975          $lessonssql = "SELECT l.id
 976                           FROM {lesson} l
 977                          WHERE l.course=:course";
 978  
 979          $params = array ("course" => $data->courseid);
 980          $lessons = $DB->get_records_sql($lessonssql, $params);
 981  
 982          // Get rid of attempts files.
 983          $fs = get_file_storage();
 984          if ($lessons) {
 985              foreach ($lessons as $lessonid => $unused) {
 986                  if (!$cm = get_coursemodule_from_instance('lesson', $lessonid)) {
 987                      continue;
 988                  }
 989                  $context = context_module::instance($cm->id);
 990                  $fs->delete_area_files($context->id, 'mod_lesson', 'essay_responses');
 991              }
 992          }
 993  
 994          $DB->delete_records_select('lesson_timer', "lessonid IN ($lessonssql)", $params);
 995          $DB->delete_records_select('lesson_grades', "lessonid IN ($lessonssql)", $params);
 996          $DB->delete_records_select('lesson_attempts', "lessonid IN ($lessonssql)", $params);
 997          $DB->delete_records_select('lesson_branch', "lessonid IN ($lessonssql)", $params);
 998  
 999          // remove all grades from gradebook
1000          if (empty($data->reset_gradebook_grades)) {
1001              lesson_reset_gradebook($data->courseid);
1002          }
1003  
1004          $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallattempts', 'lesson'), 'error'=>false);
1005      }
1006  
1007      // Remove user overrides.
1008      if (!empty($data->reset_lesson_user_overrides)) {
1009          $DB->delete_records_select('lesson_overrides',
1010                  'lessonid IN (SELECT id FROM {lesson} WHERE course = ?) AND userid IS NOT NULL', array($data->courseid));
1011          $status[] = array(
1012          'component' => $componentstr,
1013          'item' => get_string('useroverridesdeleted', 'lesson'),
1014          'error' => false);
1015      }
1016      // Remove group overrides.
1017      if (!empty($data->reset_lesson_group_overrides)) {
1018          $DB->delete_records_select('lesson_overrides',
1019          'lessonid IN (SELECT id FROM {lesson} WHERE course = ?) AND groupid IS NOT NULL', array($data->courseid));
1020          $status[] = array(
1021          'component' => $componentstr,
1022          'item' => get_string('groupoverridesdeleted', 'lesson'),
1023          'error' => false);
1024      }
1025      /// updating dates - shift may be negative too
1026      if ($data->timeshift) {
1027          $DB->execute("UPDATE {lesson_overrides}
1028                           SET available = available + ?
1029                         WHERE lessonid IN (SELECT id FROM {lesson} WHERE course = ?)
1030                           AND available <> 0", array($data->timeshift, $data->courseid));
1031          $DB->execute("UPDATE {lesson_overrides}
1032                           SET deadline = deadline + ?
1033                         WHERE lessonid IN (SELECT id FROM {lesson} WHERE course = ?)
1034                           AND deadline <> 0", array($data->timeshift, $data->courseid));
1035  
1036          shift_course_mod_dates('lesson', array('available', 'deadline'), $data->timeshift, $data->courseid);
1037          $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged'), 'error'=>false);
1038      }
1039  
1040      return $status;
1041  }
1042  
1043  /**
1044   * Returns all other caps used in module
1045   * @return array
1046   */
1047  function lesson_get_extra_capabilities() {
1048      return array('moodle/site:accessallgroups');
1049  }
1050  
1051  /**
1052   * @uses FEATURE_GROUPS
1053   * @uses FEATURE_GROUPINGS
1054   * @uses FEATURE_MOD_INTRO
1055   * @uses FEATURE_COMPLETION_TRACKS_VIEWS
1056   * @uses FEATURE_GRADE_HAS_GRADE
1057   * @uses FEATURE_GRADE_OUTCOMES
1058   * @param string $feature FEATURE_xx constant for requested feature
1059   * @return mixed True if module supports feature, false if not, null if doesn't know
1060   */
1061  function lesson_supports($feature) {
1062      switch($feature) {
1063          case FEATURE_GROUPS:
1064              return true;
1065          case FEATURE_GROUPINGS:
1066              return true;
1067          case FEATURE_MOD_INTRO:
1068              return true;
1069          case FEATURE_COMPLETION_TRACKS_VIEWS:
1070              return true;
1071          case FEATURE_GRADE_HAS_GRADE:
1072              return true;
1073          case FEATURE_COMPLETION_HAS_RULES:
1074              return true;
1075          case FEATURE_GRADE_OUTCOMES:
1076              return true;
1077          case FEATURE_BACKUP_MOODLE2:
1078              return true;
1079          case FEATURE_SHOW_DESCRIPTION:
1080              return true;
1081          default:
1082              return null;
1083      }
1084  }
1085  
1086  /**
1087   * Obtains the automatic completion state for this lesson based on any conditions
1088   * in lesson settings.
1089   *
1090   * @param object $course Course
1091   * @param object $cm course-module
1092   * @param int $userid User ID
1093   * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
1094   * @return bool True if completed, false if not, $type if conditions not set.
1095   */
1096  function lesson_get_completion_state($course, $cm, $userid, $type) {
1097      global $CFG, $DB;
1098  
1099      // Get lesson details.
1100      $lesson = $DB->get_record('lesson', array('id' => $cm->instance), '*',
1101              MUST_EXIST);
1102  
1103      $result = $type; // Default return value.
1104      // If completion option is enabled, evaluate it and return true/false.
1105      if ($lesson->completionendreached) {
1106          $value = $DB->record_exists('lesson_timer', array(
1107                  'lessonid' => $lesson->id, 'userid' => $userid, 'completed' => 1));
1108          if ($type == COMPLETION_AND) {
1109              $result = $result && $value;
1110          } else {
1111              $result = $result || $value;
1112          }
1113      }
1114      if ($lesson->completiontimespent != 0) {
1115          $duration = $DB->get_field_sql(
1116                          "SELECT SUM(lessontime - starttime)
1117                                 FROM {lesson_timer}
1118                                WHERE lessonid = :lessonid
1119                                  AND userid = :userid",
1120                          array('userid' => $userid, 'lessonid' => $lesson->id));
1121          if (!$duration) {
1122              $duration = 0;
1123          }
1124          if ($type == COMPLETION_AND) {
1125              $result = $result && ($lesson->completiontimespent < $duration);
1126          } else {
1127              $result = $result || ($lesson->completiontimespent < $duration);
1128          }
1129      }
1130      return $result;
1131  }
1132  /**
1133   * This function extends the settings navigation block for the site.
1134   *
1135   * It is safe to rely on PAGE here as we will only ever be within the module
1136   * context when this is called
1137   *
1138   * @param settings_navigation $settings
1139   * @param navigation_node $lessonnode
1140   */
1141  function lesson_extend_settings_navigation($settings, $lessonnode) {
1142      global $PAGE, $DB;
1143  
1144      // We want to add these new nodes after the Edit settings node, and before the
1145      // Locally assigned roles node. Of course, both of those are controlled by capabilities.
1146      $keys = $lessonnode->get_children_key_list();
1147      $beforekey = null;
1148      $i = array_search('modedit', $keys);
1149      if ($i === false and array_key_exists(0, $keys)) {
1150          $beforekey = $keys[0];
1151      } else if (array_key_exists($i + 1, $keys)) {
1152          $beforekey = $keys[$i + 1];
1153      }
1154  
1155      if (has_capability('mod/lesson:manageoverrides', $PAGE->cm->context)) {
1156          $url = new moodle_url('/mod/lesson/overrides.php', array('cmid' => $PAGE->cm->id));
1157          $node = navigation_node::create(get_string('groupoverrides', 'lesson'),
1158                  new moodle_url($url, array('mode' => 'group')),
1159                  navigation_node::TYPE_SETTING, null, 'mod_lesson_groupoverrides');
1160          $lessonnode->add_node($node, $beforekey);
1161  
1162          $node = navigation_node::create(get_string('useroverrides', 'lesson'),
1163                  new moodle_url($url, array('mode' => 'user')),
1164                  navigation_node::TYPE_SETTING, null, 'mod_lesson_useroverrides');
1165          $lessonnode->add_node($node, $beforekey);
1166      }
1167  
1168      if (has_capability('mod/lesson:edit', $PAGE->cm->context)) {
1169          $url = new moodle_url('/mod/lesson/view.php', array('id' => $PAGE->cm->id));
1170          $lessonnode->add(get_string('preview', 'lesson'), $url);
1171          $editnode = $lessonnode->add(get_string('edit', 'lesson'));
1172          $url = new moodle_url('/mod/lesson/edit.php', array('id' => $PAGE->cm->id, 'mode' => 'collapsed'));
1173          $editnode->add(get_string('collapsed', 'lesson'), $url);
1174          $url = new moodle_url('/mod/lesson/edit.php', array('id' => $PAGE->cm->id, 'mode' => 'full'));
1175          $editnode->add(get_string('full', 'lesson'), $url);
1176      }
1177  
1178      if (has_capability('mod/lesson:viewreports', $PAGE->cm->context)) {
1179          $reportsnode = $lessonnode->add(get_string('reports', 'lesson'));
1180          $url = new moodle_url('/mod/lesson/report.php', array('id'=>$PAGE->cm->id, 'action'=>'reportoverview'));
1181          $reportsnode->add(get_string('overview', 'lesson'), $url);
1182          $url = new moodle_url('/mod/lesson/report.php', array('id'=>$PAGE->cm->id, 'action'=>'reportdetail'));
1183          $reportsnode->add(get_string('detailedstats', 'lesson'), $url);
1184      }
1185  
1186      if (has_capability('mod/lesson:grade', $PAGE->cm->context)) {
1187          $url = new moodle_url('/mod/lesson/essay.php', array('id'=>$PAGE->cm->id));
1188          $lessonnode->add(get_string('manualgrading', 'lesson'), $url);
1189      }
1190  
1191  }
1192  
1193  /**
1194   * Get list of available import or export formats
1195   *
1196   * Copied and modified from lib/questionlib.php
1197   *
1198   * @param string $type 'import' if import list, otherwise export list assumed
1199   * @return array sorted list of import/export formats available
1200   */
1201  function lesson_get_import_export_formats($type) {
1202      global $CFG;
1203      $fileformats = core_component::get_plugin_list("qformat");
1204  
1205      $fileformatname=array();
1206      foreach ($fileformats as $fileformat=>$fdir) {
1207          $format_file = "$fdir/format.php";
1208          if (file_exists($format_file) ) {
1209              require_once($format_file);
1210          } else {
1211              continue;
1212          }
1213          $classname = "qformat_$fileformat";
1214          $format_class = new $classname();
1215          if ($type=='import') {
1216              $provided = $format_class->provide_import();
1217          } else {
1218              $provided = $format_class->provide_export();
1219          }
1220          if ($provided) {
1221              $fileformatnames[$fileformat] = get_string('pluginname', 'qformat_'.$fileformat);
1222          }
1223      }
1224      natcasesort($fileformatnames);
1225  
1226      return $fileformatnames;
1227  }
1228  
1229  /**
1230   * Serves the lesson attachments. Implements needed access control ;-)
1231   *
1232   * @package mod_lesson
1233   * @category files
1234   * @param stdClass $course course object
1235   * @param stdClass $cm course module object
1236   * @param stdClass $context context object
1237   * @param string $filearea file area
1238   * @param array $args extra arguments
1239   * @param bool $forcedownload whether or not force download
1240   * @param array $options additional options affecting the file serving
1241   * @return bool false if file not found, does not return if found - justsend the file
1242   */
1243  function lesson_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
1244      global $CFG, $DB;
1245  
1246      if ($context->contextlevel != CONTEXT_MODULE) {
1247          return false;
1248      }
1249  
1250      $fileareas = lesson_get_file_areas();
1251      if (!array_key_exists($filearea, $fileareas)) {
1252          return false;
1253      }
1254  
1255      if (!$lesson = $DB->get_record('lesson', array('id'=>$cm->instance))) {
1256          return false;
1257      }
1258  
1259      require_course_login($course, true, $cm);
1260  
1261      if ($filearea === 'page_contents') {
1262          $pageid = (int)array_shift($args);
1263          if (!$page = $DB->get_record('lesson_pages', array('id'=>$pageid))) {
1264              return false;
1265          }
1266          $fullpath = "/$context->id/mod_lesson/$filearea/$pageid/".implode('/', $args);
1267  
1268      } else if ($filearea === 'page_answers' || $filearea === 'page_responses') {
1269          $itemid = (int)array_shift($args);
1270          if (!$pageanswers = $DB->get_record('lesson_answers', array('id' => $itemid))) {
1271              return false;
1272          }
1273          $fullpath = "/$context->id/mod_lesson/$filearea/$itemid/".implode('/', $args);
1274  
1275      } else if ($filearea === 'essay_responses') {
1276          $itemid = (int)array_shift($args);
1277          if (!$attempt = $DB->get_record('lesson_attempts', array('id' => $itemid))) {
1278              return false;
1279          }
1280          $fullpath = "/$context->id/mod_lesson/$filearea/$itemid/".implode('/', $args);
1281  
1282      } else if ($filearea === 'mediafile') {
1283          if (count($args) > 1) {
1284              // Remove the itemid when it appears to be part of the arguments. If there is only one argument
1285              // then it is surely the file name. The itemid is sometimes used to prevent browser caching.
1286              array_shift($args);
1287          }
1288          $fullpath = "/$context->id/mod_lesson/$filearea/0/".implode('/', $args);
1289  
1290      } else {
1291          return false;
1292      }
1293  
1294      $fs = get_file_storage();
1295      if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
1296          return false;
1297      }
1298  
1299      // finally send the file
1300      send_stored_file($file, 0, 0, $forcedownload, $options); // download MUST be forced - security!
1301  }
1302  
1303  /**
1304   * Returns an array of file areas
1305   *
1306   * @package  mod_lesson
1307   * @category files
1308   * @return array a list of available file areas
1309   */
1310  function lesson_get_file_areas() {
1311      $areas = array();
1312      $areas['page_contents'] = get_string('pagecontents', 'mod_lesson');
1313      $areas['mediafile'] = get_string('mediafile', 'mod_lesson');
1314      $areas['page_answers'] = get_string('pageanswers', 'mod_lesson');
1315      $areas['page_responses'] = get_string('pageresponses', 'mod_lesson');
1316      $areas['essay_responses'] = get_string('essayresponses', 'mod_lesson');
1317      return $areas;
1318  }
1319  
1320  /**
1321   * Returns a file_info_stored object for the file being requested here
1322   *
1323   * @package  mod_lesson
1324   * @category files
1325   * @global stdClass $CFG
1326   * @param file_browse $browser file browser instance
1327   * @param array $areas file areas
1328   * @param stdClass $course course object
1329   * @param stdClass $cm course module object
1330   * @param stdClass $context context object
1331   * @param string $filearea file area
1332   * @param int $itemid item ID
1333   * @param string $filepath file path
1334   * @param string $filename file name
1335   * @return file_info_stored
1336   */
1337  function lesson_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
1338      global $CFG, $DB;
1339  
1340      if (!has_capability('moodle/course:managefiles', $context)) {
1341          // No peaking here for students!
1342          return null;
1343      }
1344  
1345      // Mediafile area does not have sub directories, so let's select the default itemid to prevent
1346      // the user from selecting a directory to access the mediafile content.
1347      if ($filearea == 'mediafile' && is_null($itemid)) {
1348          $itemid = 0;
1349      }
1350  
1351      if (is_null($itemid)) {
1352          return new mod_lesson_file_info($browser, $course, $cm, $context, $areas, $filearea);
1353      }
1354  
1355      $fs = get_file_storage();
1356      $filepath = is_null($filepath) ? '/' : $filepath;
1357      $filename = is_null($filename) ? '.' : $filename;
1358      if (!$storedfile = $fs->get_file($context->id, 'mod_lesson', $filearea, $itemid, $filepath, $filename)) {
1359          return null;
1360      }
1361  
1362      $itemname = $filearea;
1363      if ($filearea == 'page_contents') {
1364          $itemname = $DB->get_field('lesson_pages', 'title', array('lessonid' => $cm->instance, 'id' => $itemid));
1365          $itemname = format_string($itemname, true, array('context' => $context));
1366      } else {
1367          $areas = lesson_get_file_areas();
1368          if (isset($areas[$filearea])) {
1369              $itemname = $areas[$filearea];
1370          }
1371      }
1372  
1373      $urlbase = $CFG->wwwroot . '/pluginfile.php';
1374      return new file_info_stored($browser, $context, $storedfile, $urlbase, $itemname, $itemid, true, true, false);
1375  }
1376  
1377  
1378  /**
1379   * Return a list of page types
1380   * @param string $pagetype current page type
1381   * @param stdClass $parentcontext Block's parent context
1382   * @param stdClass $currentcontext Current context of block
1383   */
1384  function lesson_page_type_list($pagetype, $parentcontext, $currentcontext) {
1385      $module_pagetype = array(
1386          'mod-lesson-*'=>get_string('page-mod-lesson-x', 'lesson'),
1387          'mod-lesson-view'=>get_string('page-mod-lesson-view', 'lesson'),
1388          'mod-lesson-edit'=>get_string('page-mod-lesson-edit', 'lesson'));
1389      return $module_pagetype;
1390  }
1391  
1392  /**
1393   * Update the lesson activity to include any file
1394   * that was uploaded, or if there is none, set the
1395   * mediafile field to blank.
1396   *
1397   * @param int $lessonid the lesson id
1398   * @param stdClass $context the context
1399   * @param int $draftitemid the draft item
1400   */
1401  function lesson_update_media_file($lessonid, $context, $draftitemid) {
1402      global $DB;
1403  
1404      // Set the filestorage object.
1405      $fs = get_file_storage();
1406      // Save the file if it exists that is currently in the draft area.
1407      file_save_draft_area_files($draftitemid, $context->id, 'mod_lesson', 'mediafile', 0);
1408      // Get the file if it exists.
1409      $files = $fs->get_area_files($context->id, 'mod_lesson', 'mediafile', 0, 'itemid, filepath, filename', false);
1410      // Check that there is a file to process.
1411      if (count($files) == 1) {
1412          // Get the first (and only) file.
1413          $file = reset($files);
1414          // Set the mediafile column in the lessons table.
1415          $DB->set_field('lesson', 'mediafile', '/' . $file->get_filename(), array('id' => $lessonid));
1416      } else {
1417          // Set the mediafile column in the lessons table.
1418          $DB->set_field('lesson', 'mediafile', '', array('id' => $lessonid));
1419      }
1420  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1