Search moodle.org's
Developer Documentation


   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   * Library of functions and constants for module glossary
  20   * (replace glossary with the name of your module and delete this line)
  21   *
  22   * @package   mod_glossary
  23   * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  24   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  require_once($CFG->libdir . '/completionlib.php');
  27  
  28  define("GLOSSARY_SHOW_ALL_CATEGORIES", 0);
  29  define("GLOSSARY_SHOW_NOT_CATEGORISED", -1);
  30  
  31  define("GLOSSARY_NO_VIEW", -1);
  32  define("GLOSSARY_STANDARD_VIEW", 0);
  33  define("GLOSSARY_CATEGORY_VIEW", 1);
  34  define("GLOSSARY_DATE_VIEW", 2);
  35  define("GLOSSARY_AUTHOR_VIEW", 3);
  36  define("GLOSSARY_ADDENTRY_VIEW", 4);
  37  define("GLOSSARY_IMPORT_VIEW", 5);
  38  define("GLOSSARY_EXPORT_VIEW", 6);
  39  define("GLOSSARY_APPROVAL_VIEW", 7);
  40  
  41  /// STANDARD FUNCTIONS ///////////////////////////////////////////////////////////
  42  /**
  43   * @global object
  44   * @param object $glossary
  45   * @return int
  46   */
  47  function glossary_add_instance($glossary) {
  48      global $DB;
  49  /// Given an object containing all the necessary data,
  50  /// (defined by the form in mod_form.php) this function
  51  /// will create a new instance and return the id number
  52  /// of the new instance.
  53  
  54      if (empty($glossary->ratingtime) or empty($glossary->assessed)) {
  55          $glossary->assesstimestart  = 0;
  56          $glossary->assesstimefinish = 0;
  57      }
  58  
  59      if (empty($glossary->globalglossary) ) {
  60          $glossary->globalglossary = 0;
  61      }
  62  
  63      if (!has_capability('mod/glossary:manageentries', context_system::instance())) {
  64          $glossary->globalglossary = 0;
  65      }
  66  
  67      $glossary->timecreated  = time();
  68      $glossary->timemodified = $glossary->timecreated;
  69  
  70      //Check displayformat is a valid one
  71      $formats = get_list_of_plugins('mod/glossary/formats','TEMPLATE');
  72      if (!in_array($glossary->displayformat, $formats)) {
  73          print_error('unknowformat', '', '', $glossary->displayformat);
  74      }
  75  
  76      $returnid = $DB->insert_record("glossary", $glossary);
  77      $glossary->id = $returnid;
  78      glossary_grade_item_update($glossary);
  79  
  80      return $returnid;
  81  }
  82  
  83  /**
  84   * Given an object containing all the necessary data,
  85   * (defined by the form in mod_form.php) this function
  86   * will update an existing instance with new data.
  87   *
  88   * @global object
  89   * @global object
  90   * @param object $glossary
  91   * @return bool
  92   */
  93  function glossary_update_instance($glossary) {
  94      global $CFG, $DB;
  95  
  96      if (empty($glossary->globalglossary)) {
  97          $glossary->globalglossary = 0;
  98      }
  99  
 100      if (!has_capability('mod/glossary:manageentries', context_system::instance())) {
 101          // keep previous
 102          unset($glossary->globalglossary);
 103      }
 104  
 105      $glossary->timemodified = time();
 106      $glossary->id           = $glossary->instance;
 107  
 108      if (empty($glossary->ratingtime) or empty($glossary->assessed)) {
 109          $glossary->assesstimestart  = 0;
 110          $glossary->assesstimefinish = 0;
 111      }
 112  
 113      //Check displayformat is a valid one
 114      $formats = get_list_of_plugins('mod/glossary/formats','TEMPLATE');
 115      if (!in_array($glossary->displayformat, $formats)) {
 116          print_error('unknowformat', '', '', $glossary->displayformat);
 117      }
 118  
 119      $DB->update_record("glossary", $glossary);
 120      if ($glossary->defaultapproval) {
 121          $DB->execute("UPDATE {glossary_entries} SET approved = 1 where approved <> 1 and glossaryid = ?", array($glossary->id));
 122      }
 123      glossary_grade_item_update($glossary);
 124  
 125      return true;
 126  }
 127  
 128  /**
 129   * Given an ID of an instance of this module,
 130   * this function will permanently delete the instance
 131   * and any data that depends on it.
 132   *
 133   * @global object
 134   * @param int $id glossary id
 135   * @return bool success
 136   */
 137  function glossary_delete_instance($id) {
 138      global $DB, $CFG;
 139  
 140      if (!$glossary = $DB->get_record('glossary', array('id'=>$id))) {
 141          return false;
 142      }
 143  
 144      if (!$cm = get_coursemodule_from_instance('glossary', $id)) {
 145          return false;
 146      }
 147  
 148      if (!$context = context_module::instance($cm->id, IGNORE_MISSING)) {
 149          return false;
 150      }
 151  
 152      $fs = get_file_storage();
 153  
 154      if ($glossary->mainglossary) {
 155          // unexport entries
 156          $sql = "SELECT ge.id, ge.sourceglossaryid, cm.id AS sourcecmid
 157                    FROM {glossary_entries} ge
 158                    JOIN {modules} m ON m.name = 'glossary'
 159                    JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = ge.sourceglossaryid)
 160                   WHERE ge.glossaryid = ? AND ge.sourceglossaryid > 0";
 161  
 162          if ($exported = $DB->get_records_sql($sql, array($id))) {
 163              foreach ($exported as $entry) {
 164                  $entry->glossaryid = $entry->sourceglossaryid;
 165                  $entry->sourceglossaryid = 0;
 166                  $newcontext = context_module::instance($entry->sourcecmid);
 167                  if ($oldfiles = $fs->get_area_files($context->id, 'mod_glossary', 'attachment', $entry->id)) {
 168                      foreach ($oldfiles as $oldfile) {
 169                          $file_record = new stdClass();
 170                          $file_record->contextid = $newcontext->id;
 171                          $fs->create_file_from_storedfile($file_record, $oldfile);
 172                      }
 173                      $fs->delete_area_files($context->id, 'mod_glossary', 'attachment', $entry->id);
 174                      $entry->attachment = '1';
 175                  } else {
 176                      $entry->attachment = '0';
 177                  }
 178                  $DB->update_record('glossary_entries', $entry);
 179              }
 180          }
 181      } else {
 182          // move exported entries to main glossary
 183          $sql = "UPDATE {glossary_entries}
 184                     SET sourceglossaryid = 0
 185                   WHERE sourceglossaryid = ?";
 186          $DB->execute($sql, array($id));
 187      }
 188  
 189      // Delete any dependent records
 190      $entry_select = "SELECT id FROM {glossary_entries} WHERE glossaryid = ?";
 191      $DB->delete_records_select('comments', "contextid=? AND commentarea=? AND itemid IN ($entry_select)", array($id, 'glossary_entry', $context->id));
 192      $DB->delete_records_select('glossary_alias',    "entryid IN ($entry_select)", array($id));
 193  
 194      $category_select = "SELECT id FROM {glossary_categories} WHERE glossaryid = ?";
 195      $DB->delete_records_select('glossary_entries_categories', "categoryid IN ($category_select)", array($id));
 196      $DB->delete_records('glossary_categories', array('glossaryid'=>$id));
 197      $DB->delete_records('glossary_entries', array('glossaryid'=>$id));
 198  
 199      // delete all files
 200      $fs->delete_area_files($context->id);
 201  
 202      glossary_grade_item_delete($glossary);
 203  
 204      $DB->delete_records('glossary', array('id'=>$id));
 205  
 206      // Reset caches.
 207      \mod_glossary\local\concept_cache::reset_glossary($glossary);
 208  
 209      return true;
 210  }
 211  
 212  /**
 213   * Return a small object with summary information about what a
 214   * user has done with a given particular instance of this module
 215   * Used for user activity reports.
 216   * $return->time = the time they did it
 217   * $return->info = a short text description
 218   *
 219   * @param object $course
 220   * @param object $user
 221   * @param object $mod
 222   * @param object $glossary
 223   * @return object|null
 224   */
 225  function glossary_user_outline($course, $user, $mod, $glossary) {
 226      global $CFG;
 227  
 228      require_once("$CFG->libdir/gradelib.php");
 229      $grades = grade_get_grades($course->id, 'mod', 'glossary', $glossary->id, $user->id);
 230      if (empty($grades->items[0]->grades)) {
 231          $grade = false;
 232      } else {
 233          $grade = reset($grades->items[0]->grades);
 234      }
 235  
 236      if ($entries = glossary_get_user_entries($glossary->id, $user->id)) {
 237          $result = new stdClass();
 238          $result->info = count($entries) . ' ' . get_string("entries", "glossary");
 239  
 240          $lastentry = array_pop($entries);
 241          $result->time = $lastentry->timemodified;
 242  
 243          if ($grade) {
 244              $result->info .= ', ' . get_string('grade') . ': ' . $grade->str_long_grade;
 245          }
 246          return $result;
 247      } else if ($grade) {
 248          $result = new stdClass();
 249          $result->info = get_string('grade') . ': ' . $grade->str_long_grade;
 250  
 251          //datesubmitted == time created. dategraded == time modified or time overridden
 252          //if grade was last modified by the user themselves use date graded. Otherwise use date submitted
 253          //TODO: move this copied & pasted code somewhere in the grades API. See MDL-26704
 254          if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) {
 255              $result->time = $grade->dategraded;
 256          } else {
 257              $result->time = $grade->datesubmitted;
 258          }
 259  
 260          return $result;
 261      }
 262      return NULL;
 263  }
 264  
 265  /**
 266   * @global object
 267   * @param int $glossaryid
 268   * @param int $userid
 269   * @return array
 270   */
 271  function glossary_get_user_entries($glossaryid, $userid) {
 272  /// Get all the entries for a user in a glossary
 273      global $DB;
 274  
 275      return $DB->get_records_sql("SELECT e.*, u.firstname, u.lastname, u.email, u.picture
 276                                     FROM {glossary} g, {glossary_entries} e, {user} u
 277                               WHERE g.id = ?
 278                                 AND e.glossaryid = g.id
 279                                 AND e.userid = ?
 280                                 AND e.userid = u.id
 281                            ORDER BY e.timemodified ASC", array($glossaryid, $userid));
 282  }
 283  
 284  /**
 285   * Print a detailed representation of what a  user has done with
 286   * a given particular instance of this module, for user activity reports.
 287   *
 288   * @global object
 289   * @param object $course
 290   * @param object $user
 291   * @param object $mod
 292   * @param object $glossary
 293   */
 294  function glossary_user_complete($course, $user, $mod, $glossary) {
 295      global $CFG, $OUTPUT;
 296      require_once("$CFG->libdir/gradelib.php");
 297  
 298      $grades = grade_get_grades($course->id, 'mod', 'glossary', $glossary->id, $user->id);
 299      if (!empty($grades->items[0]->grades)) {
 300          $grade = reset($grades->items[0]->grades);
 301          echo $OUTPUT->container(get_string('grade').': '.$grade->str_long_grade);
 302          if ($grade->str_feedback) {
 303              echo $OUTPUT->container(get_string('feedback').': '.$grade->str_feedback);
 304          }
 305      }
 306  
 307      if ($entries = glossary_get_user_entries($glossary->id, $user->id)) {
 308          echo '<table width="95%" border="0"><tr><td>';
 309          foreach ($entries as $entry) {
 310              $cm = get_coursemodule_from_instance("glossary", $glossary->id, $course->id);
 311              glossary_print_entry($course, $cm, $glossary, $entry,"","",0);
 312              echo '<p>';
 313          }
 314          echo '</td></tr></table>';
 315      }
 316  }
 317  
 318  /**
 319   * Returns all glossary entries since a given time for specified glossary
 320   *
 321   * @param array $activities sequentially indexed array of objects
 322   * @param int   $index
 323   * @param int   $timestart
 324   * @param int   $courseid
 325   * @param int   $cmid
 326   * @param int   $userid defaults to 0
 327   * @param int   $groupid defaults to 0
 328   * @return void adds items into $activities and increases $index
 329   */
 330  function glossary_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid = 0, $groupid = 0) {
 331      global $COURSE, $USER, $DB;
 332  
 333      if ($COURSE->id == $courseid) {
 334          $course = $COURSE;
 335      } else {
 336          $course = $DB->get_record('course', array('id' => $courseid));
 337      }
 338  
 339      $modinfo = get_fast_modinfo($course);
 340      $cm = $modinfo->cms[$cmid];
 341      $context = context_module::instance($cm->id);
 342  
 343      if (!$cm->uservisible) {
 344          return;
 345      }
 346  
 347      $viewfullnames = has_capability('moodle/site:viewfullnames', $context);
 348      // Groups are not yet supported for glossary. See MDL-10728 .
 349      /*
 350      $accessallgroups = has_capability('moodle/site:accessallgroups', $context);
 351      $groupmode = groups_get_activity_groupmode($cm, $course);
 352       */
 353  
 354      $params['timestart'] = $timestart;
 355  
 356      if ($userid) {
 357          $userselect = "AND u.id = :userid";
 358          $params['userid'] = $userid;
 359      } else {
 360          $userselect = '';
 361      }
 362  
 363      if ($groupid) {
 364          $groupselect = 'AND gm.groupid = :groupid';
 365          $groupjoin   = 'JOIN {groups_members} gm ON  gm.userid=u.id';
 366          $params['groupid'] = $groupid;
 367      } else {
 368          $groupselect = '';
 369          $groupjoin   = '';
 370      }
 371  
 372      $approvedselect = "";
 373      if (!has_capability('mod/glossary:approve', $context)) {
 374          $approvedselect = " AND ge.approved = 1 ";
 375      }
 376  
 377      $params['timestart'] = $timestart;
 378      $params['glossaryid'] = $cm->instance;
 379  
 380      $ufields = user_picture::fields('u', null, 'userid');
 381      $entries = $DB->get_records_sql("
 382                SELECT ge.id AS entryid, ge.glossaryid, ge.concept, ge.definition, ge.approved,
 383                       ge.timemodified, $ufields
 384                  FROM {glossary_entries} ge
 385                  JOIN {user} u ON u.id = ge.userid
 386                       $groupjoin
 387                 WHERE ge.timemodified > :timestart
 388                   AND ge.glossaryid = :glossaryid
 389                       $approvedselect
 390                       $userselect
 391                       $groupselect
 392              ORDER BY ge.timemodified ASC", $params);
 393  
 394      if (!$entries) {
 395          return;
 396      }
 397  
 398      foreach ($entries as $entry) {
 399          // Groups are not yet supported for glossary. See MDL-10728 .
 400          /*
 401          $usersgroups = null;
 402          if ($entry->userid != $USER->id) {
 403              if ($groupmode == SEPARATEGROUPS and !$accessallgroups) {
 404                  if (is_null($usersgroups)) {
 405                      $usersgroups = groups_get_all_groups($course->id, $entry->userid, $cm->groupingid);
 406                      if (is_array($usersgroups)) {
 407                          $usersgroups = array_keys($usersgroups);
 408                      } else {
 409                          $usersgroups = array();
 410                      }
 411                  }
 412                  if (!array_intersect($usersgroups, $modinfo->get_groups($cm->groupingid))) {
 413                      continue;
 414                  }
 415              }
 416          }
 417           */
 418  
 419          $tmpactivity                       = new stdClass();
 420          $tmpactivity->user                 = user_picture::unalias($entry, null, 'userid');
 421          $tmpactivity->user->fullname       = fullname($tmpactivity->user, $viewfullnames);
 422          $tmpactivity->type                 = 'glossary';
 423          $tmpactivity->cmid                 = $cm->id;
 424          $tmpactivity->glossaryid           = $entry->glossaryid;
 425          $tmpactivity->name                 = format_string($cm->name, true);
 426          $tmpactivity->sectionnum           = $cm->sectionnum;
 427          $tmpactivity->timestamp            = $entry->timemodified;
 428          $tmpactivity->content              = new stdClass();
 429          $tmpactivity->content->entryid     = $entry->entryid;
 430          $tmpactivity->content->concept     = $entry->concept;
 431          $tmpactivity->content->definition  = $entry->definition;
 432          $tmpactivity->content->approved    = $entry->approved;
 433  
 434          $activities[$index++] = $tmpactivity;
 435      }
 436  
 437      return true;
 438  }
 439  
 440  /**
 441   * Outputs the glossary entry indicated by $activity
 442   *
 443   * @param object $activity      the activity object the glossary resides in
 444   * @param int    $courseid      the id of the course the glossary resides in
 445   * @param bool   $detail        not used, but required for compatibilty with other modules
 446   * @param int    $modnames      not used, but required for compatibilty with other modules
 447   * @param bool   $viewfullnames not used, but required for compatibilty with other modules
 448   * @return void
 449   */
 450  function glossary_print_recent_mod_activity($activity, $courseid, $detail, $modnames, $viewfullnames) {
 451      global $OUTPUT;
 452  
 453      echo html_writer::start_tag('div', array('class'=>'glossary-activity clearfix'));
 454      if (!empty($activity->user)) {
 455          echo html_writer::tag('div', $OUTPUT->user_picture($activity->user, array('courseid'=>$courseid)),
 456              array('class' => 'glossary-activity-picture'));
 457      }
 458  
 459      echo html_writer::start_tag('div', array('class'=>'glossary-activity-content'));
 460      echo html_writer::start_tag('div', array('class'=>'glossary-activity-entry'));
 461  
 462      if (isset($activity->content->approved) && !$activity->content->approved) {
 463          $urlparams = array('g' => $activity->glossaryid, 'mode' => 'approval', 'hook' => $activity->content->concept);
 464          $class = array('class' => 'dimmed_text');
 465      } else {
 466          $urlparams = array('g' => $activity->glossaryid, 'mode' => 'entry', 'hook' => $activity->content->entryid);
 467          $class = array();
 468      }
 469      echo html_writer::link(new moodle_url('/mod/glossary/view.php', $urlparams),
 470              strip_tags($activity->content->concept), $class);
 471      echo html_writer::end_tag('div');
 472  
 473      $url = new moodle_url('/user/view.php', array('course'=>$courseid, 'id'=>$activity->user->id));
 474      $name = $activity->user->fullname;
 475      $link = html_writer::link($url, $name, $class);
 476  
 477      echo html_writer::start_tag('div', array('class'=>'user'));
 478      echo $link .' - '. userdate($activity->timestamp);
 479      echo html_writer::end_tag('div');
 480  
 481      echo html_writer::end_tag('div');
 482  
 483      echo html_writer::end_tag('div');
 484      return;
 485  }
 486  /**
 487   * Given a course and a time, this module should find recent activity
 488   * that has occurred in glossary activities and print it out.
 489   * Return true if there was output, or false is there was none.
 490   *
 491   * @global object
 492   * @global object
 493   * @global object
 494   * @param object $course
 495   * @param object $viewfullnames
 496   * @param int $timestart
 497   * @return bool
 498   */
 499  function glossary_print_recent_activity($course, $viewfullnames, $timestart) {
 500      global $CFG, $USER, $DB, $OUTPUT, $PAGE;
 501  
 502      //TODO: use timestamp in approved field instead of changing timemodified when approving in 2.0
 503      if (!defined('GLOSSARY_RECENT_ACTIVITY_LIMIT')) {
 504          define('GLOSSARY_RECENT_ACTIVITY_LIMIT', 50);
 505      }
 506      $modinfo = get_fast_modinfo($course);
 507      $ids = array();
 508  
 509      foreach ($modinfo->cms as $cm) {
 510          if ($cm->modname != 'glossary') {
 511              continue;
 512          }
 513          if (!$cm->uservisible) {
 514              continue;
 515          }
 516          $ids[$cm->instance] = $cm->id;
 517      }
 518  
 519      if (!$ids) {
 520          return false;
 521      }
 522  
 523      // generate list of approval capabilities for all glossaries in the course.
 524      $approvals = array();
 525      foreach ($ids as $glinstanceid => $glcmid) {
 526          $context = context_module::instance($glcmid);
 527          if (has_capability('mod/glossary:view', $context)) {
 528              // get records glossary entries that are approved if user has no capability to approve entries.
 529              if (has_capability('mod/glossary:approve', $context)) {
 530                  $approvals[] = ' ge.glossaryid = :glsid'.$glinstanceid.' ';
 531              } else {
 532                  $approvals[] = ' (ge.approved = 1 AND ge.glossaryid = :glsid'.$glinstanceid.') ';
 533              }
 534              $params['glsid'.$glinstanceid] = $glinstanceid;
 535          }
 536      }
 537  
 538      if (count($approvals) == 0) {
 539          return false;
 540      }
 541      $selectsql = 'SELECT ge.id, ge.concept, ge.approved, ge.timemodified, ge.glossaryid,
 542                                          '.user_picture::fields('u',null,'userid');
 543      $countsql = 'SELECT COUNT(*)';
 544  
 545      $joins = array(' FROM {glossary_entries} ge ');
 546      $joins[] = 'JOIN {user} u ON u.id = ge.userid ';
 547      $fromsql = implode($joins, "\n");
 548  
 549      $params['timestart'] = $timestart;
 550      $clausesql = ' WHERE ge.timemodified > :timestart ';
 551  
 552      if (count($approvals) > 0) {
 553          $approvalsql = 'AND ('. implode($approvals, ' OR ') .') ';
 554      } else {
 555          $approvalsql = '';
 556      }
 557      $ordersql = 'ORDER BY ge.timemodified ASC';
 558      $entries = $DB->get_records_sql($selectsql.$fromsql.$clausesql.$approvalsql.$ordersql, $params, 0, (GLOSSARY_RECENT_ACTIVITY_LIMIT+1));
 559  
 560      if (empty($entries)) {
 561          return false;
 562      }
 563  
 564      echo $OUTPUT->heading(get_string('newentries', 'glossary').':', 3);
 565      $strftimerecent = get_string('strftimerecent');
 566      $entrycount = 0;
 567      foreach ($entries as $entry) {
 568          if ($entrycount < GLOSSARY_RECENT_ACTIVITY_LIMIT) {
 569              if ($entry->approved) {
 570                  $dimmed = '';
 571                  $urlparams = array('g' => $entry->glossaryid, 'mode' => 'entry', 'hook' => $entry->id);
 572              } else {
 573                  $dimmed = ' dimmed_text';
 574                  $urlparams = array('id' => $ids[$entry->glossaryid], 'mode' => 'approval', 'hook' => format_text($entry->concept, true));
 575              }
 576              $link = new moodle_url($CFG->wwwroot.'/mod/glossary/view.php' , $urlparams);
 577              echo '<div class="head'.$dimmed.'">';
 578              echo '<div class="date">'.userdate($entry->timemodified, $strftimerecent).'</div>';
 579              echo '<div class="name">'.fullname($entry, $viewfullnames).'</div>';
 580              echo '</div>';
 581              echo '<div class="info"><a href="'.$link.'">'.format_string($entry->concept, true).'</a></div>';
 582              $entrycount += 1;
 583          } else {
 584              $numnewentries = $DB->count_records_sql($countsql.$joins[0].$clausesql.$approvalsql, $params);
 585              echo '<div class="head"><div class="activityhead">'.get_string('andmorenewentries', 'glossary', $numnewentries - GLOSSARY_RECENT_ACTIVITY_LIMIT).'</div></div>';
 586              break;
 587          }
 588      }
 589  
 590      return true;
 591  }
 592  
 593  /**
 594   * @global object
 595   * @param object $log
 596   */
 597  function glossary_log_info($log) {
 598      global $DB;
 599  
 600      return $DB->get_record_sql("SELECT e.*, u.firstname, u.lastname
 601                                    FROM {glossary_entries} e, {user} u
 602                                   WHERE e.id = ? AND u.id = ?", array($log->info, $log->userid));
 603  }
 604  
 605  /**
 606   * Function to be run periodically according to the moodle cron
 607   * This function searches for things that need to be done, such
 608   * as sending out mail, toggling flags etc ...
 609   * @return bool
 610   */
 611  function glossary_cron () {
 612      return true;
 613  }
 614  
 615  /**
 616   * Return grade for given user or all users.
 617   *
 618   * @param stdClass $glossary A glossary instance
 619   * @param int $userid Optional user id, 0 means all users
 620   * @return array An array of grades, false if none
 621   */
 622  function glossary_get_user_grades($glossary, $userid=0) {
 623      global $CFG;
 624  
 625      require_once($CFG->dirroot.'/rating/lib.php');
 626  
 627      $ratingoptions = new stdClass;
 628  
 629      //need these to work backwards to get a context id. Is there a better way to get contextid from a module instance?
 630      $ratingoptions->modulename = 'glossary';
 631      $ratingoptions->moduleid   = $glossary->id;
 632      $ratingoptions->component  = 'mod_glossary';
 633      $ratingoptions->ratingarea = 'entry';
 634  
 635      $ratingoptions->userid = $userid;
 636      $ratingoptions->aggregationmethod = $glossary->assessed;
 637      $ratingoptions->scaleid = $glossary->scale;
 638      $ratingoptions->itemtable = 'glossary_entries';
 639      $ratingoptions->itemtableusercolumn = 'userid';
 640  
 641      $rm = new rating_manager();
 642      return $rm->get_user_grades($ratingoptions);
 643  }
 644  
 645  /**
 646   * Return rating related permissions
 647   *
 648   * @param int $contextid the context id
 649   * @param string $component The component we want to get permissions for
 650   * @param string $ratingarea The ratingarea that we want to get permissions for
 651   * @return array an associative array of the user's rating permissions
 652   */
 653  function glossary_rating_permissions($contextid, $component, $ratingarea) {
 654      if ($component != 'mod_glossary' || $ratingarea != 'entry') {
 655          // We don't know about this component/ratingarea so just return null to get the
 656          // default restrictive permissions.
 657          return null;
 658      }
 659      $context = context::instance_by_id($contextid);
 660      return array(
 661          'view'    => has_capability('mod/glossary:viewrating', $context),
 662          'viewany' => has_capability('mod/glossary:viewanyrating', $context),
 663          'viewall' => has_capability('mod/glossary:viewallratings', $context),
 664          'rate'    => has_capability('mod/glossary:rate', $context)
 665      );
 666  }
 667  
 668  /**
 669   * Validates a submitted rating
 670   * @param array $params submitted data
 671   *            context => object the context in which the rated items exists [required]
 672   *            component => The component for this module - should always be mod_forum [required]
 673   *            ratingarea => object the context in which the rated items exists [required]
 674   *            itemid => int the ID of the object being rated [required]
 675   *            scaleid => int the scale from which the user can select a rating. Used for bounds checking. [required]
 676   *            rating => int the submitted rating
 677   *            rateduserid => int the id of the user whose items have been rated. NOT the user who submitted the ratings. 0 to update all. [required]
 678   *            aggregation => int the aggregation method to apply when calculating grades ie RATING_AGGREGATE_AVERAGE [optional]
 679   * @return boolean true if the rating is valid. Will throw rating_exception if not
 680   */
 681  function glossary_rating_validate($params) {
 682      global $DB, $USER;
 683  
 684      // Check the component is mod_forum
 685      if ($params['component'] != 'mod_glossary') {
 686          throw new rating_exception('invalidcomponent');
 687      }
 688  
 689      // Check the ratingarea is post (the only rating area in forum)
 690      if ($params['ratingarea'] != 'entry') {
 691          throw new rating_exception('invalidratingarea');
 692      }
 693  
 694      // Check the rateduserid is not the current user .. you can't rate your own posts
 695      if ($params['rateduserid'] == $USER->id) {
 696          throw new rating_exception('nopermissiontorate');
 697      }
 698  
 699      $glossarysql = "SELECT g.id as glossaryid, g.scale, g.course, e.userid as userid, e.approved, e.timecreated, g.assesstimestart, g.assesstimefinish
 700                        FROM {glossary_entries} e
 701                        JOIN {glossary} g ON e.glossaryid = g.id
 702                       WHERE e.id = :itemid";
 703      $glossaryparams = array('itemid' => $params['itemid']);
 704      $info = $DB->get_record_sql($glossarysql, $glossaryparams);
 705      if (!$info) {
 706          //item doesn't exist
 707          throw new rating_exception('invaliditemid');
 708      }
 709  
 710      if ($info->scale != $params['scaleid']) {
 711          //the scale being submitted doesnt match the one in the database
 712          throw new rating_exception('invalidscaleid');
 713      }
 714  
 715      //check that the submitted rating is valid for the scale
 716  
 717      // lower limit
 718      if ($params['rating'] < 0  && $params['rating'] != RATING_UNSET_RATING) {
 719          throw new rating_exception('invalidnum');
 720      }
 721  
 722      // upper limit
 723      if ($info->scale < 0) {
 724          //its a custom scale
 725          $scalerecord = $DB->get_record('scale', array('id' => -$info->scale));
 726          if ($scalerecord) {
 727              $scalearray = explode(',', $scalerecord->scale);
 728              if ($params['rating'] > count($scalearray)) {
 729                  throw new rating_exception('invalidnum');
 730              }
 731          } else {
 732              throw new rating_exception('invalidscaleid');
 733          }
 734      } else if ($params['rating'] > $info->scale) {
 735          //if its numeric and submitted rating is above maximum
 736          throw new rating_exception('invalidnum');
 737      }
 738  
 739      if (!$info->approved) {
 740          //item isnt approved
 741          throw new rating_exception('nopermissiontorate');
 742      }
 743  
 744      //check the item we're rating was created in the assessable time window
 745      if (!empty($info->assesstimestart) && !empty($info->assesstimefinish)) {
 746          if ($info->timecreated < $info->assesstimestart || $info->timecreated > $info->assesstimefinish) {
 747              throw new rating_exception('notavailable');
 748          }
 749      }
 750  
 751      $cm = get_coursemodule_from_instance('glossary', $info->glossaryid, $info->course, false, MUST_EXIST);
 752      $context = context_module::instance($cm->id, MUST_EXIST);
 753  
 754      // if the supplied context doesnt match the item's context
 755      if ($context->id != $params['context']->id) {
 756          throw new rating_exception('invalidcontext');
 757      }
 758  
 759      return true;
 760  }
 761  
 762  /**
 763   * Update activity grades
 764   *
 765   * @category grade
 766   * @param stdClass $glossary Null means all glossaries (with extra cmidnumber property)
 767   * @param int $userid specific user only, 0 means all
 768   * @param bool $nullifnone If true and the user has no grade then a grade item with rawgrade == null will be inserted
 769   */
 770  function glossary_update_grades($glossary=null, $userid=0, $nullifnone=true) {
 771      global $CFG, $DB;
 772      require_once($CFG->libdir.'/gradelib.php');
 773  
 774      if (!$glossary->assessed) {
 775          glossary_grade_item_update($glossary);
 776  
 777      } else if ($grades = glossary_get_user_grades($glossary, $userid)) {
 778          glossary_grade_item_update($glossary, $grades);
 779  
 780      } else if ($userid and $nullifnone) {
 781          $grade = new stdClass();
 782          $grade->userid   = $userid;
 783          $grade->rawgrade = NULL;
 784          glossary_grade_item_update($glossary, $grade);
 785  
 786      } else {
 787          glossary_grade_item_update($glossary);
 788      }
 789  }
 790  
 791  /**
 792   * Create/update grade item for given glossary
 793   *
 794   * @category grade
 795   * @param stdClass $glossary object with extra cmidnumber
 796   * @param mixed $grades Optional array/object of grade(s); 'reset' means reset grades in gradebook
 797   * @return int, 0 if ok, error code otherwise
 798   */
 799  function glossary_grade_item_update($glossary, $grades=NULL) {
 800      global $CFG;
 801      require_once($CFG->libdir.'/gradelib.php');
 802  
 803      $params = array('itemname'=>$glossary->name, 'idnumber'=>$glossary->cmidnumber);
 804  
 805      if (!$glossary->assessed or $glossary->scale == 0) {
 806          $params['gradetype'] = GRADE_TYPE_NONE;
 807  
 808      } else if ($glossary->scale > 0) {
 809          $params['gradetype'] = GRADE_TYPE_VALUE;
 810          $params['grademax']  = $glossary->scale;
 811          $params['grademin']  = 0;
 812  
 813      } else if ($glossary->scale < 0) {
 814          $params['gradetype'] = GRADE_TYPE_SCALE;
 815          $params['scaleid']   = -$glossary->scale;
 816      }
 817  
 818      if ($grades  === 'reset') {
 819          $params['reset'] = true;
 820          $grades = NULL;
 821      }
 822  
 823      return grade_update('mod/glossary', $glossary->course, 'mod', 'glossary', $glossary->id, 0, $grades, $params);
 824  }
 825  
 826  /**
 827   * Delete grade item for given glossary
 828   *
 829   * @category grade
 830   * @param object $glossary object
 831   */
 832  function glossary_grade_item_delete($glossary) {
 833      global $CFG;
 834      require_once($CFG->libdir.'/gradelib.php');
 835  
 836      return grade_update('mod/glossary', $glossary->course, 'mod', 'glossary', $glossary->id, 0, NULL, array('deleted'=>1));
 837  }
 838  
 839  /**
 840   * @global object
 841   * @param int $gloassryid
 842   * @param int $scaleid
 843   * @return bool
 844   */
 845  function glossary_scale_used ($glossaryid,$scaleid) {
 846  //This function returns if a scale is being used by one glossary
 847      global $DB;
 848  
 849      $return = false;
 850  
 851      $rec = $DB->get_record("glossary", array("id"=>$glossaryid, "scale"=>-$scaleid));
 852  
 853      if (!empty($rec)  && !empty($scaleid)) {
 854          $return = true;
 855      }
 856  
 857      return $return;
 858  }
 859  
 860  /**
 861   * Checks if scale is being used by any instance of glossary
 862   *
 863   * This is used to find out if scale used anywhere
 864   *
 865   * @global object
 866   * @param int $scaleid
 867   * @return boolean True if the scale is used by any glossary
 868   */
 869  function glossary_scale_used_anywhere($scaleid) {
 870      global $DB;
 871  
 872      if ($scaleid and $DB->record_exists('glossary', array('scale'=>-$scaleid))) {
 873          return true;
 874      } else {
 875          return false;
 876      }
 877  }
 878  
 879  //////////////////////////////////////////////////////////////////////////////////////
 880  /// Any other glossary functions go here.  Each of them must have a name that
 881  /// starts with glossary_
 882  
 883  /**
 884   * This function return an array of valid glossary_formats records
 885   * Everytime it's called, every existing format is checked, new formats
 886   * are included if detected and old formats are deleted and any glossary
 887   * using an invalid format is updated to the default (dictionary).
 888   *
 889   * @global object
 890   * @global object
 891   * @return array
 892   */
 893  function glossary_get_available_formats() {
 894      global $CFG, $DB;
 895  
 896      //Get available formats (plugin) and insert (if necessary) them into glossary_formats
 897      $formats = get_list_of_plugins('mod/glossary/formats', 'TEMPLATE');
 898      $pluginformats = array();
 899      foreach ($formats as $format) {
 900          //If the format file exists
 901          if (file_exists($CFG->dirroot.'/mod/glossary/formats/'.$format.'/'.$format.'_format.php')) {
 902              include_once($CFG->dirroot.'/mod/glossary/formats/'.$format.'/'.$format.'_format.php');
 903              //If the function exists
 904              if (function_exists('glossary_show_entry_'.$format)) {
 905                  //Acummulate it as a valid format
 906                  $pluginformats[] = $format;
 907                  //If the format doesn't exist in the table
 908                  if (!$rec = $DB->get_record('glossary_formats', array('name'=>$format))) {
 909                      //Insert the record in glossary_formats
 910                      $gf = new stdClass();
 911                      $gf->name = $format;
 912                      $gf->popupformatname = $format;
 913                      $gf->visible = 1;
 914                      $DB->insert_record("glossary_formats",$gf);
 915                  }
 916              }
 917          }
 918      }
 919  
 920      //Delete non_existent formats from glossary_formats table
 921      $formats = $DB->get_records("glossary_formats");
 922      foreach ($formats as $format) {
 923          $todelete = false;
 924          //If the format in DB isn't a valid previously detected format then delete the record
 925          if (!in_array($format->name,$pluginformats)) {
 926              $todelete = true;
 927          }
 928  
 929          if ($todelete) {
 930              //Delete the format
 931              $DB->delete_records('glossary_formats', array('name'=>$format->name));
 932              //Reasign existing glossaries to default (dictionary) format
 933              if ($glossaries = $DB->get_records('glossary', array('displayformat'=>$format->name))) {
 934                  foreach($glossaries as $glossary) {
 935                      $DB->set_field('glossary','displayformat','dictionary', array('id'=>$glossary->id));
 936                  }
 937              }
 938          }
 939      }
 940  
 941      //Now everything is ready in glossary_formats table
 942      $formats = $DB->get_records("glossary_formats");
 943  
 944      return $formats;
 945  }
 946  
 947  /**
 948   * @param bool $debug
 949   * @param string $text
 950   * @param int $br
 951   */
 952  function glossary_debug($debug,$text,$br=1) {
 953      if ( $debug ) {
 954          echo '<font color="red">' . $text . '</font>';
 955          if ( $br ) {
 956              echo '<br />';
 957          }
 958      }
 959  }
 960  
 961  /**
 962   *
 963   * @global object
 964   * @param int $glossaryid
 965   * @param string $entrylist
 966   * @param string $pivot
 967   * @return array
 968   */
 969  function glossary_get_entries($glossaryid, $entrylist, $pivot = "") {
 970      global $DB;
 971      if ($pivot) {
 972         $pivot .= ",";
 973      }
 974  
 975      return $DB->get_records_sql("SELECT $pivot id,userid,concept,definition,format
 976                                     FROM {glossary_entries}
 977                                    WHERE glossaryid = ?
 978                                          AND id IN ($entrylist)", array($glossaryid));
 979  }
 980  
 981  /**
 982   * @global object
 983   * @global object
 984   * @param object $concept
 985   * @param string $courseid
 986   * @return array
 987   */
 988  function glossary_get_entries_search($concept, $courseid) {
 989      global $CFG, $DB;
 990  
 991      //Check if the user is an admin
 992      $bypassadmin = 1; //This means NO (by default)
 993      if (has_capability('moodle/course:viewhiddenactivities', context_system::instance())) {
 994          $bypassadmin = 0; //This means YES
 995      }
 996  
 997      //Check if the user is a teacher
 998      $bypassteacher = 1; //This means NO (by default)
 999      if (has_capability('mod/glossary:manageentries', context_course::instance($courseid))) {
1000          $bypassteacher = 0; //This means YES
1001      }
1002  
1003      $conceptlower = core_text::strtolower(trim($concept));
1004  
1005      $params = array('courseid1'=>$courseid, 'courseid2'=>$courseid, 'conceptlower'=>$conceptlower, 'concept'=>$concept);
1006  
1007      return $DB->get_records_sql("SELECT e.*, g.name as glossaryname, cm.id as cmid, cm.course as courseid
1008                                     FROM {glossary_entries} e, {glossary} g,
1009                                          {course_modules} cm, {modules} m
1010                                    WHERE m.name = 'glossary' AND
1011                                          cm.module = m.id AND
1012                                          (cm.visible = 1 OR  cm.visible = $bypassadmin OR
1013                                              (cm.course = :courseid1 AND cm.visible = $bypassteacher)) AND
1014                                          g.id = cm.instance AND
1015                                          e.glossaryid = g.id  AND
1016                                          ( (e.casesensitive != 0 AND LOWER(concept) = :conceptlower) OR
1017                                            (e.casesensitive = 0 and concept = :concept)) AND
1018                                          (g.course = :courseid2 OR g.globalglossary = 1) AND
1019                                           e.usedynalink != 0 AND
1020                                           g.usedynalink != 0", $params);
1021  }
1022  
1023  /**
1024   * @global object
1025   * @global object
1026   * @param object $course
1027   * @param object $course
1028   * @param object $glossary
1029   * @param object $entry
1030   * @param string $mode
1031   * @param string $hook
1032   * @param int $printicons
1033   * @param int $displayformat
1034   * @param bool $printview
1035   * @return mixed
1036   */
1037  function glossary_print_entry($course, $cm, $glossary, $entry, $mode='',$hook='',$printicons = 1, $displayformat  = -1, $printview = false) {
1038      global $USER, $CFG;
1039      $return = false;
1040      if ( $displayformat < 0 ) {
1041          $displayformat = $glossary->displayformat;
1042      }
1043      if ($entry->approved or ($USER->id == $entry->userid) or ($mode == 'approval' and !$entry->approved) ) {
1044          $formatfile = $CFG->dirroot.'/mod/glossary/formats/'.$displayformat.'/'.$displayformat.'_format.php';
1045          if ($printview) {
1046              $functionname = 'glossary_print_entry_'.$displayformat;
1047          } else {
1048              $functionname = 'glossary_show_entry_'.$displayformat;
1049          }
1050  
1051          if (file_exists($formatfile)) {
1052              include_once($formatfile);
1053              if (function_exists($functionname)) {
1054                  $return = $functionname($course, $cm, $glossary, $entry,$mode,$hook,$printicons);
1055              } else if ($printview) {
1056                  //If the glossary_print_entry_XXXX function doesn't exist, print default (old) print format
1057                  $return = glossary_print_entry_default($entry, $glossary, $cm);
1058              }
1059          }
1060      }
1061      return $return;
1062  }
1063  
1064  /**
1065   * Default (old) print format used if custom function doesn't exist in format
1066   *
1067   * @param object $entry
1068   * @param object $glossary
1069   * @param object $cm
1070   * @return void Output is echo'd
1071   */
1072  function glossary_print_entry_default ($entry, $glossary, $cm) {
1073      global $CFG;
1074  
1075      require_once($CFG->libdir . '/filelib.php');
1076  
1077      echo $OUTPUT->heading(strip_tags($entry->concept), 4);
1078  
1079      $definition = $entry->definition;
1080  
1081      $definition = '<span class="nolink">' . strip_tags($definition) . '</span>';
1082  
1083      $context = context_module::instance($cm->id);
1084      $definition = file_rewrite_pluginfile_urls($definition, 'pluginfile.php', $context->id, 'mod_glossary', 'entry', $entry->id);
1085  
1086      $options = new stdClass();
1087      $options->para = false;
1088      $options->trusted = $entry->definitiontrust;
1089      $options->context = $context;
1090      $options->overflowdiv = true;
1091      $definition = format_text($definition, $entry->definitionformat, $options);
1092      echo ($definition);
1093      echo '<br /><br />';
1094  }
1095  
1096  /**
1097   * Print glossary concept/term as a heading &lt;h4>
1098   * @param object $entry
1099   */
1100  function  glossary_print_entry_concept($entry, $return=false) {
1101      global $OUTPUT;
1102  
1103      $text = $OUTPUT->heading(format_string($entry->concept), 4);
1104      if (!empty($entry->highlight)) {
1105          $text = highlight($entry->highlight, $text);
1106      }
1107  
1108      if ($return) {
1109          return $text;
1110      } else {
1111          echo $text;
1112      }
1113  }
1114  
1115  /**
1116   *
1117   * @global moodle_database DB
1118   * @param object $entry
1119   * @param object $glossary
1120   * @param object $cm
1121   */
1122  function glossary_print_entry_definition($entry, $glossary, $cm) {
1123      global $GLOSSARY_EXCLUDEENTRY;
1124  
1125      $definition = $entry->definition;
1126  
1127      // Do not link self.
1128      $GLOSSARY_EXCLUDEENTRY = $entry->id;
1129  
1130      $context = context_module::instance($cm->id);
1131      $definition = file_rewrite_pluginfile_urls($definition, 'pluginfile.php', $context->id, 'mod_glossary', 'entry', $entry->id);
1132  
1133      $options = new stdClass();
1134      $options->para = false;
1135      $options->trusted = $entry->definitiontrust;
1136      $options->context = $context;
1137      $options->overflowdiv = true;
1138  
1139      $text = format_text($definition, $entry->definitionformat, $options);
1140  
1141      // Stop excluding concepts from autolinking
1142      unset($GLOSSARY_EXCLUDEENTRY);
1143  
1144      if (!empty($entry->highlight)) {
1145          $text = highlight($entry->highlight, $text);
1146      }
1147      if (isset($entry->footer)) {   // Unparsed footer info
1148          $text .= $entry->footer;
1149      }
1150      echo $text;
1151  }
1152  
1153  /**
1154   *
1155   * @global object
1156   * @param object $course
1157   * @param object $cm
1158   * @param object $glossary
1159   * @param object $entry
1160   * @param string $mode
1161   * @param string $hook
1162   * @param string $type
1163   * @return string|void
1164   */
1165  function  glossary_print_entry_aliases($course, $cm, $glossary, $entry,$mode='',$hook='', $type = 'print') {
1166      global $DB;
1167  
1168      $return = '';
1169      if ( $aliases = $DB->get_records('glossary_alias', array('entryid'=>$entry->id))) {
1170          foreach ($aliases as $alias) {
1171              if (trim($alias->alias)) {
1172                  if ($return == '') {
1173                      $return = '<select id="keyword" style="font-size:8pt">';
1174                  }
1175                  $return .= "<option>$alias->alias</option>";
1176              }
1177          }
1178          if ($return != '') {
1179              $return .= '</select>';
1180          }
1181      }
1182      if ($type == 'print') {
1183          echo $return;
1184      } else {
1185          return $return;
1186      }
1187  }
1188  
1189  /**
1190   *
1191   * @global object
1192   * @global object
1193   * @global object
1194   * @param object $course
1195   * @param object $cm
1196   * @param object $glossary
1197   * @param object $entry
1198   * @param string $mode
1199   * @param string $hook
1200   * @param string $type
1201   * @return string|void
1202   */
1203  function glossary_print_entry_icons($course, $cm, $glossary, $entry, $mode='',$hook='', $type = 'print') {
1204      global $USER, $CFG, $DB, $OUTPUT;
1205  
1206      $context = context_module::instance($cm->id);
1207  
1208      $output = false;   //To decide if we must really return text in "return". Activate when needed only!
1209      $importedentry = ($entry->sourceglossaryid == $glossary->id);
1210      $ismainglossary = $glossary->mainglossary;
1211  
1212  
1213      $return = '<span class="commands">';
1214      // Differentiate links for each entry.
1215      $altsuffix = ': '.strip_tags(format_text($entry->concept));
1216  
1217      if (!$entry->approved) {
1218          $output = true;
1219          $return .= html_writer::tag('span', get_string('entryishidden','glossary'),
1220              array('class' => 'glossary-hidden-note'));
1221      }
1222  
1223      if (has_capability('mod/glossary:approve', $context) && !$glossary->defaultapproval && $entry->approved) {
1224          $output = true;
1225          $return .= '<a class="action-icon" title="' . get_string('disapprove', 'glossary').
1226                     '" href="approve.php?newstate=0&amp;eid='.$entry->id.'&amp;mode='.$mode.
1227                     '&amp;hook='.urlencode($hook).'&amp;sesskey='.sesskey().
1228                     '"><img src="'.$OUTPUT->pix_url('t/block').'" class="smallicon" alt="'.
1229                     get_string('disapprove','glossary').$altsuffix.'" /></a>';
1230      }
1231  
1232      $iscurrentuser = ($entry->userid == $USER->id);
1233  
1234      if (has_capability('mod/glossary:manageentries', $context) or (isloggedin() and has_capability('mod/glossary:write', $context) and $iscurrentuser)) {
1235          // only teachers can export entries so check it out
1236          if (has_capability('mod/glossary:export', $context) and !$ismainglossary and !$importedentry) {
1237              $mainglossary = $DB->get_record('glossary', array('mainglossary'=>1,'course'=>$course->id));
1238              if ( $mainglossary ) {  // if there is a main glossary defined, allow to export the current entry
1239                  $output = true;
1240                  $return .= '<a class="action-icon" title="'.get_string('exporttomainglossary','glossary') . '" href="exportentry.php?id='.$entry->id.'&amp;prevmode='.$mode.'&amp;hook='.urlencode($hook).'"><img src="'.$OUTPUT->pix_url('export', 'glossary').'" class="smallicon" alt="'.get_string('exporttomainglossary','glossary').$altsuffix.'" /></a>';
1241              }
1242          }
1243  
1244          if ( $entry->sourceglossaryid ) {
1245              $icon = $OUTPUT->pix_url('minus', 'glossary');   // graphical metaphor (minus) for deleting an imported entry
1246          } else {
1247              $icon = $OUTPUT->pix_url('t/delete');
1248          }
1249  
1250          //Decide if an entry is editable:
1251          // -It isn't a imported entry (so nobody can edit a imported (from secondary to main) entry)) and
1252          // -The user is teacher or he is a student with time permissions (edit period or editalways defined).
1253          $ineditperiod = ((time() - $entry->timecreated <  $CFG->maxeditingtime) || $glossary->editalways);
1254          if ( !$importedentry and (has_capability('mod/glossary:manageentries', $context) or ($entry->userid == $USER->id and ($ineditperiod and has_capability('mod/glossary:write', $context))))) {
1255              $output = true;
1256              $return .= "<a class='action-icon' title=\"" . get_string("delete") . "\" href=\"deleteentry.php?id=$cm->id&amp;mode=delete&amp;entry=$entry->id&amp;prevmode=$mode&amp;hook=".urlencode($hook)."\"><img src=\"";
1257              $return .= $icon;
1258              $return .= "\" class=\"smallicon\" alt=\"" . get_string("delete") .$altsuffix."\" /></a>";
1259  
1260              $return .= "<a class='action-icon' title=\"" . get_string("edit") . "\" href=\"edit.php?cmid=$cm->id&amp;id=$entry->id&amp;mode=$mode&amp;hook=".urlencode($hook)."\"><img src=\"" . $OUTPUT->pix_url('t/edit') . "\" class=\"smallicon\" alt=\"" . get_string("edit") .$altsuffix. "\" /></a>";
1261          } elseif ( $importedentry ) {
1262              $return .= "<font size=\"-1\">" . get_string("exportedentry","glossary") . "</font>";
1263          }
1264      }
1265      if (!empty($CFG->enableportfolios) && (has_capability('mod/glossary:exportentry', $context) || ($iscurrentuser && has_capability('mod/glossary:exportownentry', $context)))) {
1266          require_once($CFG->libdir . '/portfoliolib.php');
1267          $button = new portfolio_add_button();
1268          $button->set_callback_options('glossary_entry_portfolio_caller',  array('id' => $cm->id, 'entryid' => $entry->id), 'mod_glossary');
1269  
1270          $filecontext = $context;
1271          if ($entry->sourceglossaryid == $cm->instance) {
1272              if ($maincm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
1273                  $filecontext = context_module::instance($maincm->id);
1274              }
1275          }
1276          $fs = get_file_storage();
1277          if ($files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'attachment', $entry->id, "timemodified", false)
1278           || $files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'entry', $entry->id, "timemodified", false)) {
1279  
1280              $button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
1281          } else {
1282              $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
1283          }
1284  
1285          $return .= $button->to_html(PORTFOLIO_ADD_ICON_LINK);
1286      }
1287      $return .= '</span>';
1288  
1289      if (!empty($CFG->usecomments) && has_capability('mod/glossary:comment', $context) and $glossary->allowcomments) {
1290          require_once($CFG->dirroot . '/comment/lib.php');
1291          $cmt = new stdClass();
1292          $cmt->component = 'mod_glossary';
1293          $cmt->context  = $context;
1294          $cmt->course   = $course;
1295          $cmt->cm       = $cm;
1296          $cmt->area     = 'glossary_entry';
1297          $cmt->itemid   = $entry->id;
1298          $cmt->showcount = true;
1299          $comment = new comment($cmt);
1300          $return .= '<div>'.$comment->output(true).'</div>';
1301          $output = true;
1302      }
1303  
1304      //If we haven't calculated any REAL thing, delete result ($return)
1305      if (!$output) {
1306          $return = '';
1307      }
1308      //Print or get
1309      if ($type == 'print') {
1310          echo $return;
1311      } else {
1312          return $return;
1313      }
1314  }
1315  
1316  /**
1317   * @param object $course
1318   * @param object $cm
1319   * @param object $glossary
1320   * @param object $entry
1321   * @param string $mode
1322   * @param object $hook
1323   * @param bool $printicons
1324   * @param bool $aliases
1325   * @return void
1326   */
1327  function  glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $mode, $hook, $printicons, $aliases=true) {
1328      if ($aliases) {
1329          $aliases = glossary_print_entry_aliases($course, $cm, $glossary, $entry, $mode, $hook,'html');
1330      }
1331      $icons   = '';
1332      if ($printicons) {
1333          $icons   = glossary_print_entry_icons($course, $cm, $glossary, $entry, $mode, $hook,'html');
1334      }
1335      if ($aliases || $icons || !empty($entry->rating)) {
1336          echo '<table>';
1337          if ( $aliases ) {
1338              echo '<tr valign="top"><td class="aliases">' .
1339                   '<label for="keyword">' . get_string('aliases','glossary').': </label>' .
1340                   $aliases . '</td></tr>';
1341          }
1342          if ($icons) {
1343              echo '<tr valign="top"><td class="icons">'.$icons.'</td></tr>';
1344          }
1345          if (!empty($entry->rating)) {
1346              echo '<tr valign="top"><td class="ratings">';
1347              glossary_print_entry_ratings($course, $entry);
1348              echo '</td></tr>';
1349          }
1350          echo '</table>';
1351      }
1352  }
1353  
1354  /**
1355   * Print the list of attachments for this glossary entry
1356   *
1357   * @param object $entry
1358   * @param object $cm The coursemodule
1359   * @param string $format The format for this view (html, or text)
1360   * @param string $unused1 This parameter is no longer used
1361   * @param string $unused2 This parameter is no longer used
1362   */
1363  function glossary_print_entry_attachment($entry, $cm, $format = null, $unused1 = null, $unused2 = null) {
1364      // Valid format values: html: The HTML link for the attachment is an icon; and
1365      //                      text: The HTML link for the attachment is text.
1366      if ($entry->attachment) {
1367          echo '<div class="attachments">';
1368          echo glossary_print_attachments($entry, $cm, $format);
1369          echo '</div>';
1370      }
1371      if ($unused1) {
1372          debugging('The align parameter is deprecated, please use appropriate CSS instead', DEBUG_DEVELOPER);
1373      }
1374      if ($unused2 !== null) {
1375          debugging('The insidetable parameter is deprecated, please use appropriate CSS instead', DEBUG_DEVELOPER);
1376      }
1377  }
1378  
1379  /**
1380   * @global object
1381   * @param object $cm
1382   * @param object $entry
1383   * @param string $mode
1384   * @param string $align
1385   * @param bool $insidetable
1386   */
1387  function  glossary_print_entry_approval($cm, $entry, $mode, $align="right", $insidetable=true) {
1388      global $CFG, $OUTPUT;
1389  
1390      if ($mode == 'approval' and !$entry->approved) {
1391          if ($insidetable) {
1392              echo '<table class="glossaryapproval" align="'.$align.'"><tr><td align="'.$align.'">';
1393          }
1394          echo $OUTPUT->action_icon(
1395              new moodle_url('approve.php', array('eid' => $entry->id, 'mode' => $mode, 'sesskey' => sesskey())),
1396              new pix_icon('t/approve', get_string('approve','glossary'), '',
1397                  array('class' => 'iconsmall', 'align' => $align))
1398          );
1399          if ($insidetable) {
1400              echo '</td></tr></table>';
1401          }
1402      }
1403  }
1404  
1405  /**
1406   * It returns all entries from all glossaries that matches the specified criteria
1407   *  within a given $course. It performs an $extended search if necessary.
1408   * It restrict the search to only one $glossary if the $glossary parameter is set.
1409   *
1410   * @global object
1411   * @global object
1412   * @param object $course
1413   * @param array $searchterms
1414   * @param int $extended
1415   * @param object $glossary
1416   * @return array
1417   */
1418  function glossary_search($course, $searchterms, $extended = 0, $glossary = NULL) {
1419      global $CFG, $DB;
1420  
1421      if ( !$glossary ) {
1422          if ( $glossaries = $DB->get_records("glossary", array("course"=>$course->id)) ) {
1423              $glos = "";
1424              foreach ( $glossaries as $glossary ) {
1425                  $glos .= "$glossary->id,";
1426              }
1427              $glos = substr($glos,0,-1);
1428          }
1429      } else {
1430          $glos = $glossary->id;
1431      }
1432  
1433      if (!has_capability('mod/glossary:manageentries', context_course::instance($glossary->course))) {
1434          $glossarymodule = $DB->get_record("modules", array("name"=>"glossary"));
1435          $onlyvisible = " AND g.id = cm.instance AND cm.visible = 1 AND cm.module = $glossarymodule->id";
1436          $onlyvisibletable = ", {course_modules} cm";
1437      } else {
1438  
1439          $onlyvisible = "";
1440          $onlyvisibletable = "";
1441      }
1442  
1443      if ($DB->sql_regex_supported()) {
1444          $REGEXP    = $DB->sql_regex(true);
1445          $NOTREGEXP = $DB->sql_regex(false);
1446      }
1447  
1448      $searchcond = array();
1449      $params     = array();
1450      $i = 0;
1451  
1452      $concat = $DB->sql_concat('e.concept', "' '", 'e.definition');
1453  
1454  
1455      foreach ($searchterms as $searchterm) {
1456          $i++;
1457  
1458          $NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle
1459                     /// will use it to simulate the "-" operator with LIKE clause
1460  
1461      /// Under Oracle and MSSQL, trim the + and - operators and perform
1462      /// simpler LIKE (or NOT LIKE) queries
1463          if (!$DB->sql_regex_supported()) {
1464              if (substr($searchterm, 0, 1) == '-') {
1465                  $NOT = true;
1466              }
1467              $searchterm = trim($searchterm, '+-');
1468          }
1469  
1470          // TODO: +- may not work for non latin languages
1471  
1472          if (substr($searchterm,0,1) == '+') {
1473              $searchterm = trim($searchterm, '+-');
1474              $searchterm = preg_quote($searchterm, '|');
1475              $searchcond[] = "$concat $REGEXP :ss$i";
1476              $params['ss'.$i] = "(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)";
1477  
1478          } else if (substr($searchterm,0,1) == "-") {
1479              $searchterm = trim($searchterm, '+-');
1480              $searchterm = preg_quote($searchterm, '|');
1481              $searchcond[] = "$concat $NOTREGEXP :ss$i";
1482              $params['ss'.$i] = "(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)";
1483  
1484          } else {
1485              $searchcond[] = $DB->sql_like($concat, ":ss$i", false, true, $NOT);
1486              $params['ss'.$i] = "%$searchterm%";
1487          }
1488      }
1489  
1490      if (empty($searchcond)) {
1491          $totalcount = 0;
1492          return array();
1493      }
1494  
1495      $searchcond = implode(" AND ", $searchcond);
1496  
1497      $sql = "SELECT e.*
1498                FROM {glossary_entries} e, {glossary} g $onlyvisibletable
1499               WHERE $searchcond
1500                 AND (e.glossaryid = g.id or e.sourceglossaryid = g.id) $onlyvisible
1501                 AND g.id IN ($glos) AND e.approved <> 0";
1502  
1503      return $DB->get_records_sql($sql, $params);
1504  }
1505  
1506  /**
1507   * @global object
1508   * @param array $searchterms
1509   * @param object $glossary
1510   * @param bool $extended
1511   * @return array
1512   */
1513  function glossary_search_entries($searchterms, $glossary, $extended) {
1514      global $DB;
1515  
1516      $course = $DB->get_record("course", array("id"=>$glossary->course));
1517      return glossary_search($course,$searchterms,$extended,$glossary);
1518  }
1519  
1520  /**
1521   * if return=html, then return a html string.
1522   * if return=text, then return a text-only string.
1523   * otherwise, print HTML for non-images, and return image HTML
1524   *     if attachment is an image, $align set its aligment.
1525   *
1526   * @global object
1527   * @global object
1528   * @param object $entry
1529   * @param object $cm
1530   * @param string $type html, txt, empty
1531   * @param string $unused This parameter is no longer used
1532   * @return string image string or nothing depending on $type param
1533   */
1534  function glossary_print_attachments($entry, $cm, $type=NULL, $unused = null) {
1535      global $CFG, $DB, $OUTPUT;
1536  
1537      if (!$context = context_module::instance($cm->id, IGNORE_MISSING)) {
1538          return '';
1539      }
1540  
1541      if ($entry->sourceglossaryid == $cm->instance) {
1542          if (!$maincm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
1543              return '';
1544          }
1545          $filecontext = context_module::instance($maincm->id);
1546  
1547      } else {
1548          $filecontext = $context;
1549      }
1550  
1551      $strattachment = get_string('attachment', 'glossary');
1552  
1553      $fs = get_file_storage();
1554  
1555      $imagereturn = '';
1556      $output = '';
1557  
1558      if ($files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'attachment', $entry->id, "timemodified", false)) {
1559          foreach ($files as $file) {
1560              $filename = $file->get_filename();
1561              $mimetype = $file->get_mimetype();
1562              $iconimage = $OUTPUT->pix_icon(file_file_icon($file), get_mimetype_description($file), 'moodle', array('class' => 'icon'));
1563              $path = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$context->id.'/mod_glossary/attachment/'.$entry->id.'/'.$filename);
1564  
1565              if ($type == 'html') {
1566                  $output .= "<a href=\"$path\">$iconimage</a> ";
1567                  $output .= "<a href=\"$path\">".s($filename)."</a>";
1568                  $output .= "<br />";
1569  
1570              } else if ($type == 'text') {
1571                  $output .= "$strattachment ".s($filename).":\n$path\n";
1572  
1573              } else {
1574                  if (in_array($mimetype, array('image/gif', 'image/jpeg', 'image/png'))) {
1575                      // Image attachments don't get printed as links
1576                      $imagereturn .= "<br /><img src=\"$path\" alt=\"\" />";
1577                  } else {
1578                      $output .= "<a href=\"$path\">$iconimage</a> ";
1579                      $output .= format_text("<a href=\"$path\">".s($filename)."</a>", FORMAT_HTML, array('context'=>$context));
1580                      $output .= '<br />';
1581                  }
1582              }
1583          }
1584      }
1585  
1586      if ($type) {
1587          return $output;
1588      } else {
1589          echo $output;
1590          return $imagereturn;
1591      }
1592  }
1593  
1594  ////////////////////////////////////////////////////////////////////////////////
1595  // File API                                                                   //
1596  ////////////////////////////////////////////////////////////////////////////////
1597  
1598  /**
1599   * Lists all browsable file areas
1600   *
1601   * @package  mod_glossary
1602   * @category files
1603   * @param stdClass $course course object
1604   * @param stdClass $cm course module object
1605   * @param stdClass $context context object
1606   * @return array
1607   */
1608  function glossary_get_file_areas($course, $cm, $context) {
1609      return array(
1610          'attachment' => get_string('areaattachment', 'mod_glossary'),
1611          'entry' => get_string('areaentry', 'mod_glossary'),
1612      );
1613  }
1614  
1615  /**
1616   * File browsing support for glossary module.
1617   *
1618   * @param file_browser $browser
1619   * @param array $areas
1620   * @param stdClass $course
1621   * @param cm_info $cm
1622   * @param context $context
1623   * @param string $filearea
1624   * @param int $itemid
1625   * @param string $filepath
1626   * @param string $filename
1627   * @return file_info_stored file_info_stored instance or null if not found
1628   */
1629  function glossary_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
1630      global $CFG, $DB, $USER;
1631  
1632      if ($context->contextlevel != CONTEXT_MODULE) {
1633          return null;
1634      }
1635  
1636      if (!isset($areas[$filearea])) {
1637          return null;
1638      }
1639  
1640      if (is_null($itemid)) {
1641          require_once($CFG->dirroot.'/mod/glossary/locallib.php');
1642          return new glossary_file_info_container($browser, $course, $cm, $context, $areas, $filearea);
1643      }
1644  
1645      if (!$entry = $DB->get_record('glossary_entries', array('id' => $itemid))) {
1646          return null;
1647      }
1648  
1649      if (!$glossary = $DB->get_record('glossary', array('id' => $cm->instance))) {
1650          return null;
1651      }
1652  
1653      if ($glossary->defaultapproval and !$entry->approved and !has_capability('mod/glossary:approve', $context)) {
1654          return null;
1655      }
1656  
1657      // this trickery here is because we need to support source glossary access
1658      if ($entry->glossaryid == $cm->instance) {
1659          $filecontext = $context;
1660      } else if ($entry->sourceglossaryid == $cm->instance) {
1661          if (!$maincm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
1662              return null;
1663          }
1664          $filecontext = context_module::instance($maincm->id);
1665      } else {
1666          return null;
1667      }
1668  
1669      $fs = get_file_storage();
1670      $filepath = is_null($filepath) ? '/' : $filepath;
1671      $filename = is_null($filename) ? '.' : $filename;
1672      if (!($storedfile = $fs->get_file($filecontext->id, 'mod_glossary', $filearea, $itemid, $filepath, $filename))) {
1673          return null;
1674      }
1675  
1676      // Checks to see if the user can manage files or is the owner.
1677      // TODO MDL-33805 - Do not use userid here and move the capability check above.
1678      if (!has_capability('moodle/course:managefiles', $context) && $storedfile->get_userid() != $USER->id) {
1679          return null;
1680      }
1681  
1682      $urlbase = $CFG->wwwroot.'/pluginfile.php';
1683  
1684      return new file_info_stored($browser, $filecontext, $storedfile, $urlbase, s($entry->concept), true, true, false, false);
1685  }
1686  
1687  /**
1688   * Serves the glossary attachments. Implements needed access control ;-)
1689   *
1690   * @package  mod_glossary
1691   * @category files
1692   * @param stdClass $course course object
1693   * @param stdClass $cm course module object
1694   * @param stdClsss $context context object
1695   * @param string $filearea file area
1696   * @param array $args extra arguments
1697   * @param bool $forcedownload whether or not force download
1698   * @param array $options additional options affecting the file serving
1699   * @return bool false if file not found, does not return if found - justsend the file
1700   */
1701  function glossary_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
1702      global $CFG, $DB;
1703  
1704      if ($context->contextlevel != CONTEXT_MODULE) {
1705          return false;
1706      }
1707  
1708      require_course_login($course, true, $cm);
1709  
1710      if ($filearea === 'attachment' or $filearea === 'entry') {
1711          $entryid = (int)array_shift($args);
1712  
1713          require_course_login($course, true, $cm);
1714  
1715          if (!$entry = $DB->get_record('glossary_entries', array('id'=>$entryid))) {
1716              return false;
1717          }
1718  
1719          if (!$glossary = $DB->get_record('glossary', array('id'=>$cm->instance))) {
1720              return false;
1721          }
1722  
1723          if ($glossary->defaultapproval and !$entry->approved and !has_capability('mod/glossary:approve', $context)) {
1724              return false;
1725          }
1726  
1727          // this trickery here is because we need to support source glossary access
1728  
1729          if ($entry->glossaryid == $cm->instance) {
1730              $filecontext = $context;
1731  
1732          } else if ($entry->sourceglossaryid == $cm->instance) {
1733              if (!$maincm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
1734                  return false;
1735              }
1736              $filecontext = context_module::instance($maincm->id);
1737  
1738          } else {
1739              return false;
1740          }
1741  
1742          $relativepath = implode('/', $args);
1743          $fullpath = "/$filecontext->id/mod_glossary/$filearea/$entryid/$relativepath";
1744  
1745          $fs = get_file_storage();
1746          if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
1747              return false;
1748          }
1749  
1750          // finally send the file
1751          send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
1752  
1753      } else if ($filearea === 'export') {
1754          require_login($course, false, $cm);
1755          require_capability('mod/glossary:export', $context);
1756  
1757          if (!$glossary = $DB->get_record('glossary', array('id'=>$cm->instance))) {
1758              return false;
1759          }
1760  
1761          $cat = array_shift($args);
1762          $cat = clean_param($cat, PARAM_ALPHANUM);
1763  
1764          $filename = clean_filename(strip_tags(format_string($glossary->name)).'.xml');
1765          $content = glossary_generate_export_file($glossary, NULL, $cat);
1766  
1767          send_file($content, $filename, 0, 0, true, true);
1768      }
1769  
1770      return false;
1771  }
1772  
1773  /**
1774   *
1775   */
1776  function glossary_print_tabbed_table_end() {
1777       echo "</div></div>";
1778  }
1779  
1780  /**
1781   * @param object $cm
1782   * @param object $glossary
1783   * @param string $mode
1784   * @param string $hook
1785   * @param string $sortkey
1786   * @param string $sortorder
1787   */
1788  function glossary_print_approval_menu($cm, $glossary,$mode, $hook, $sortkey = '', $sortorder = '') {
1789      if ($glossary->showalphabet) {
1790          echo '<div class="glossaryexplain">' . get_string("explainalphabet","glossary") . '</div><br />';
1791      }
1792      glossary_print_special_links($cm, $glossary, $mode, $hook);
1793  
1794      glossary_print_alphabet_links($cm, $glossary, $mode, $hook,$sortkey, $sortorder);
1795  
1796      glossary_print_all_links($cm, $glossary, $mode, $hook);
1797  
1798      glossary_print_sorting_links($cm, $mode, 'CREATION', 'asc');
1799  }
1800  /**
1801   * @param object $cm
1802   * @param object $glossary
1803   * @param string $hook
1804   * @param string $sortkey
1805   * @param string $sortorder
1806   */
1807  function glossary_print_import_menu($cm, $glossary, $mode, $hook, $sortkey='', $sortorder = '') {
1808      echo '<div class="glossaryexplain">' . get_string("explainimport","glossary") . '</div>';
1809  }
1810  
1811  /**
1812   * @param object $cm
1813   * @param object $glossary
1814   * @param string $hook
1815   * @param string $sortkey
1816   * @param string $sortorder
1817   */
1818  function glossary_print_export_menu($cm, $glossary, $mode, $hook, $sortkey='', $sortorder = '') {
1819      echo '<div class="glossaryexplain">' . get_string("explainexport","glossary") . '</div>';
1820  }
1821  /**
1822   * @param object $cm
1823   * @param object $glossary
1824   * @param string $hook
1825   * @param string $sortkey
1826   * @param string $sortorder
1827   */
1828  function glossary_print_alphabet_menu($cm, $glossary, $mode, $hook, $sortkey='', $sortorder = '') {
1829      if ( $mode != 'date' ) {
1830          if ($glossary->showalphabet) {
1831              echo '<div class="glossaryexplain">' . get_string("explainalphabet","glossary") . '</div><br />';
1832          }
1833  
1834          glossary_print_special_links($cm, $glossary, $mode, $hook);
1835  
1836          glossary_print_alphabet_links($cm, $glossary, $mode, $hook, $sortkey, $sortorder);
1837  
1838          glossary_print_all_links($cm, $glossary, $mode, $hook);
1839      } else {
1840          glossary_print_sorting_links($cm, $mode, $sortkey,$sortorder);
1841      }
1842  }
1843  
1844  /**
1845   * @param object $cm
1846   * @param object $glossary
1847   * @param string $hook
1848   * @param string $sortkey
1849   * @param string $sortorder
1850   */
1851  function glossary_print_author_menu($cm, $glossary,$mode, $hook, $sortkey = '', $sortorder = '') {
1852      if ($glossary->showalphabet) {
1853          echo '<div class="glossaryexplain">' . get_string("explainalphabet","glossary") . '</div><br />';
1854      }
1855  
1856      glossary_print_alphabet_links($cm, $glossary, $mode, $hook, $sortkey, $sortorder);
1857      glossary_print_all_links($cm, $glossary, $mode, $hook);
1858      glossary_print_sorting_links($cm, $mode, $sortkey,$sortorder);
1859  }
1860  
1861  /**
1862   * @global object
1863   * @global object
1864   * @param object $cm
1865   * @param object $glossary
1866   * @param string $hook
1867   * @param object $category
1868   */
1869  function glossary_print_categories_menu($cm, $glossary, $hook, $category) {
1870       global $CFG, $DB, $OUTPUT;
1871  
1872       $context = context_module::instance($cm->id);
1873  
1874      // Prepare format_string/text options
1875      $fmtoptions = array(
1876          'context' => $context);
1877  
1878       echo '<table border="0" width="100%">';
1879       echo '<tr>';
1880  
1881       echo '<td align="center" style="width:20%">';
1882       if (has_capability('mod/glossary:managecategories', $context)) {
1883               $options['id'] = $cm->id;
1884               $options['mode'] = 'cat';
1885               $options['hook'] = $hook;
1886               echo $OUTPUT->single_button(new moodle_url("editcategories.php", $options), get_string("editcategories","glossary"), "get");
1887       }
1888       echo '</td>';
1889  
1890       echo '<td align="center" style="width:60%">';
1891       echo '<b>';
1892  
1893       $menu = array();
1894       $menu[GLOSSARY_SHOW_ALL_CATEGORIES] = get_string("allcategories","glossary");
1895       $menu[GLOSSARY_SHOW_NOT_CATEGORISED] = get_string("notcategorised","glossary");
1896  
1897       $categories = $DB->get_records("glossary_categories", array("glossaryid"=>$glossary->id), "name ASC");
1898       $selected = '';
1899       if ( $categories ) {
1900            foreach ($categories as $currentcategory) {
1901                   $url = $currentcategory->id;
1902                   if ( $category ) {
1903                       if ($currentcategory->id == $category->id) {
1904                           $selected = $url;
1905                       }
1906                   }
1907                   $menu[$url] = format_string($currentcategory->name, true, $fmtoptions);
1908            }
1909       }
1910       if ( !$selected ) {
1911           $selected = GLOSSARY_SHOW_NOT_CATEGORISED;
1912       }
1913  
1914       if ( $category ) {
1915          echo format_string($category->name, true, $fmtoptions);
1916       } else {
1917          if ( $hook == GLOSSARY_SHOW_NOT_CATEGORISED ) {
1918  
1919              echo get_string("entrieswithoutcategory","glossary");
1920              $selected = GLOSSARY_SHOW_NOT_CATEGORISED;
1921  
1922          } elseif ( $hook == GLOSSARY_SHOW_ALL_CATEGORIES ) {
1923  
1924              echo get_string("allcategories","glossary");
1925              $selected = GLOSSARY_SHOW_ALL_CATEGORIES;
1926  
1927          }
1928       }
1929       echo '</b></td>';
1930       echo '<td align="center" style="width:20%">';
1931  
1932       $select = new single_select(new moodle_url("/mod/glossary/view.php", array('id'=>$cm->id, 'mode'=>'cat')), 'hook', $menu, $selected, null, "catmenu");
1933       $select->set_label(get_string('categories', 'glossary'), array('class' => 'accesshide'));
1934       echo $OUTPUT->render($select);
1935  
1936       echo '</td>';
1937       echo '</tr>';
1938  
1939       echo '</table>';
1940  }
1941  
1942  /**
1943   * @global object
1944   * @param object $cm
1945   * @param object $glossary
1946   * @param string $mode
1947   * @param string $hook
1948   */
1949  function glossary_print_all_links($cm, $glossary, $mode, $hook) {
1950  global $CFG;
1951       if ( $glossary->showall) {
1952           $strallentries       = get_string("allentries", "glossary");
1953           if ( $hook == 'ALL' ) {
1954                echo "<b>$strallentries</b>";
1955           } else {
1956                $strexplainall = strip_tags(get_string("explainall","glossary"));
1957                echo "<a title=\"$strexplainall\" href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;mode=$mode&amp;hook=ALL\">$strallentries</a>";
1958           }
1959       }
1960  }
1961  
1962  /**
1963   * @global object
1964   * @param object $cm
1965   * @param object $glossary
1966   * @param string $mode
1967   * @param string $hook
1968   */
1969  function glossary_print_special_links($cm, $glossary, $mode, $hook) {
1970  global $CFG;
1971       if ( $glossary->showspecial) {
1972           $strspecial          = get_string("special", "glossary");
1973           if ( $hook == 'SPECIAL' ) {
1974                echo "<b>$strspecial</b> | ";
1975           } else {
1976                $strexplainspecial = strip_tags(get_string("explainspecial","glossary"));
1977                echo "<a title=\"$strexplainspecial\" href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;mode=$mode&amp;hook=SPECIAL\">$strspecial</a> | ";
1978           }
1979       }
1980  }
1981  
1982  /**
1983   * @global object
1984   * @param object $glossary
1985   * @param string $mode
1986   * @param string $hook
1987   * @param string $sortkey
1988   * @param string $sortorder
1989   */
1990  function glossary_print_alphabet_links($cm, $glossary, $mode, $hook, $sortkey, $sortorder) {
1991  global $CFG;
1992       if ( $glossary->showalphabet) {
1993            $alphabet = explode(",", get_string('alphabet', 'langconfig'));
1994            for ($i = 0; $i < count($alphabet); $i++) {
1995                if ( $hook == $alphabet[$i] and $hook) {
1996                     echo "<b>$alphabet[$i]</b>";
1997                } else {
1998                     echo "<a href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;mode=$mode&amp;hook=".urlencode($alphabet[$i])."&amp;sortkey=$sortkey&amp;sortorder=$sortorder\">$alphabet[$i]</a>";
1999                }
2000                echo ' | ';
2001            }
2002       }
2003  }
2004  
2005  /**
2006   * @global object
2007   * @param object $cm
2008   * @param string $mode
2009   * @param string $sortkey
2010   * @param string $sortorder
2011   */
2012  function glossary_print_sorting_links($cm, $mode, $sortkey = '',$sortorder = '') {
2013      global $CFG, $OUTPUT;
2014  
2015      $asc    = get_string("ascending","glossary");
2016      $desc   = get_string("descending","glossary");
2017      $bopen  = '<b>';
2018      $bclose = '</b>';
2019  
2020       $neworder = '';
2021       $currentorder = '';
2022       $currentsort = '';
2023       if ( $sortorder ) {
2024           if ( $sortorder == 'asc' ) {
2025               $currentorder = $asc;
2026               $neworder = '&amp;sortorder=desc';
2027               $newordertitle = get_string('changeto', 'glossary', $desc);
2028           } else {
2029               $currentorder = $desc;
2030               $neworder = '&amp;sortorder=asc';
2031               $newordertitle = get_string('changeto', 'glossary', $asc);
2032           }
2033           $icon = " <img src=\"".$OUTPUT->pix_url($sortorder, 'glossary')."\" class=\"icon\" alt=\"$newordertitle\" />";
2034       } else {
2035           if ( $sortkey != 'CREATION' and $sortkey != 'UPDATE' and
2036                 $sortkey != 'FIRSTNAME' and $sortkey != 'LASTNAME' ) {
2037               $icon = "";
2038               $newordertitle = $asc;
2039           } else {
2040               $newordertitle = $desc;
2041               $neworder = '&amp;sortorder=desc';
2042               $icon = ' <img src="'.$OUTPUT->pix_url('asc', 'glossary').'" class="icon" alt="'.$newordertitle.'" />';
2043           }
2044       }
2045       $ficon     = '';
2046       $fneworder = '';
2047       $fbtag     = '';
2048       $fendbtag  = '';
2049  
2050       $sicon     = '';
2051       $sneworder = '';
2052  
2053       $sbtag      = '';
2054       $fbtag      = '';
2055       $fendbtag      = '';
2056       $sendbtag      = '';
2057  
2058       $sendbtag  = '';
2059  
2060       if ( $sortkey == 'CREATION' or $sortkey == 'FIRSTNAME' ) {
2061           $ficon       = $icon;
2062           $fneworder   = $neworder;
2063           $fordertitle = $newordertitle;
2064           $sordertitle = $asc;
2065           $fbtag       = $bopen;
2066           $fendbtag    = $bclose;
2067       } elseif ($sortkey == 'UPDATE' or $sortkey == 'LASTNAME') {
2068           $sicon = $icon;
2069           $sneworder   = $neworder;
2070           $fordertitle = $asc;
2071           $sordertitle = $newordertitle;
2072           $sbtag       = $bopen;
2073           $sendbtag    = $bclose;
2074       } else {
2075           $fordertitle = $asc;
2076           $sordertitle = $asc;
2077       }
2078  
2079       if ( $sortkey == 'CREATION' or $sortkey == 'UPDATE' ) {
2080           $forder = 'CREATION';
2081           $sorder =  'UPDATE';
2082           $fsort  = get_string("sortbycreation", "glossary");
2083           $ssort  = get_string("sortbylastupdate", "glossary");
2084  
2085           $currentsort = $fsort;
2086           if ($sortkey == 'UPDATE') {
2087               $currentsort = $ssort;
2088           }
2089           $sort        = get_string("sortchronogically", "glossary");
2090       } elseif ( $sortkey == 'FIRSTNAME' or $sortkey == 'LASTNAME') {
2091           $forder = 'FIRSTNAME';
2092           $sorder =  'LASTNAME';
2093           $fsort  = get_string("firstname");
2094           $ssort  = get_string("lastname");
2095  
2096           $currentsort = $fsort;
2097           if ($sortkey == 'LASTNAME') {
2098               $currentsort = $ssort;
2099           }
2100           $sort        = get_string("sortby", "glossary");
2101       }
2102       $current = '<span class="accesshide">'.get_string('current', 'glossary', "$currentsort $currentorder").'</span>';
2103       echo "<br />$current $sort: $sbtag<a title=\"$ssort $sordertitle\" href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;sortkey=$sorder$sneworder&amp;mode=$mode\">$ssort$sicon</a>$sendbtag | ".
2104                            "$fbtag<a title=\"$fsort $fordertitle\" href=\"$CFG->wwwroot/mod/glossary/view.php?id=$cm->id&amp;sortkey=$forder$fneworder&amp;mode=$mode\">$fsort$ficon</a>$fendbtag<br />";
2105  }
2106  
2107  /**
2108   *
2109   * @param object $entry0
2110   * @param object $entry1
2111   * @return int [-1 | 0 | 1]
2112   */
2113  function glossary_sort_entries ( $entry0, $entry1 ) {
2114  
2115      if ( core_text::strtolower(ltrim($entry0->concept)) < core_text::strtolower(ltrim($entry1->concept)) ) {
2116          return -1;
2117      } elseif ( core_text::strtolower(ltrim($entry0->concept)) > core_text::strtolower(ltrim($entry1->concept)) ) {
2118          return 1;
2119      } else {
2120          return 0;
2121      }
2122  }
2123  
2124  
2125  /**
2126   * @global object
2127   * @global object
2128   * @global object
2129   * @param object $course
2130   * @param object $entry
2131   * @return bool
2132   */
2133  function  glossary_print_entry_ratings($course, $entry) {
2134      global $OUTPUT;
2135      if( !empty($entry->rating) ){
2136          echo $OUTPUT->render($entry->rating);
2137      }
2138  }
2139  
2140  /**
2141   *
2142   * @global object
2143   * @global object
2144   * @global object
2145   * @param int $courseid
2146   * @param array $entries
2147   * @param int $displayformat
2148   */
2149  function glossary_print_dynaentry($courseid, $entries, $displayformat = -1) {
2150      global $USER,$CFG, $DB;
2151  
2152      echo '<div class="boxaligncenter">';
2153      echo '<table class="glossarypopup" cellspacing="0"><tr>';
2154      echo '<td>';
2155      if ( $entries ) {
2156          foreach ( $entries as $entry ) {
2157              if (! $glossary = $DB->get_record('glossary', array('id'=>$entry->glossaryid))) {
2158                  print_error('invalidid', 'glossary');
2159              }
2160              if (! $course = $DB->get_record('course', array('id'=>$glossary->course))) {
2161                  print_error('coursemisconf');
2162              }
2163              if (!$cm = get_coursemodule_from_instance('glossary', $entry->glossaryid, $glossary->course) ) {
2164                  print_error('invalidid', 'glossary');
2165              }
2166  
2167              //If displayformat is present, override glossary->displayformat
2168              if ($displayformat < 0) {
2169                  $dp = $glossary->displayformat;
2170              } else {
2171                  $dp = $displayformat;
2172              }
2173  
2174              //Get popupformatname
2175              $format = $DB->get_record('glossary_formats', array('name'=>$dp));
2176              $displayformat = $format->popupformatname;
2177  
2178              //Check displayformat variable and set to default if necessary
2179              if (!$displayformat) {
2180                  $displayformat = 'dictionary';
2181              }
2182  
2183              $formatfile = $CFG->dirroot.'/mod/glossary/formats/'.$displayformat.'/'.$displayformat.'_format.php';
2184              $functionname = 'glossary_show_entry_'.$displayformat;
2185  
2186              if (file_exists($formatfile)) {
2187                  include_once($formatfile);
2188                  if (function_exists($functionname)) {
2189                      $functionname($course, $cm, $glossary, $entry,'','','','');
2190                  }
2191              }
2192          }
2193      }
2194      echo '</td>';
2195      echo '</tr></table></div>';
2196  }
2197  
2198  /**
2199   *
2200   * @global object
2201   * @param array $entries
2202   * @param array $aliases
2203   * @param array $categories
2204   * @return string
2205   */
2206  function glossary_generate_export_csv($entries, $aliases, $categories) {
2207      global $CFG;
2208      $csv = '';
2209      $delimiter = '';
2210      require_once($CFG->libdir . '/csvlib.class.php');
2211      $delimiter = csv_import_reader::get_delimiter('comma');
2212      $csventries = array(0 => array(get_string('concept', 'glossary'), get_string('definition', 'glossary')));
2213      $csvaliases = array(0 => array());
2214      $csvcategories = array(0 => array());
2215      $aliascount = 0;
2216      $categorycount = 0;
2217  
2218      foreach ($entries as $entry) {
2219          $thisaliasesentry = array();
2220          $thiscategoriesentry = array();
2221          $thiscsventry = array($entry->concept, nl2br($entry->definition));
2222  
2223          if (array_key_exists($entry->id, $aliases) && is_array($aliases[$entry->id])) {
2224              $thiscount = count($aliases[$entry->id]);
2225              if ($thiscount > $aliascount) {
2226                  $aliascount = $thiscount;
2227              }
2228              foreach ($aliases[$entry->id] as $alias) {
2229                  $thisaliasesentry[] = trim($alias);
2230              }
2231          }
2232          if (array_key_exists($entry->id, $categories) && is_array($categories[$entry->id])) {
2233              $thiscount = count($categories[$entry->id]);
2234              if ($thiscount > $categorycount) {
2235                  $categorycount = $thiscount;
2236              }
2237              foreach ($categories[$entry->id] as $catentry) {
2238                  $thiscategoriesentry[] = trim($catentry);
2239              }
2240          }
2241          $csventries[$entry->id] = $thiscsventry;
2242          $csvaliases[$entry->id] = $thisaliasesentry;
2243          $csvcategories[$entry->id] = $thiscategoriesentry;
2244  
2245      }
2246      $returnstr = '';
2247      foreach ($csventries as $id => $row) {
2248          $aliasstr = '';
2249          $categorystr = '';
2250          if ($id == 0) {
2251              $aliasstr = get_string('alias', 'glossary');
2252              $categorystr = get_string('category', 'glossary');
2253          }
2254          $row = array_merge($row, array_pad($csvaliases[$id], $aliascount, $aliasstr), array_pad($csvcategories[$id], $categorycount, $categorystr));
2255          $returnstr .= '"' . implode('"' . $delimiter . '"', $row) . '"' . "\n";
2256      }
2257      return $returnstr;
2258  }
2259  
2260  /**
2261   *
2262   * @param object $glossary
2263   * @param string $ignored invalid parameter
2264   * @param int|string $hook
2265   * @return string
2266   */
2267  function glossary_generate_export_file($glossary, $ignored = "", $hook = 0) {
2268      global $CFG, $DB;
2269  
2270      $co  = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
2271  
2272      $co .= glossary_start_tag("GLOSSARY",0,true);
2273      $co .= glossary_start_tag("INFO",1,true);
2274          $co .= glossary_full_tag("NAME",2,false,$glossary->name);
2275          $co .= glossary_full_tag("INTRO",2,false,$glossary->intro);
2276          $co .= glossary_full_tag("INTROFORMAT",2,false,$glossary->introformat);
2277          $co .= glossary_full_tag("ALLOWDUPLICATEDENTRIES",2,false,$glossary->allowduplicatedentries);
2278          $co .= glossary_full_tag("DISPLAYFORMAT",2,false,$glossary->displayformat);
2279          $co .= glossary_full_tag("SHOWSPECIAL",2,false,$glossary->showspecial);
2280          $co .= glossary_full_tag("SHOWALPHABET",2,false,$glossary->showalphabet);
2281          $co .= glossary_full_tag("SHOWALL",2,false,$glossary->showall);
2282          $co .= glossary_full_tag("ALLOWCOMMENTS",2,false,$glossary->allowcomments);
2283          $co .= glossary_full_tag("USEDYNALINK",2,false,$glossary->usedynalink);
2284          $co .= glossary_full_tag("DEFAULTAPPROVAL",2,false,$glossary->defaultapproval);
2285          $co .= glossary_full_tag("GLOBALGLOSSARY",2,false,$glossary->globalglossary);
2286          $co .= glossary_full_tag("ENTBYPAGE",2,false,$glossary->entbypage);
2287  
2288          if ( $entries = $DB->get_records("glossary_entries", array("glossaryid"=>$glossary->id))) {
2289              $co .= glossary_start_tag("ENTRIES",2,true);
2290              foreach ($entries as $entry) {
2291                  $permissiongranted = 1;
2292                  if ( $hook ) {
2293                      switch ( $hook ) {
2294                      case "ALL":
2295                      case "SPECIAL":
2296                      break;
2297                      default:
2298                          $permissiongranted = ($entry->concept[ strlen($hook)-1 ] == $hook);
2299                      break;
2300                      }
2301                  }
2302                  if ( $hook ) {
2303                      switch ( $hook ) {
2304                      case GLOSSARY_SHOW_ALL_CATEGORIES:
2305                      break;
2306                      case GLOSSARY_SHOW_NOT_CATEGORISED:
2307                          $permissiongranted = !$DB->record_exists("glossary_entries_categories", array("entryid"=>$entry->id));
2308                      break;
2309                      default:
2310                          $permissiongranted = $DB->record_exists("glossary_entries_categories", array("entryid"=>$entry->id, "categoryid"=>$hook));
2311                      break;
2312                      }
2313                  }
2314                  if ( $entry->approved and $permissiongranted ) {
2315                      $co .= glossary_start_tag("ENTRY",3,true);
2316                      $co .= glossary_full_tag("CONCEPT",4,false,trim($entry->concept));
2317                      $co .= glossary_full_tag("DEFINITION",4,false,$entry->definition);
2318                      $co .= glossary_full_tag("FORMAT",4,false,$entry->definitionformat); // note: use old name for BC reasons
2319                      $co .= glossary_full_tag("USEDYNALINK",4,false,$entry->usedynalink);
2320                      $co .= glossary_full_tag("CASESENSITIVE",4,false,$entry->casesensitive);
2321                      $co .= glossary_full_tag("FULLMATCH",4,false,$entry->fullmatch);
2322                      $co .= glossary_full_tag("TEACHERENTRY",4,false,$entry->teacherentry);
2323  
2324                      if ( $aliases = $DB->get_records("glossary_alias", array("entryid"=>$entry->id))) {
2325                          $co .= glossary_start_tag("ALIASES",4,true);
2326                          foreach ($aliases as $alias) {
2327                              $co .= glossary_start_tag("ALIAS",5,true);
2328                                  $co .= glossary_full_tag("NAME",6,false,trim($alias->alias));
2329                              $co .= glossary_end_tag("ALIAS",5,true);
2330                          }
2331                          $co .= glossary_end_tag("ALIASES",4,true);
2332                      }
2333                      if ( $catentries = $DB->get_records("glossary_entries_categories", array("entryid"=>$entry->id))) {
2334                          $co .= glossary_start_tag("CATEGORIES",4,true);
2335                          foreach ($catentries as $catentry) {
2336                              $category = $DB->get_record("glossary_categories", array("id"=>$catentry->categoryid));
2337  
2338                              $co .= glossary_start_tag("CATEGORY",5,true);
2339                                  $co .= glossary_full_tag("NAME",6,false,$category->name);
2340                                  $co .= glossary_full_tag("USEDYNALINK",6,false,$category->usedynalink);
2341                              $co .= glossary_end_tag("CATEGORY",5,true);
2342                          }
2343                          $co .= glossary_end_tag("CATEGORIES",4,true);
2344                      }
2345  
2346                      $co .= glossary_end_tag("ENTRY",3,true);
2347                  }
2348              }
2349              $co .= glossary_end_tag("ENTRIES",2,true);
2350  
2351          }
2352  
2353  
2354      $co .= glossary_end_tag("INFO",1,true);
2355      $co .= glossary_end_tag("GLOSSARY",0,true);
2356  
2357      return $co;
2358  }
2359  /// Functions designed by Eloy Lafuente
2360  /// Functions to create, open and write header of the xml file
2361  
2362  /**
2363   * Read import file and convert to current charset
2364   *
2365   * @global object
2366   * @param string $file
2367   * @return string
2368   */
2369  function glossary_read_imported_file($file_content) {
2370      require_once  "../../lib/xmlize.php";
2371      global $CFG;
2372  
2373      return xmlize($file_content, 0);
2374  }
2375  
2376  /**
2377   * Return the xml start tag
2378   *
2379   * @param string $tag
2380   * @param int $level
2381   * @param bool $endline
2382   * @return string
2383   */
2384  function glossary_start_tag($tag,$level=0,$endline=false) {
2385          if ($endline) {
2386             $endchar = "\n";
2387          } else {
2388             $endchar = "";
2389          }
2390          return str_repeat(" ",$level*2)."<".strtoupper($tag).">".$endchar;
2391  }
2392  
2393  /**
2394   * Return the xml end tag
2395   * @param string $tag
2396   * @param int $level
2397   * @param bool $endline
2398   * @return string
2399   */
2400  function glossary_end_tag($tag,$level=0,$endline=true) {
2401          if ($endline) {
2402             $endchar = "\n";
2403          } else {
2404             $endchar = "";
2405          }
2406          return str_repeat(" ",$level*2)."</".strtoupper($tag).">".$endchar;
2407  }
2408  
2409  /**
2410   * Return the start tag, the contents and the end tag
2411   *
2412   * @global object
2413   * @param string $tag
2414   * @param int $level
2415   * @param bool $endline
2416   * @param string $content
2417   * @return string
2418   */
2419  function glossary_full_tag($tag,$level=0,$endline=true,$content) {
2420          global $CFG;
2421  
2422          $st = glossary_start_tag($tag,$level,$endline);
2423          $co = preg_replace("/\r\n|\r/", "\n", s($content));
2424          $et = glossary_end_tag($tag,0,true);
2425          return $st.$co.$et;
2426  }
2427  
2428  /**
2429   * How many unrated entries are in the given glossary for a given user?
2430   *
2431   * @global moodle_database $DB
2432   * @param int $glossaryid
2433   * @param int $userid
2434   * @return int
2435   */
2436  function glossary_count_unrated_entries($glossaryid, $userid) {
2437      global $DB;
2438  
2439      $sql = "SELECT COUNT('x') as num
2440                FROM {glossary_entries}
2441               WHERE glossaryid = :glossaryid AND
2442                     userid <> :userid";
2443      $params = array('glossaryid' => $glossaryid, 'userid' => $userid);
2444      $entries = $DB->count_records_sql($sql, $params);
2445  
2446      if ($entries) {
2447          // We need to get the contextid for the glossaryid we have been given.
2448          $sql = "SELECT ctx.id
2449                    FROM {context} ctx
2450                    JOIN {course_modules} cm ON cm.id = ctx.instanceid
2451                    JOIN {modules} m ON m.id = cm.module
2452                    JOIN {glossary} g ON g.id = cm.instance
2453                   WHERE ctx.contextlevel = :contextlevel AND
2454                         m.name = 'glossary' AND
2455                         g.id = :glossaryid";
2456          $contextid = $DB->get_field_sql($sql, array('glossaryid' => $glossaryid, 'contextlevel' => CONTEXT_MODULE));
2457  
2458          // Now we need to count the ratings that this user has made
2459          $sql = "SELECT COUNT('x') AS num
2460                    FROM {glossary_entries} e
2461                    JOIN {rating} r ON r.itemid = e.id
2462                   WHERE e.glossaryid = :glossaryid AND
2463                         r.userid = :userid AND
2464                         r.component = 'mod_glossary' AND
2465                         r.ratingarea = 'entry' AND
2466                         r.contextid = :contextid";
2467          $params = array('glossaryid' => $glossaryid, 'userid' => $userid, 'contextid' => $contextid);
2468          $rated = $DB->count_records_sql($sql, $params);
2469          if ($rated) {
2470              // The number or enties minus the number or rated entries equals the number of unrated
2471              // entries
2472              if ($entries > $rated) {
2473                  return $entries - $rated;
2474              } else {
2475                  return 0;    // Just in case there was a counting error
2476              }
2477          } else {
2478              return (int)$entries;
2479          }
2480      } else {
2481          return 0;
2482      }
2483  }
2484  
2485  /**
2486   *
2487   * Returns the html code to represent any pagging bar. Paramenters are:
2488   *
2489   * The function dinamically show the first and last pages, and "scroll" over pages.
2490   * Fully compatible with Moodle's print_paging_bar() function. Perhaps some day this
2491   * could replace the general one. ;-)
2492   *
2493   * @param int $totalcount total number of records to be displayed
2494   * @param int $page page currently selected (0 based)
2495   * @param int $perpage number of records per page
2496   * @param string $baseurl url to link in each page, the string 'page=XX' will be added automatically.
2497   *
2498   * @param int $maxpageallowed Optional maximum number of page allowed.
2499   * @param int $maxdisplay Optional maximum number of page links to show in the bar
2500   * @param string $separator Optional string to be used between pages in the bar
2501   * @param string $specialtext Optional string to be showed as an special link
2502   * @param string $specialvalue Optional value (page) to be used in the special link
2503   * @param bool $previousandnext Optional to decide if we want the previous and next links
2504   * @return string
2505   */
2506  function glossary_get_paging_bar($totalcount, $page, $perpage, $baseurl, $maxpageallowed=99999, $maxdisplay=20, $separator="&nbsp;", $specialtext="", $specialvalue=-1, $previousandnext = true) {
2507  
2508      $code = '';
2509  
2510      $showspecial = false;
2511      $specialselected = false;
2512  
2513      //Check if we have to show the special link
2514      if (!empty($specialtext)) {
2515          $showspecial = true;
2516      }
2517      //Check if we are with the special link selected
2518      if ($showspecial && $page == $specialvalue) {
2519          $specialselected = true;
2520      }
2521  
2522      //If there are results (more than 1 page)
2523      if ($totalcount > $perpage) {
2524          $code .= "<div style=\"text-align:center\">";
2525          $code .= "<p>".get_string("page").":";
2526  
2527          $maxpage = (int)(($totalcount-1)/$perpage);
2528  
2529          //Lower and upper limit of page
2530          if ($page < 0) {
2531              $page = 0;
2532          }
2533          if ($page > $maxpageallowed) {
2534              $page = $maxpageallowed;
2535          }
2536          if ($page > $maxpage) {
2537              $page = $maxpage;
2538          }
2539  
2540          //Calculate the window of pages
2541          $pagefrom = $page - ((int)($maxdisplay / 2));
2542          if ($pagefrom < 0) {
2543              $pagefrom = 0;
2544          }
2545          $pageto = $pagefrom + $maxdisplay - 1;
2546          if ($pageto > $maxpageallowed) {
2547              $pageto = $maxpageallowed;
2548          }
2549          if ($pageto > $maxpage) {
2550              $pageto = $maxpage;
2551          }
2552  
2553          //Some movements can be necessary if don't see enought pages
2554          if ($pageto - $pagefrom < $maxdisplay - 1) {
2555              if ($pageto - $maxdisplay + 1 > 0) {
2556                  $pagefrom = $pageto - $maxdisplay + 1;
2557              }
2558          }
2559  
2560          //Calculate first and last if necessary
2561          $firstpagecode = '';
2562          $lastpagecode = '';
2563          if ($pagefrom > 0) {
2564              $firstpagecode = "$separator<a href=\"{$baseurl}page=0\">1</a>";
2565              if ($pagefrom > 1) {
2566                  $firstpagecode .= "$separator...";
2567              }
2568          }
2569          if ($pageto < $maxpage) {
2570              if ($pageto < $maxpage -1) {
2571                  $lastpagecode = "$separator...";
2572              }
2573              $lastpagecode .= "$separator<a href=\"{$baseurl}page=$maxpage\">".($maxpage+1)."</a>";
2574          }
2575  
2576          //Previous
2577          if ($page > 0 && $previousandnext) {
2578              $pagenum = $page - 1;
2579              $code .= "&nbsp;(<a  href=\"{$baseurl}page=$pagenum\">".get_string("previous")."</a>)&nbsp;";
2580          }
2581  
2582          //Add first
2583          $code .= $firstpagecode;
2584  
2585          $pagenum = $pagefrom;
2586  
2587          //List of maxdisplay pages
2588          while ($pagenum <= $pageto) {
2589              $pagetoshow = $pagenum +1;
2590              if ($pagenum == $page && !$specialselected) {
2591                  $code .= "$separator<b>$pagetoshow</b>";
2592              } else {
2593                  $code .= "$separator<a href=\"{$baseurl}page=$pagenum\">$pagetoshow</a>";
2594              }
2595              $pagenum++;
2596          }
2597  
2598          //Add last
2599          $code .= $lastpagecode;
2600  
2601          //Next
2602          if ($page < $maxpage && $page < $maxpageallowed && $previousandnext) {
2603              $pagenum = $page + 1;
2604              $code .= "$separator(<a href=\"{$baseurl}page=$pagenum\">".get_string("next")."</a>)";
2605          }
2606  
2607          //Add special
2608          if ($showspecial) {
2609              $code .= '<br />';
2610              if ($specialselected) {
2611                  $code .= "<b>$specialtext</b>";
2612              } else {
2613                  $code .= "$separator<a href=\"{$baseurl}page=$specialvalue\">$specialtext</a>";
2614              }
2615          }
2616  
2617          //End html
2618          $code .= "</p>";
2619          $code .= "</div>";
2620      }
2621  
2622      return $code;
2623  }
2624  
2625  /**
2626   * List the actions that correspond to a view of this module.
2627   * This is used by the participation report.
2628   *
2629   * Note: This is not used by new logging system. Event with
2630   *       crud = 'r' and edulevel = LEVEL_PARTICIPATING will
2631   *       be considered as view action.
2632   *
2633   * @return array
2634   */
2635  function glossary_get_view_actions() {
2636      return array('view','view all','view entry');
2637  }
2638  
2639  /**
2640   * List the actions that correspond to a post of this module.
2641   * This is used by the participation report.
2642   *
2643   * Note: This is not used by new logging system. Event with
2644   *       crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
2645   *       will be considered as post action.
2646   *
2647   * @return array
2648   */
2649  function glossary_get_post_actions() {
2650      return array('add category','add entry','approve entry','delete category','delete entry','edit category','update entry');
2651  }
2652  
2653  
2654  /**
2655   * Implementation of the function for printing the form elements that control
2656   * whether the course reset functionality affects the glossary.
2657   * @param object $mform form passed by reference
2658   */
2659  function glossary_reset_course_form_definition(&$mform) {
2660      $mform->addElement('header', 'glossaryheader', get_string('modulenameplural', 'glossary'));
2661      $mform->addElement('checkbox', 'reset_glossary_all', get_string('resetglossariesall','glossary'));
2662  
2663      $mform->addElement('select', 'reset_glossary_types', get_string('resetglossaries', 'glossary'),
2664                         array('main'=>get_string('mainglossary', 'glossary'), 'secondary'=>get_string('secondaryglossary', 'glossary')), array('multiple' => 'multiple'));
2665      $mform->setAdvanced('reset_glossary_types');
2666      $mform->disabledIf('reset_glossary_types', 'reset_glossary_all', 'checked');
2667  
2668      $mform->addElement('checkbox', 'reset_glossary_notenrolled', get_string('deletenotenrolled', 'glossary'));
2669      $mform->disabledIf('reset_glossary_notenrolled', 'reset_glossary_all', 'checked');
2670  
2671      $mform->addElement('checkbox', 'reset_glossary_ratings', get_string('deleteallratings'));
2672      $mform->disabledIf('reset_glossary_ratings', 'reset_glossary_all', 'checked');
2673  
2674      $mform->addElement('checkbox', 'reset_glossary_comments', get_string('deleteallcomments'));
2675      $mform->disabledIf('reset_glossary_comments', 'reset_glossary_all', 'checked');
2676  }
2677  
2678  /**
2679   * Course reset form defaults.
2680   * @return array
2681   */
2682  function glossary_reset_course_form_defaults($course) {
2683      return array('reset_glossary_all'=>0, 'reset_glossary_ratings'=>1, 'reset_glossary_comments'=>1, 'reset_glossary_notenrolled'=>0);
2684  }
2685  
2686  /**
2687   * Removes all grades from gradebook
2688   *
2689   * @param int $courseid The ID of the course to reset
2690   * @param string $type The optional type of glossary. 'main', 'secondary' or ''
2691   */
2692  function glossary_reset_gradebook($courseid, $type='') {
2693      global $DB;
2694  
2695      switch ($type) {
2696          case 'main'      : $type = "AND g.mainglossary=1"; break;
2697          case 'secondary' : $type = "AND g.mainglossary=0"; break;
2698          default          : $type = ""; //all
2699      }
2700  
2701      $sql = "SELECT g.*, cm.idnumber as cmidnumber, g.course as courseid
2702                FROM {glossary} g, {course_modules} cm, {modules} m
2703               WHERE m.name='glossary' AND m.id=cm.module AND cm.instance=g.id AND g.course=? $type";
2704  
2705      if ($glossarys = $DB->get_records_sql($sql, array($courseid))) {
2706          foreach ($glossarys as $glossary) {
2707              glossary_grade_item_update($glossary, 'reset');
2708          }
2709      }
2710  }
2711  /**
2712   * Actual implementation of the reset course functionality, delete all the
2713   * glossary responses for course $data->courseid.
2714   *
2715   * @global object
2716   * @param $data the data submitted from the reset course.
2717   * @return array status array
2718   */
2719  function glossary_reset_userdata($data) {
2720      global $CFG, $DB;
2721      require_once($CFG->dirroot.'/rating/lib.php');
2722  
2723      $componentstr = get_string('modulenameplural', 'glossary');
2724      $status = array();
2725  
2726      $allentriessql = "SELECT e.id
2727                          FROM {glossary_entries} e
2728                               JOIN {glossary} g ON e.glossaryid = g.id
2729                         WHERE g.course = ?";
2730  
2731      $allglossariessql = "SELECT g.id
2732                             FROM {glossary} g
2733                            WHERE g.course = ?";
2734  
2735      $params = array($data->courseid);
2736  
2737      $fs = get_file_storage();
2738  
2739      $rm = new rating_manager();
2740      $ratingdeloptions = new stdClass;
2741      $ratingdeloptions->component = 'mod_glossary';
2742      $ratingdeloptions->ratingarea = 'entry';
2743  
2744      // delete entries if requested
2745      if (!empty($data->reset_glossary_all)
2746           or (!empty($data->reset_glossary_types) and in_array('main', $data->reset_glossary_types) and in_array('secondary', $data->reset_glossary_types))) {
2747  
2748          $params[] = 'glossary_entry';
2749          $DB->delete_records_select('comments', "itemid IN ($allentriessql) AND commentarea=?", $params);
2750          $DB->delete_records_select('glossary_alias',    "entryid IN ($allentriessql)", $params);
2751          $DB->delete_records_select('glossary_entries', "glossaryid IN ($allglossariessql)", $params);
2752  
2753          // now get rid of all attachments
2754          if ($glossaries = $DB->get_records_sql($allglossariessql, $params)) {
2755              foreach ($glossaries as $glossaryid=>$unused) {
2756                  if (!$cm = get_coursemodule_from_instance('glossary', $glossaryid)) {
2757                      continue;
2758                  }
2759                  $context = context_module::instance($cm->id);
2760                  $fs->delete_area_files($context->id, 'mod_glossary', 'attachment');
2761  
2762                  //delete ratings
2763                  $ratingdeloptions->contextid = $context->id;
2764                  $rm->delete_ratings($ratingdeloptions);
2765              }
2766          }
2767  
2768          // remove all grades from gradebook
2769          if (empty($data->reset_gradebook_grades)) {
2770              glossary_reset_gradebook($data->courseid);
2771          }
2772  
2773          $status[] = array('component'=>$componentstr, 'item'=>get_string('resetglossariesall', 'glossary'), 'error'=>false);
2774  
2775      } else if (!empty($data->reset_glossary_types)) {
2776          $mainentriessql         = "$allentriessql AND g.mainglossary=1";
2777          $secondaryentriessql    = "$allentriessql AND g.mainglossary=0";
2778  
2779          $mainglossariessql      = "$allglossariessql AND g.mainglossary=1";
2780          $secondaryglossariessql = "$allglossariessql AND g.mainglossary=0";
2781  
2782          if (in_array('main', $data->reset_glossary_types)) {
2783              $params[] = 'glossary_entry';
2784              $DB->delete_records_select('comments', "itemid IN ($mainentriessql) AND commentarea=?", $params);
2785              $DB->delete_records_select('glossary_entries', "glossaryid IN ($mainglossariessql)", $params);
2786  
2787              if ($glossaries = $DB->get_records_sql($mainglossariessql, $params)) {
2788                  foreach ($glossaries as $glossaryid=>$unused) {
2789                      if (!$cm = get_coursemodule_from_instance('glossary', $glossaryid)) {
2790                          continue;
2791                      }
2792                      $context = context_module::instance($cm->id);
2793                      $fs->delete_area_files($context->id, 'mod_glossary', 'attachment');
2794  
2795                      //delete ratings
2796                      $ratingdeloptions->contextid = $context->id;
2797                      $rm->delete_ratings($ratingdeloptions);
2798                  }
2799              }
2800  
2801              // remove all grades from gradebook
2802              if (empty($data->reset_gradebook_grades)) {
2803                  glossary_reset_gradebook($data->courseid, 'main');
2804              }
2805  
2806              $status[] = array('component'=>$componentstr, 'item'=>get_string('resetglossaries', 'glossary').': '.get_string('mainglossary', 'glossary'), 'error'=>false);
2807  
2808          } else if (in_array('secondary', $data->reset_glossary_types)) {
2809              $params[] = 'glossary_entry';
2810              $DB->delete_records_select('comments', "itemid IN ($secondaryentriessql) AND commentarea=?", $params);
2811              $DB->delete_records_select('glossary_entries', "glossaryid IN ($secondaryglossariessql)", $params);
2812              // remove exported source flag from entries in main glossary
2813              $DB->execute("UPDATE {glossary_entries}
2814                               SET sourceglossaryid=0
2815                             WHERE glossaryid IN ($mainglossariessql)", $params);
2816  
2817              if ($glossaries = $DB->get_records_sql($secondaryglossariessql, $params)) {
2818                  foreach ($glossaries as $glossaryid=>$unused) {
2819                      if (!$cm = get_coursemodule_from_instance('glossary', $glossaryid)) {
2820                          continue;
2821                      }
2822                      $context = context_module::instance($cm->id);
2823                      $fs->delete_area_files($context->id, 'mod_glossary', 'attachment');
2824  
2825                      //delete ratings
2826                      $ratingdeloptions->contextid = $context->id;
2827                      $rm->delete_ratings($ratingdeloptions);
2828                  }
2829              }
2830  
2831              // remove all grades from gradebook
2832              if (empty($data->reset_gradebook_grades)) {
2833                  glossary_reset_gradebook($data->courseid, 'secondary');
2834              }
2835  
2836              $status[] = array('component'=>$componentstr, 'item'=>get_string('resetglossaries', 'glossary').': '.get_string('secondaryglossary', 'glossary'), 'error'=>false);
2837          }
2838      }
2839  
2840      // remove entries by users not enrolled into course
2841      if (!empty($data->reset_glossary_notenrolled)) {
2842          $entriessql = "SELECT e.id, e.userid, e.glossaryid, u.id AS userexists, u.deleted AS userdeleted
2843                           FROM {glossary_entries} e
2844                                JOIN {glossary} g ON e.glossaryid = g.id
2845                                LEFT JOIN {user} u ON e.userid = u.id
2846                          WHERE g.course = ? AND e.userid > 0";
2847  
2848          $course_context = context_course::instance($data->courseid);
2849          $notenrolled = array();
2850          $rs = $DB->get_recordset_sql($entriessql, $params);
2851          if ($rs->valid()) {
2852              foreach ($rs as $entry) {
2853                  if (array_key_exists($entry->userid, $notenrolled) or !$entry->userexists or $entry->userdeleted
2854                    or !is_enrolled($course_context , $entry->userid)) {
2855                      $DB->delete_records('comments', array('commentarea'=>'glossary_entry', 'itemid'=>$entry->id));
2856                      $DB->delete_records('glossary_entries', array('id'=>$entry->id));
2857  
2858                      if ($cm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
2859                          $context = context_module::instance($cm->id);
2860                          $fs->delete_area_files($context->id, 'mod_glossary', 'attachment', $entry->id);
2861  
2862                          //delete ratings
2863                          $ratingdeloptions->contextid = $context->id;
2864                          $rm->delete_ratings($ratingdeloptions);
2865                      }
2866                  }
2867              }
2868              $status[] = array('component'=>$componentstr, 'item'=>get_string('deletenotenrolled', 'glossary'), 'error'=>false);
2869          }
2870          $rs->close();
2871      }
2872  
2873      // remove all ratings
2874      if (!empty($data->reset_glossary_ratings)) {
2875          //remove ratings
2876          if ($glossaries = $DB->get_records_sql($allglossariessql, $params)) {
2877              foreach ($glossaries as $glossaryid=>$unused) {
2878                  if (!$cm = get_coursemodule_from_instance('glossary', $glossaryid)) {
2879                      continue;
2880                  }
2881                  $context = context_module::instance($cm->id);
2882  
2883                  //delete ratings
2884                  $ratingdeloptions->contextid = $context->id;
2885                  $rm->delete_ratings($ratingdeloptions);
2886              }
2887          }
2888  
2889          // remove all grades from gradebook
2890          if (empty($data->reset_gradebook_grades)) {
2891              glossary_reset_gradebook($data->courseid);
2892          }
2893          $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallratings'), 'error'=>false);
2894      }
2895  
2896      // remove comments
2897      if (!empty($data->reset_glossary_comments)) {
2898          $params[] = 'glossary_entry';
2899          $DB->delete_records_select('comments', "itemid IN ($allentriessql) AND commentarea= ? ", $params);
2900          $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallcomments'), 'error'=>false);
2901      }
2902  
2903      /// updating dates - shift may be negative too
2904      if ($data->timeshift) {
2905          shift_course_mod_dates('glossary', array('assesstimestart', 'assesstimefinish'), $data->timeshift, $data->courseid);
2906          $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged'), 'error'=>false);
2907      }
2908  
2909      return $status;
2910  }
2911  
2912  /**
2913   * Returns all other caps used in module
2914   * @return array
2915   */
2916  function glossary_get_extra_capabilities() {
2917      return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames', 'moodle/site:trustcontent', 'moodle/rating:view', 'moodle/rating:viewany', 'moodle/rating:viewall', 'moodle/rating:rate', 'moodle/comment:view', 'moodle/comment:post', 'moodle/comment:delete');
2918  }
2919  
2920  /**
2921   * @param string $feature FEATURE_xx constant for requested feature
2922   * @return mixed True if module supports feature, null if doesn't know
2923   */
2924  function glossary_supports($feature) {
2925      switch($feature) {
2926          case FEATURE_GROUPS:                  return false;
2927          case FEATURE_GROUPINGS:               return false;
2928          case FEATURE_MOD_INTRO:               return true;
2929          case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
2930          case FEATURE_COMPLETION_HAS_RULES:    return true;
2931          case FEATURE_GRADE_HAS_GRADE:         return true;
2932          case FEATURE_GRADE_OUTCOMES:          return true;
2933          case FEATURE_RATE:                    return true;
2934          case FEATURE_BACKUP_MOODLE2:          return true;
2935          case FEATURE_SHOW_DESCRIPTION:        return true;
2936  
2937          default: return null;
2938      }
2939  }
2940  
2941  /**
2942   * Obtains the automatic completion state for this glossary based on any conditions
2943   * in glossary settings.
2944   *
2945   * @global object
2946   * @global object
2947   * @param object $course Course
2948   * @param object $cm Course-module
2949   * @param int $userid User ID
2950   * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
2951   * @return bool True if completed, false if not. (If no conditions, then return
2952   *   value depends on comparison type)
2953   */
2954  function glossary_get_completion_state($course,$cm,$userid,$type) {
2955      global $CFG, $DB;
2956  
2957      // Get glossary details
2958      if (!($glossary=$DB->get_record('glossary',array('id'=>$cm->instance)))) {
2959          throw new Exception("Can't find glossary {$cm->instance}");
2960      }
2961  
2962      $result=$type; // Default return value
2963  
2964      if ($glossary->completionentries) {
2965          $value = $glossary->completionentries <=
2966                   $DB->count_records('glossary_entries',array('glossaryid'=>$glossary->id, 'userid'=>$userid, 'approved'=>1));
2967          if ($type == COMPLETION_AND) {
2968              $result = $result && $value;
2969          } else {
2970              $result = $result || $value;
2971          }
2972      }
2973  
2974      return $result;
2975  }
2976  
2977  function glossary_extend_navigation($navigation, $course, $module, $cm) {
2978      global $CFG;
2979      $navigation->add(get_string('standardview', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$cm->id, 'mode'=>'letter')));
2980      $navigation->add(get_string('categoryview', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$cm->id, 'mode'=>'cat')));
2981      $navigation->add(get_string('dateview', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$cm->id, 'mode'=>'date')));
2982      $navigation->add(get_string('authorview', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$cm->id, 'mode'=>'author')));
2983  }
2984  
2985  /**
2986   * Adds module specific settings to the settings block
2987   *
2988   * @param settings_navigation $settings The settings navigation object
2989   * @param navigation_node $glossarynode The node to add module settings to
2990   */
2991  function glossary_extend_settings_navigation(settings_navigation $settings, navigation_node $glossarynode) {
2992      global $PAGE, $DB, $CFG, $USER;
2993  
2994      $mode = optional_param('mode', '', PARAM_ALPHA);
2995      $hook = optional_param('hook', 'ALL', PARAM_CLEAN);
2996  
2997      if (has_capability('mod/glossary:import', $PAGE->cm->context)) {
2998          $glossarynode->add(get_string('importentries', 'glossary'), new moodle_url('/mod/glossary/import.php', array('id'=>$PAGE->cm->id)));
2999      }
3000  
3001      if (has_capability('mod/glossary:export', $PAGE->cm->context)) {
3002          $glossarynode->add(get_string('exportentries', 'glossary'), new moodle_url('/mod/glossary/export.php', array('id'=>$PAGE->cm->id, 'mode'=>$mode, 'hook'=>$hook)));
3003      }
3004  
3005      if (has_capability('mod/glossary:approve', $PAGE->cm->context) && ($hiddenentries = $DB->count_records('glossary_entries', array('glossaryid'=>$PAGE->cm->instance, 'approved'=>0)))) {
3006          $glossarynode->add(get_string('waitingapproval', 'glossary'), new moodle_url('/mod/glossary/view.php', array('id'=>$PAGE->cm->id, 'mode'=>'approval')));
3007      }
3008  
3009      if (has_capability('mod/glossary:write', $PAGE->cm->context)) {
3010          $glossarynode->add(get_string('addentry', 'glossary'), new moodle_url('/mod/glossary/edit.php', array('cmid'=>$PAGE->cm->id)));
3011      }
3012  
3013      $glossary = $DB->get_record('glossary', array("id" => $PAGE->cm->instance));
3014  
3015      if (!empty($CFG->enablerssfeeds) && !empty($CFG->glossary_enablerssfeeds) && $glossary->rsstype && $glossary->rssarticles && has_capability('mod/glossary:view', $PAGE->cm->context)) {
3016          require_once("$CFG->libdir/rsslib.php");
3017  
3018          $string = get_string('rsstype','forum');
3019  
3020          $url = new moodle_url(rss_get_url($PAGE->cm->context->id, $USER->id, 'mod_glossary', $glossary->id));
3021          $glossarynode->add($string, $url, settings_navigation::TYPE_SETTING, null, null, new pix_icon('i/rss', ''));
3022      }
3023  }
3024  
3025  /**
3026   * Running addtional permission check on plugin, for example, plugins
3027   * may have switch to turn on/off comments option, this callback will
3028   * affect UI display, not like pluginname_comment_validate only throw
3029   * exceptions.
3030   * Capability check has been done in comment->check_permissions(), we
3031   * don't need to do it again here.
3032   *
3033   * @package  mod_glossary
3034   * @category comment
3035   *
3036   * @param stdClass $comment_param {
3037   *              context  => context the context object
3038   *              courseid => int course id
3039   *              cm       => stdClass course module object
3040   *              commentarea => string comment area
3041   *              itemid      => int itemid
3042   * }
3043   * @return array
3044   */
3045  function glossary_comment_permissions($comment_param) {
3046      return array('post'=>true, 'view'=>true);
3047  }
3048  
3049  /**
3050   * Validate comment parameter before perform other comments actions
3051   *
3052   * @package  mod_glossary
3053   * @category comment
3054   *
3055   * @param stdClass $comment_param {
3056   *              context  => context the context object
3057   *              courseid => int course id
3058   *              cm       => stdClass course module object
3059   *              commentarea => string comment area
3060   *              itemid      => int itemid
3061   * }
3062   * @return boolean
3063   */
3064  function glossary_comment_validate($comment_param) {
3065      global $DB;
3066      // validate comment area
3067      if ($comment_param->commentarea != 'glossary_entry') {
3068          throw new comment_exception('invalidcommentarea');
3069      }
3070      if (!$record = $DB->get_record('glossary_entries', array('id'=>$comment_param->itemid))) {
3071          throw new comment_exception('invalidcommentitemid');
3072      }
3073      if ($record->sourceglossaryid && $record->sourceglossaryid == $comment_param->cm->instance) {
3074          $glossary = $DB->get_record('glossary', array('id'=>$record->sourceglossaryid));
3075      } else {
3076          $glossary = $DB->get_record('glossary', array('id'=>$record->glossaryid));
3077      }
3078      if (!$glossary) {
3079          throw new comment_exception('invalidid', 'data');
3080      }
3081      if (!$course = $DB->get_record('course', array('id'=>$glossary->course))) {
3082          throw new comment_exception('coursemisconf');
3083      }
3084      if (!$cm = get_coursemodule_from_instance('glossary', $glossary->id, $course->id)) {
3085          throw new comment_exception('invalidcoursemodule');
3086      }
3087      $context = context_module::instance($cm->id);
3088  
3089      if ($glossary->defaultapproval and !$record->approved and !has_capability('mod/glossary:approve', $context)) {
3090          throw new comment_exception('notapproved', 'glossary');
3091      }
3092      // validate context id
3093      if ($context->id != $comment_param->context->id) {
3094          throw new comment_exception('invalidcontext');
3095      }
3096      // validation for comment deletion
3097      if (!empty($comment_param->commentid)) {
3098          if ($comment = $DB->get_record('comments', array('id'=>$comment_param->commentid))) {
3099              if ($comment->commentarea != 'glossary_entry') {
3100                  throw new comment_exception('invalidcommentarea');
3101              }
3102              if ($comment->contextid != $comment_param->context->id) {
3103                  throw new comment_exception('invalidcontext');
3104              }
3105              if ($comment->itemid != $comment_param->itemid) {
3106                  throw new comment_exception('invalidcommentitemid');
3107              }
3108          } else {
3109              throw new comment_exception('invalidcommentid');
3110          }
3111      }
3112      return true;
3113  }
3114  
3115  /**
3116   * Return a list of page types
3117   * @param string $pagetype current page type
3118   * @param stdClass $parentcontext Block's parent context
3119   * @param stdClass $currentcontext Current context of block
3120   */
3121  function glossary_page_type_list($pagetype, $parentcontext, $currentcontext) {
3122      $module_pagetype = array(
3123          'mod-glossary-*'=>get_string('page-mod-glossary-x', 'glossary'),
3124          'mod-glossary-view'=>get_string('page-mod-glossary-view', 'glossary'),
3125          'mod-glossary-edit'=>get_string('page-mod-glossary-edit', 'glossary'));
3126      return $module_pagetype;
3127  }

Search This Site: