Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * External glossary functions unit tests
  19   *
  20   * @package    mod_glossary
  21   * @category   external
  22   * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  global $CFG;
  28  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  29  
  30  /**
  31   * External glossary functions unit tests
  32   *
  33   * @package    mod_glossary
  34   * @category   external
  35   * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class mod_glossary_external_testcase extends externallib_advanced_testcase {
  39  
  40      /**
  41       * Test get_glossaries_by_courses
  42       */
  43      public function test_get_glossaries_by_courses() {
  44          $this->resetAfterTest(true);
  45  
  46          // As admin.
  47          $this->setAdminUser();
  48          $c1 = self::getDataGenerator()->create_course();
  49          $c2 = self::getDataGenerator()->create_course();
  50          $g1 = self::getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'name' => 'First Glossary'));
  51          $g2 = self::getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'name' => 'Second Glossary'));
  52          $g3 = self::getDataGenerator()->create_module('glossary', array('course' => $c2->id, 'name' => 'Third Glossary'));
  53  
  54          $s1 = $this->getDataGenerator()->create_user();
  55          self::getDataGenerator()->enrol_user($s1->id,  $c1->id);
  56  
  57          // Check results where student is enrolled.
  58          $this->setUser($s1);
  59          $glossaries = mod_glossary_external::get_glossaries_by_courses(array());
  60          $glossaries = external_api::clean_returnvalue(mod_glossary_external::get_glossaries_by_courses_returns(), $glossaries);
  61  
  62          $this->assertCount(2, $glossaries['glossaries']);
  63          $this->assertEquals('First Glossary', $glossaries['glossaries'][0]['name']);
  64          $this->assertEquals('Second Glossary', $glossaries['glossaries'][1]['name']);
  65          $this->assertEquals(1, $glossaries['glossaries'][0]['canaddentry']);
  66          $this->assertEquals(1, $glossaries['glossaries'][1]['canaddentry']);
  67  
  68          // Check results with specific course IDs.
  69          $glossaries = mod_glossary_external::get_glossaries_by_courses(array($c1->id, $c2->id));
  70          $glossaries = external_api::clean_returnvalue(mod_glossary_external::get_glossaries_by_courses_returns(), $glossaries);
  71  
  72          $this->assertCount(2, $glossaries['glossaries']);
  73          $this->assertEquals('First Glossary', $glossaries['glossaries'][0]['name']);
  74          $this->assertEquals('Second Glossary', $glossaries['glossaries'][1]['name']);
  75  
  76          $this->assertEquals('course', $glossaries['warnings'][0]['item']);
  77          $this->assertEquals($c2->id, $glossaries['warnings'][0]['itemid']);
  78          $this->assertEquals('1', $glossaries['warnings'][0]['warningcode']);
  79          $this->assertEquals(1, $glossaries['glossaries'][0]['canaddentry']);
  80  
  81          // Now as admin.
  82          $this->setAdminUser();
  83  
  84          $glossaries = mod_glossary_external::get_glossaries_by_courses(array($c2->id));
  85          $glossaries = external_api::clean_returnvalue(mod_glossary_external::get_glossaries_by_courses_returns(), $glossaries);
  86  
  87          $this->assertCount(1, $glossaries['glossaries']);
  88          $this->assertEquals('Third Glossary', $glossaries['glossaries'][0]['name']);
  89          $this->assertEquals(1, $glossaries['glossaries'][0]['canaddentry']);
  90      }
  91  
  92      public function test_view_glossary() {
  93          $this->resetAfterTest(true);
  94  
  95          // Generate all the things.
  96          $c1 = $this->getDataGenerator()->create_course();
  97          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
  98          $u1 = $this->getDataGenerator()->create_user();
  99          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 100  
 101          $sink = $this->redirectEvents();
 102          $this->setUser($u1);
 103          $return = mod_glossary_external::view_glossary($g1->id, 'letter');
 104          $return = external_api::clean_returnvalue(mod_glossary_external::view_glossary_returns(), $return);
 105          $events = $sink->get_events();
 106  
 107          // Assertion.
 108          $this->assertTrue($return['status']);
 109          $this->assertEmpty($return['warnings']);
 110          $this->assertCount(1, $events);
 111          $this->assertEquals('\mod_glossary\event\course_module_viewed', $events[0]->eventname);
 112          $sink->close();
 113      }
 114  
 115      public function test_view_glossary_without_permission() {
 116          $this->resetAfterTest(true);
 117  
 118          // Generate all the things.
 119          $c1 = $this->getDataGenerator()->create_course();
 120          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 121          $u1 = $this->getDataGenerator()->create_user();
 122          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 123          $ctx = context_module::instance($g1->cmid);
 124  
 125          // Revoke permission.
 126          $roles = get_archetype_roles('user');
 127          $role = array_shift($roles);
 128          assign_capability('mod/glossary:view', CAP_PROHIBIT, $role->id, $ctx, true);
 129          accesslib_clear_all_caches_for_unit_testing();
 130  
 131          // Assertion.
 132          $this->setUser($u1);
 133          $this->expectException(require_login_exception::class);
 134          $this->expectExceptionMessage('Activity is hidden');
 135          mod_glossary_external::view_glossary($g1->id, 'letter');
 136      }
 137  
 138      public function test_view_entry() {
 139          $this->resetAfterTest(true);
 140  
 141          // Generate all the things.
 142          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 143          $c1 = $this->getDataGenerator()->create_course();
 144          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 145          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'visible' => false));
 146          $u1 = $this->getDataGenerator()->create_user();
 147          $e1 = $gg->create_content($g1, array('approved' => 1));
 148          $e2 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u1->id));
 149          $e3 = $gg->create_content($g1, array('approved' => 0, 'userid' => -1));
 150          $e4 = $gg->create_content($g2, array('approved' => 1));
 151          $ctx = context_module::instance($g1->cmid);
 152          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 153          $this->setUser($u1);
 154  
 155          // Test readable entry.
 156          $sink = $this->redirectEvents();
 157          $return = mod_glossary_external::view_entry($e1->id);
 158          $return = external_api::clean_returnvalue(mod_glossary_external::view_entry_returns(), $return);
 159          $events = $sink->get_events();
 160          $this->assertTrue($return['status']);
 161          $this->assertEmpty($return['warnings']);
 162          $this->assertCount(1, $events);
 163          $this->assertEquals('\mod_glossary\event\entry_viewed', $events[0]->eventname);
 164          $sink->close();
 165  
 166          // Test non-approved of self.
 167          $return = mod_glossary_external::view_entry($e2->id);
 168          $return = external_api::clean_returnvalue(mod_glossary_external::view_entry_returns(), $return);
 169          $events = $sink->get_events();
 170          $this->assertTrue($return['status']);
 171          $this->assertEmpty($return['warnings']);
 172          $this->assertCount(1, $events);
 173          $this->assertEquals('\mod_glossary\event\entry_viewed', $events[0]->eventname);
 174          $sink->close();
 175  
 176          // Test non-approved of other.
 177          try {
 178              mod_glossary_external::view_entry($e3->id);
 179              $this->fail('Cannot view non-approved entries of others.');
 180          } catch (invalid_parameter_exception $e) {
 181              // All good.
 182          }
 183  
 184          // Test non-readable entry.
 185          $this->expectException(require_login_exception::class);
 186          $this->expectExceptionMessage('Activity is hidden');
 187          mod_glossary_external::view_entry($e4->id);
 188      }
 189  
 190      public function test_get_entries_by_letter() {
 191          $this->resetAfterTest(true);
 192  
 193          // Generate all the things.
 194          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 195          $c1 = $this->getDataGenerator()->create_course();
 196          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 197          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 198          $u1 = $this->getDataGenerator()->create_user();
 199          $ctx = context_module::instance($g1->cmid);
 200          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 201  
 202          $e1a = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Bob', 'userid' => 2, 'tags' => array('Cats', 'Dogs')));
 203          $e1b = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Jane', 'userid' => 2));
 204          $e1c = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Alice', 'userid' => $u1->id));
 205          $e1d = $gg->create_content($g1, array('approved' => 0, 'concept' => '0-day', 'userid' => $u1->id));
 206          $e2a = $gg->create_content($g2);
 207  
 208          $this->setAdminUser();
 209  
 210          // Just a normal request from admin user.
 211          $return = mod_glossary_external::get_entries_by_letter($g1->id, 'ALL', 0, 20, array());
 212          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_letter_returns(), $return);
 213          $this->assertCount(3, $return['entries']);
 214          $this->assertEquals(3, $return['count']);
 215          $this->assertEquals($e1c->id, $return['entries'][0]['id']);
 216          $this->assertEquals($e1a->id, $return['entries'][1]['id']);
 217          $this->assertEquals('Cats', $return['entries'][1]['tags'][0]['rawname']);
 218          $this->assertEquals('Dogs', $return['entries'][1]['tags'][1]['rawname']);
 219          $this->assertEquals($e1b->id, $return['entries'][2]['id']);
 220  
 221          // An admin user requesting all the entries.
 222          $return = mod_glossary_external::get_entries_by_letter($g1->id, 'ALL', 0, 20, array('includenotapproved' => 1));
 223          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_letter_returns(), $return);
 224          $this->assertCount(4, $return['entries']);
 225          $this->assertEquals(4, $return['count']);
 226          $this->assertEquals($e1d->id, $return['entries'][0]['id']);
 227          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 228          $this->assertEquals($e1a->id, $return['entries'][2]['id']);
 229          $this->assertEquals($e1b->id, $return['entries'][3]['id']);
 230  
 231          // A normal user.
 232          $this->setUser($u1);
 233          $return = mod_glossary_external::get_entries_by_letter($g1->id, 'ALL', 0, 20, array());
 234          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_letter_returns(), $return);
 235          $this->assertCount(3, $return['entries']);
 236          $this->assertEquals(3, $return['count']);
 237          $this->assertEquals($e1d->id, $return['entries'][0]['id']);
 238          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 239          $this->assertEquals($e1b->id, $return['entries'][2]['id']);
 240  
 241          // A normal user requesting to view all non approved entries.
 242          $return = mod_glossary_external::get_entries_by_letter($g1->id, 'ALL', 0, 20, array('includenotapproved' => 1));
 243          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_letter_returns(), $return);
 244          $this->assertCount(3, $return['entries']);
 245          $this->assertEquals(3, $return['count']);
 246          $this->assertEquals($e1d->id, $return['entries'][0]['id']);
 247          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 248          $this->assertEquals($e1b->id, $return['entries'][2]['id']);
 249      }
 250  
 251      public function test_get_entries_by_letter_with_parameters() {
 252          $this->resetAfterTest(true);
 253  
 254          // Generate all the things.
 255          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 256          $c1 = $this->getDataGenerator()->create_course();
 257          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 258          $u1 = $this->getDataGenerator()->create_user();
 259          $ctx = context_module::instance($g1->cmid);
 260          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 261  
 262          $e1a = $gg->create_content($g1, array('approved' => 1, 'concept' => '0-day', 'userid' => $u1->id));
 263          $e1b = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Bob', 'userid' => 2));
 264          $e1c = $gg->create_content($g1, array('approved' => 1, 'concept' => '1-dayb', 'userid' => $u1->id));
 265  
 266          $this->setUser($u1);
 267  
 268          // Requesting a single letter.
 269          $return = mod_glossary_external::get_entries_by_letter($g1->id, 'b', 0, 20, array());
 270          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_letter_returns(), $return);
 271          $this->assertCount(1, $return['entries']);
 272          $this->assertEquals(1, $return['count']);
 273          $this->assertEquals($e1b->id, $return['entries'][0]['id']);
 274  
 275          // Requesting special letters.
 276          $return = mod_glossary_external::get_entries_by_letter($g1->id, 'SPECIAL', 0, 20, array());
 277          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_letter_returns(), $return);
 278          $this->assertCount(2, $return['entries']);
 279          $this->assertEquals(2, $return['count']);
 280          $this->assertEquals($e1a->id, $return['entries'][0]['id']);
 281          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 282  
 283          // Requesting with limit.
 284          $return = mod_glossary_external::get_entries_by_letter($g1->id, 'ALL', 0, 1, array());
 285          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_letter_returns(), $return);
 286          $this->assertCount(1, $return['entries']);
 287          $this->assertEquals(3, $return['count']);
 288          $this->assertEquals($e1a->id, $return['entries'][0]['id']);
 289          $return = mod_glossary_external::get_entries_by_letter($g1->id, 'ALL', 1, 2, array());
 290          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_letter_returns(), $return);
 291          $this->assertCount(2, $return['entries']);
 292          $this->assertEquals(3, $return['count']);
 293          $this->assertEquals($e1c->id, $return['entries'][0]['id']);
 294          $this->assertEquals($e1b->id, $return['entries'][1]['id']);
 295      }
 296  
 297      public function test_get_entries_by_date() {
 298          global $DB;
 299          $this->resetAfterTest(true);
 300  
 301          // Generate all the things.
 302          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 303          $c1 = $this->getDataGenerator()->create_course();
 304          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'displayformat' => 'entrylist'));
 305          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 306          $u1 = $this->getDataGenerator()->create_user();
 307          $ctx = context_module::instance($g1->cmid);
 308          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 309  
 310          $now = time();
 311          $e1a = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Bob', 'userid' => $u1->id,
 312              'timecreated' => 1, 'timemodified' => $now + 3600, 'tags' => array('Cats', 'Dogs')));
 313          $e1b = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Jane', 'userid' => $u1->id,
 314              'timecreated' => $now + 3600, 'timemodified' => 1));
 315          $e1c = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Alice', 'userid' => $u1->id,
 316              'timecreated' => $now + 1, 'timemodified' => $now + 1));
 317          $e1d = $gg->create_content($g1, array('approved' => 0, 'concept' => '0-day', 'userid' => $u1->id,
 318              'timecreated' => $now + 2, 'timemodified' => $now + 2));
 319          $e2a = $gg->create_content($g2);
 320  
 321          $this->setAdminUser($u1);
 322  
 323          // Ordering by time modified descending.
 324          $return = mod_glossary_external::get_entries_by_date($g1->id, 'UPDATE', 'DESC', 0, 20, array());
 325          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
 326          $this->assertCount(3, $return['entries']);
 327          $this->assertEquals(3, $return['count']);
 328          $this->assertEquals($e1a->id, $return['entries'][0]['id']);
 329          $this->assertEquals('Cats', $return['entries'][0]['tags'][0]['rawname']);
 330          $this->assertEquals('Dogs', $return['entries'][0]['tags'][1]['rawname']);
 331          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 332          $this->assertEquals($e1b->id, $return['entries'][2]['id']);
 333  
 334          // Ordering by time modified ascending.
 335          $return = mod_glossary_external::get_entries_by_date($g1->id, 'UPDATE', 'ASC', 0, 20, array());
 336          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
 337          $this->assertCount(3, $return['entries']);
 338          $this->assertEquals(3, $return['count']);
 339          $this->assertEquals($e1b->id, $return['entries'][0]['id']);
 340          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 341          $this->assertEquals($e1a->id, $return['entries'][2]['id']);
 342  
 343          // Ordering by time created asc.
 344          $return = mod_glossary_external::get_entries_by_date($g1->id, 'CREATION', 'ASC', 0, 20, array());
 345          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
 346          $this->assertCount(3, $return['entries']);
 347          $this->assertEquals(3, $return['count']);
 348          $this->assertEquals($e1a->id, $return['entries'][0]['id']);
 349          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 350          $this->assertEquals($e1b->id, $return['entries'][2]['id']);
 351  
 352          // Ordering by time created descending.
 353          $return = mod_glossary_external::get_entries_by_date($g1->id, 'CREATION', 'DESC', 0, 20, array());
 354          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
 355          $this->assertCount(3, $return['entries']);
 356          $this->assertEquals(3, $return['count']);
 357          $this->assertEquals($e1b->id, $return['entries'][0]['id']);
 358          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 359          $this->assertEquals($e1a->id, $return['entries'][2]['id']);
 360  
 361          // Ordering including to approve.
 362          $return = mod_glossary_external::get_entries_by_date($g1->id, 'CREATION', 'ASC', 0, 20,
 363              array('includenotapproved' => true));
 364          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
 365          $this->assertCount(4, $return['entries']);
 366          $this->assertEquals(4, $return['count']);
 367          $this->assertEquals($e1a->id, $return['entries'][0]['id']);
 368          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 369          $this->assertEquals($e1d->id, $return['entries'][2]['id']);
 370          $this->assertEquals($e1b->id, $return['entries'][3]['id']);
 371  
 372          // Ordering including to approve and pagination.
 373          $return = mod_glossary_external::get_entries_by_date($g1->id, 'CREATION', 'ASC', 0, 2,
 374              array('includenotapproved' => true));
 375          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
 376          $this->assertCount(2, $return['entries']);
 377          $this->assertEquals(4, $return['count']);
 378          $this->assertEquals($e1a->id, $return['entries'][0]['id']);
 379          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 380          $return = mod_glossary_external::get_entries_by_date($g1->id, 'CREATION', 'ASC', 2, 2,
 381              array('includenotapproved' => true));
 382          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
 383          $this->assertCount(2, $return['entries']);
 384          $this->assertEquals(4, $return['count']);
 385          $this->assertEquals($e1d->id, $return['entries'][0]['id']);
 386          $this->assertEquals($e1b->id, $return['entries'][1]['id']);
 387      }
 388  
 389      public function test_get_categories() {
 390          $this->resetAfterTest(true);
 391          $this->setAdminUser();
 392  
 393          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 394          $c1 = $this->getDataGenerator()->create_course();
 395          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 396          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 397          $cat1a = $gg->create_category($g1);
 398          $cat1b = $gg->create_category($g1);
 399          $cat1c = $gg->create_category($g1);
 400          $cat2a = $gg->create_category($g2);
 401  
 402          $return = mod_glossary_external::get_categories($g1->id, 0, 20);
 403          $return = external_api::clean_returnvalue(mod_glossary_external::get_categories_returns(), $return);
 404          $this->assertCount(3, $return['categories']);
 405          $this->assertEquals(3, $return['count']);
 406          $this->assertEquals($cat1a->id, $return['categories'][0]['id']);
 407          $this->assertEquals($cat1b->id, $return['categories'][1]['id']);
 408          $this->assertEquals($cat1c->id, $return['categories'][2]['id']);
 409  
 410          $return = mod_glossary_external::get_categories($g1->id, 1, 2);
 411          $return = external_api::clean_returnvalue(mod_glossary_external::get_categories_returns(), $return);
 412          $this->assertCount(2, $return['categories']);
 413          $this->assertEquals(3, $return['count']);
 414          $this->assertEquals($cat1b->id, $return['categories'][0]['id']);
 415          $this->assertEquals($cat1c->id, $return['categories'][1]['id']);
 416      }
 417  
 418      public function test_get_entries_by_category() {
 419          $this->resetAfterTest(true);
 420  
 421          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 422          $c1 = $this->getDataGenerator()->create_course();
 423          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'displayformat' => 'entrylist'));
 424          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'displayformat' => 'entrylist'));
 425          $u1 = $this->getDataGenerator()->create_user();
 426          $ctx = context_module::instance($g1->cmid);
 427  
 428          $e1a1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id, 'tags' => array('Cats', 'Dogs')));
 429          $e1a2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
 430          $e1a3 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
 431          $e1b1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
 432          $e1b2 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u1->id));
 433          $e1x1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
 434          $e1x2 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u1->id));
 435          $e2a1 = $gg->create_content($g2, array('approved' => 1, 'userid' => $u1->id));
 436          $e2a2 = $gg->create_content($g2, array('approved' => 1, 'userid' => $u1->id));
 437  
 438          $cat1a = $gg->create_category($g1, array('name' => 'Fish'), array($e1a1, $e1a2, $e1a3));
 439          $cat1b = $gg->create_category($g1, array('name' => 'Cat'), array($e1b1, $e1b2));
 440          $cat1c = $gg->create_category($g1, array('name' => 'Zebra'), array($e1b1));   // Entry $e1b1 is in two categories.
 441          $cat2a = $gg->create_category($g2, array(), array($e2a1, $e2a2));
 442  
 443          $this->setAdminUser();
 444  
 445          // Browse one category.
 446          $return = mod_glossary_external::get_entries_by_category($g1->id, $cat1a->id, 0, 20, array());
 447          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_category_returns(), $return);
 448          $this->assertCount(3, $return['entries']);
 449          $this->assertEquals(3, $return['count']);
 450          $this->assertEquals($e1a1->id, $return['entries'][0]['id']);
 451          $this->assertEquals('Cats', $return['entries'][0]['tags'][0]['rawname']);
 452          $this->assertEquals('Dogs', $return['entries'][0]['tags'][1]['rawname']);
 453          $this->assertEquals($e1a2->id, $return['entries'][1]['id']);
 454          $this->assertEquals($e1a3->id, $return['entries'][2]['id']);
 455  
 456          // Browse all categories.
 457          $return = mod_glossary_external::get_entries_by_category($g1->id, GLOSSARY_SHOW_ALL_CATEGORIES, 0, 20, array());
 458          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_category_returns(), $return);
 459          $this->assertCount(5, $return['entries']);
 460          $this->assertEquals(5, $return['count']);
 461          $this->assertEquals($e1b1->id, $return['entries'][0]['id']);
 462          $this->assertEquals($e1a1->id, $return['entries'][1]['id']);
 463          $this->assertEquals($e1a2->id, $return['entries'][2]['id']);
 464          $this->assertEquals($e1a3->id, $return['entries'][3]['id']);
 465          $this->assertEquals($e1b1->id, $return['entries'][4]['id']);
 466  
 467          // Browse uncategorised.
 468          $return = mod_glossary_external::get_entries_by_category($g1->id, GLOSSARY_SHOW_NOT_CATEGORISED, 0, 20, array());
 469          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_category_returns(), $return);
 470          $this->assertCount(1, $return['entries']);
 471          $this->assertEquals(1, $return['count']);
 472          $this->assertEquals($e1x1->id, $return['entries'][0]['id']);
 473  
 474          // Including to approve.
 475          $return = mod_glossary_external::get_entries_by_category($g1->id, $cat1b->id, 0, 20,
 476              array('includenotapproved' => true));
 477          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_category_returns(), $return);
 478          $this->assertCount(2, $return['entries']);
 479          $this->assertEquals(2, $return['count']);
 480          $this->assertEquals($e1b1->id, $return['entries'][0]['id']);
 481          $this->assertEquals($e1b2->id, $return['entries'][1]['id']);
 482  
 483          // Using limit.
 484          $return = mod_glossary_external::get_entries_by_category($g1->id, GLOSSARY_SHOW_ALL_CATEGORIES, 0, 3,
 485              array('includenotapproved' => true));
 486          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_category_returns(), $return);
 487          $this->assertCount(3, $return['entries']);
 488          $this->assertEquals(6, $return['count']);
 489          $this->assertEquals($e1b1->id, $return['entries'][0]['id']);
 490          $this->assertEquals($e1b2->id, $return['entries'][1]['id']);
 491          $this->assertEquals($e1a1->id, $return['entries'][2]['id']);
 492          $return = mod_glossary_external::get_entries_by_category($g1->id, GLOSSARY_SHOW_ALL_CATEGORIES, 3, 2,
 493              array('includenotapproved' => true));
 494          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_category_returns(), $return);
 495          $this->assertCount(2, $return['entries']);
 496          $this->assertEquals(6, $return['count']);
 497          $this->assertEquals($e1a2->id, $return['entries'][0]['id']);
 498          $this->assertEquals($e1a3->id, $return['entries'][1]['id']);
 499      }
 500  
 501      public function test_get_authors() {
 502          $this->resetAfterTest(true);
 503  
 504          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 505          $c1 = $this->getDataGenerator()->create_course();
 506          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 507          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 508  
 509          $u1 = $this->getDataGenerator()->create_user(array('lastname' => 'Upsilon'));
 510          $u2 = $this->getDataGenerator()->create_user(array('lastname' => 'Alpha'));
 511          $u3 = $this->getDataGenerator()->create_user(array('lastname' => 'Omega'));
 512  
 513          $ctx = context_module::instance($g1->cmid);
 514  
 515          $e1a = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1));
 516          $e1b = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1));
 517          $e1c = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1));
 518          $e2a = $gg->create_content($g1, array('userid' => $u2->id, 'approved' => 1));
 519          $e3a = $gg->create_content($g1, array('userid' => $u3->id, 'approved' => 0));
 520  
 521          $this->setAdminUser();
 522  
 523          // Simple request.
 524          $return = mod_glossary_external::get_authors($g1->id, 0, 20, array());
 525          $return = external_api::clean_returnvalue(mod_glossary_external::get_authors_returns(), $return);
 526          $this->assertCount(2, $return['authors']);
 527          $this->assertEquals(2, $return['count']);
 528          $this->assertEquals($u2->id, $return['authors'][0]['id']);
 529          $this->assertEquals($u1->id, $return['authors'][1]['id']);
 530  
 531          // Include users with entries pending approval.
 532          $return = mod_glossary_external::get_authors($g1->id, 0, 20, array('includenotapproved' => true));
 533          $return = external_api::clean_returnvalue(mod_glossary_external::get_authors_returns(), $return);
 534          $this->assertCount(3, $return['authors']);
 535          $this->assertEquals(3, $return['count']);
 536          $this->assertEquals($u2->id, $return['authors'][0]['id']);
 537          $this->assertEquals($u3->id, $return['authors'][1]['id']);
 538          $this->assertEquals($u1->id, $return['authors'][2]['id']);
 539  
 540          // Pagination.
 541          $return = mod_glossary_external::get_authors($g1->id, 1, 1, array('includenotapproved' => true));
 542          $return = external_api::clean_returnvalue(mod_glossary_external::get_authors_returns(), $return);
 543          $this->assertCount(1, $return['authors']);
 544          $this->assertEquals(3, $return['count']);
 545          $this->assertEquals($u3->id, $return['authors'][0]['id']);
 546      }
 547  
 548      public function test_get_entries_by_author() {
 549          $this->resetAfterTest(true);
 550  
 551          // Generate all the things.
 552          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 553          $c1 = $this->getDataGenerator()->create_course();
 554          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'displayformat' => 'entrylist'));
 555          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'displayformat' => 'entrylist'));
 556          $u1 = $this->getDataGenerator()->create_user(array('lastname' => 'Upsilon', 'firstname' => 'Zac'));
 557          $u2 = $this->getDataGenerator()->create_user(array('lastname' => 'Ultra', 'firstname' => '1337'));
 558          $u3 = $this->getDataGenerator()->create_user(array('lastname' => 'Alpha', 'firstname' => 'Omega'));
 559          $u4 = $this->getDataGenerator()->create_user(array('lastname' => '0-day', 'firstname' => 'Zoe'));
 560          $ctx = context_module::instance($g1->cmid);
 561          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 562  
 563          $e1a1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
 564          $e1a2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
 565          $e1a3 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
 566          $e1b1 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u2->id));
 567          $e1b2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u2->id, 'tags' => array('Cats', 'Dogs')));
 568          $e1c1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u3->id));
 569          $e1d1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u4->id));
 570          $e2a = $gg->create_content($g2, array('approved' => 1, 'userid' => $u1->id));
 571  
 572          $this->setUser($u1);
 573  
 574          // Requesting a single letter.
 575          $return = mod_glossary_external::get_entries_by_author($g1->id, 'u', 'LASTNAME', 'ASC', 0, 20, array());
 576          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 577          $this->assertCount(4, $return['entries']);
 578          $this->assertEquals(4, $return['count']);
 579          $this->assertEquals($e1b2->id, $return['entries'][0]['id']);
 580          $this->assertEquals('Cats', $return['entries'][0]['tags'][0]['rawname']);
 581          $this->assertEquals('Dogs', $return['entries'][0]['tags'][1]['rawname']);
 582          $this->assertEquals($e1a1->id, $return['entries'][1]['id']);
 583          $this->assertEquals($e1a2->id, $return['entries'][2]['id']);
 584          $this->assertEquals($e1a3->id, $return['entries'][3]['id']);
 585  
 586          // Requesting special letters.
 587          $return = mod_glossary_external::get_entries_by_author($g1->id, 'SPECIAL', 'LASTNAME', 'ASC', 0, 20, array());
 588          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 589          $this->assertCount(1, $return['entries']);
 590          $this->assertEquals(1, $return['count']);
 591          $this->assertEquals($e1d1->id, $return['entries'][0]['id']);
 592  
 593          // Requesting with limit.
 594          $return = mod_glossary_external::get_entries_by_author($g1->id, 'ALL', 'LASTNAME', 'ASC', 0, 1, array());
 595          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 596          $this->assertCount(1, $return['entries']);
 597          $this->assertEquals(6, $return['count']);
 598          $this->assertEquals($e1d1->id, $return['entries'][0]['id']);
 599          $return = mod_glossary_external::get_entries_by_author($g1->id, 'ALL', 'LASTNAME', 'ASC', 1, 2, array());
 600          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 601          $this->assertCount(2, $return['entries']);
 602          $this->assertEquals(6, $return['count']);
 603          $this->assertEquals($e1c1->id, $return['entries'][0]['id']);
 604          $this->assertEquals($e1b2->id, $return['entries'][1]['id']);
 605  
 606          // Including non-approved.
 607          $this->setAdminUser();
 608          $return = mod_glossary_external::get_entries_by_author($g1->id, 'ALL', 'LASTNAME', 'ASC', 0, 20,
 609              array('includenotapproved' => true));
 610          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 611          $this->assertCount(7, $return['entries']);
 612          $this->assertEquals(7, $return['count']);
 613          $this->assertEquals($e1d1->id, $return['entries'][0]['id']);
 614          $this->assertEquals($e1c1->id, $return['entries'][1]['id']);
 615          $this->assertEquals($e1b1->id, $return['entries'][2]['id']);
 616          $this->assertEquals($e1b2->id, $return['entries'][3]['id']);
 617          $this->assertEquals($e1a1->id, $return['entries'][4]['id']);
 618          $this->assertEquals($e1a2->id, $return['entries'][5]['id']);
 619          $this->assertEquals($e1a3->id, $return['entries'][6]['id']);
 620  
 621          // Changing order.
 622          $return = mod_glossary_external::get_entries_by_author($g1->id, 'ALL', 'LASTNAME', 'DESC', 0, 1, array());
 623          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 624          $this->assertCount(1, $return['entries']);
 625          $this->assertEquals(6, $return['count']);
 626          $this->assertEquals($e1a1->id, $return['entries'][0]['id']);
 627  
 628          // Sorting by firstname.
 629          $return = mod_glossary_external::get_entries_by_author($g1->id, 'ALL', 'FIRSTNAME', 'ASC', 0, 1, array());
 630          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 631          $this->assertCount(1, $return['entries']);
 632          $this->assertEquals(6, $return['count']);
 633          $this->assertEquals($e1b2->id, $return['entries'][0]['id']);
 634  
 635          // Sorting by firstname descending.
 636          $return = mod_glossary_external::get_entries_by_author($g1->id, 'ALL', 'FIRSTNAME', 'DESC', 0, 1, array());
 637          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 638          $this->assertCount(1, $return['entries']);
 639          $this->assertEquals(6, $return['count']);
 640          $this->assertEquals($e1d1->id, $return['entries'][0]['id']);
 641  
 642          // Filtering by firstname descending.
 643          $return = mod_glossary_external::get_entries_by_author($g1->id, 'z', 'FIRSTNAME', 'DESC', 0, 20, array());
 644          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 645          $this->assertCount(4, $return['entries']);
 646          $this->assertEquals(4, $return['count']);
 647          $this->assertEquals($e1d1->id, $return['entries'][0]['id']);
 648          $this->assertEquals($e1a1->id, $return['entries'][1]['id']);
 649          $this->assertEquals($e1a2->id, $return['entries'][2]['id']);
 650          $this->assertEquals($e1a3->id, $return['entries'][3]['id']);
 651  
 652          // Test with a deleted user.
 653          delete_user($u2);
 654          $return = mod_glossary_external::get_entries_by_author($g1->id, 'u', 'LASTNAME', 'ASC', 0, 20, array());
 655          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
 656          $this->assertCount(4, $return['entries']);
 657          $this->assertEquals(4, $return['count']);
 658          $this->assertEquals($e1b2->id, $return['entries'][0]['id']);
 659          $this->assertEquals($e1a1->id, $return['entries'][1]['id']);
 660          $this->assertEquals($e1a2->id, $return['entries'][2]['id']);
 661          $this->assertEquals($e1a3->id, $return['entries'][3]['id']);
 662      }
 663  
 664      public function test_get_entries_by_author_id() {
 665          $this->resetAfterTest(true);
 666  
 667          // Generate all the things.
 668          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 669          $c1 = $this->getDataGenerator()->create_course();
 670          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'displayformat' => 'entrylist'));
 671          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id, 'displayformat' => 'entrylist'));
 672          $u1 = $this->getDataGenerator()->create_user(array('lastname' => 'Upsilon', 'firstname' => 'Zac'));
 673          $u2 = $this->getDataGenerator()->create_user(array('lastname' => 'Ultra', 'firstname' => '1337'));
 674          $u3 = $this->getDataGenerator()->create_user(array('lastname' => 'Alpha', 'firstname' => 'Omega'));
 675          $u4 = $this->getDataGenerator()->create_user(array('lastname' => '0-day', 'firstname' => 'Zoe'));
 676          $ctx = context_module::instance($g1->cmid);
 677          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 678  
 679          $e1a1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id, 'concept' => 'Zoom',
 680              'timecreated' => 3600, 'timemodified' => time() - 3600));
 681          $e1a2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id, 'concept' => 'Alpha'));
 682          $e1a3 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id, 'concept' => 'Dog',
 683              'timecreated' => 1, 'timemodified' => time() - 1800));
 684          $e1a4 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u1->id, 'concept' => 'Bird'));
 685          $e1b1 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u2->id));
 686          $e2a = $gg->create_content($g2, array('approved' => 1, 'userid' => $u1->id));
 687  
 688          $this->setAdminUser();
 689  
 690          // Standard request.
 691          $return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CONCEPT', 'ASC', 0, 20, array());
 692          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
 693          $this->assertCount(3, $return['entries']);
 694          $this->assertEquals(3, $return['count']);
 695          $this->assertEquals($e1a2->id, $return['entries'][0]['id']);
 696          $this->assertEquals($e1a3->id, $return['entries'][1]['id']);
 697          $this->assertEquals($e1a1->id, $return['entries'][2]['id']);
 698  
 699          // Standard request descending.
 700          $return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CONCEPT', 'DESC', 0, 20, array());
 701          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
 702          $this->assertCount(3, $return['entries']);
 703          $this->assertEquals(3, $return['count']);
 704          $this->assertEquals($e1a1->id, $return['entries'][0]['id']);
 705          $this->assertEquals($e1a3->id, $return['entries'][1]['id']);
 706          $this->assertEquals($e1a2->id, $return['entries'][2]['id']);
 707  
 708          // Requesting ordering by time created.
 709          $return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CREATION', 'ASC', 0, 20, array());
 710          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
 711          $this->assertCount(3, $return['entries']);
 712          $this->assertEquals(3, $return['count']);
 713          $this->assertEquals($e1a3->id, $return['entries'][0]['id']);
 714          $this->assertEquals($e1a1->id, $return['entries'][1]['id']);
 715          $this->assertEquals($e1a2->id, $return['entries'][2]['id']);
 716  
 717          // Requesting ordering by time created descending.
 718          $return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CREATION', 'DESC', 0, 20, array());
 719          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
 720          $this->assertCount(3, $return['entries']);
 721          $this->assertEquals(3, $return['count']);
 722          $this->assertEquals($e1a2->id, $return['entries'][0]['id']);
 723          $this->assertEquals($e1a1->id, $return['entries'][1]['id']);
 724          $this->assertEquals($e1a3->id, $return['entries'][2]['id']);
 725  
 726          // Requesting ordering by time modified.
 727          $return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'UPDATE', 'ASC', 0, 20, array());
 728          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
 729          $this->assertCount(3, $return['entries']);
 730          $this->assertEquals(3, $return['count']);
 731          $this->assertEquals($e1a1->id, $return['entries'][0]['id']);
 732          $this->assertEquals($e1a3->id, $return['entries'][1]['id']);
 733          $this->assertEquals($e1a2->id, $return['entries'][2]['id']);
 734  
 735          // Requesting ordering by time modified descending.
 736          $return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'UPDATE', 'DESC', 0, 20, array());
 737          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
 738          $this->assertCount(3, $return['entries']);
 739          $this->assertEquals(3, $return['count']);
 740          $this->assertEquals($e1a2->id, $return['entries'][0]['id']);
 741          $this->assertEquals($e1a3->id, $return['entries'][1]['id']);
 742          $this->assertEquals($e1a1->id, $return['entries'][2]['id']);
 743  
 744          // Including non approved.
 745          $return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CONCEPT', 'ASC', 0, 20,
 746              array('includenotapproved' => true));
 747          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
 748          $this->assertCount(4, $return['entries']);
 749          $this->assertEquals(4, $return['count']);
 750          $this->assertEquals($e1a2->id, $return['entries'][0]['id']);
 751          $this->assertEquals($e1a4->id, $return['entries'][1]['id']);
 752          $this->assertEquals($e1a3->id, $return['entries'][2]['id']);
 753          $this->assertEquals($e1a1->id, $return['entries'][3]['id']);
 754  
 755          // Pagination.
 756          $return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CONCEPT', 'ASC', 0, 2,
 757              array('includenotapproved' => true));
 758          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
 759          $this->assertCount(2, $return['entries']);
 760          $this->assertEquals(4, $return['count']);
 761          $this->assertEquals($e1a2->id, $return['entries'][0]['id']);
 762          $this->assertEquals($e1a4->id, $return['entries'][1]['id']);
 763          $return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CONCEPT', 'ASC', 1, 2,
 764              array('includenotapproved' => true));
 765          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
 766          $this->assertCount(2, $return['entries']);
 767          $this->assertEquals(4, $return['count']);
 768          $this->assertEquals($e1a4->id, $return['entries'][0]['id']);
 769          $this->assertEquals($e1a3->id, $return['entries'][1]['id']);
 770      }
 771  
 772      public function test_get_entries_by_search() {
 773          $this->resetAfterTest(true);
 774  
 775          // Generate all the things.
 776          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 777          $c1 = $this->getDataGenerator()->create_course();
 778          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 779          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 780          $u1 = $this->getDataGenerator()->create_user();
 781          $ctx = context_module::instance($g1->cmid);
 782          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 783          $this->setUser($u1);
 784  
 785          $e1 = $gg->create_content($g1, array('approved' => 1, 'concept' => 'House', 'timecreated' => time() + 3600));
 786          $e2 = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Mouse', 'timemodified' => 1));
 787          $e3 = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Hero', 'tags' => array('Cats', 'Dogs')));
 788          $e4 = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Toulouse'));
 789          $e5 = $gg->create_content($g1, array('approved' => 1, 'definition' => 'Heroes', 'concept' => 'Abcd'));
 790          $e6 = $gg->create_content($g1, array('approved' => 0, 'definition' => 'When used for Heroes'));
 791          $e7 = $gg->create_content($g1, array('approved' => 1, 'timecreated' => 1, 'timemodified' => time() + 3600,
 792              'concept' => 'Z'), array('Couscous'));
 793          $e8 = $gg->create_content($g1, array('approved' => 0), array('Heroes'));
 794          $e9 = $gg->create_content($g2, array('approved' => 0));
 795  
 796          $this->setAdminUser();
 797  
 798          // Test simple query.
 799          $query = 'hero';
 800          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, false, 'CONCEPT', 'ASC', 0, 20, array());
 801          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 802          $this->assertCount(1, $return['entries']);
 803          $this->assertEquals(1, $return['count']);
 804          $this->assertEquals($e3->id, $return['entries'][0]['id']);
 805          $this->assertEquals('Cats', $return['entries'][0]['tags'][0]['rawname']);
 806          $this->assertEquals('Dogs', $return['entries'][0]['tags'][1]['rawname']);
 807  
 808          // Enabling full search.
 809          $query = 'hero';
 810          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, true, 'CONCEPT', 'ASC', 0, 20, array());
 811          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 812          $this->assertCount(2, $return['entries']);
 813          $this->assertEquals(2, $return['count']);
 814          $this->assertEquals($e5->id, $return['entries'][0]['id']);
 815          $this->assertEquals($e3->id, $return['entries'][1]['id']);
 816  
 817          // Concept descending.
 818          $query = 'hero';
 819          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, true, 'CONCEPT', 'DESC', 0, 20, array());
 820          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 821          $this->assertCount(2, $return['entries']);
 822          $this->assertEquals(2, $return['count']);
 823          $this->assertEquals($e3->id, $return['entries'][0]['id']);
 824          $this->assertEquals($e5->id, $return['entries'][1]['id']);
 825  
 826          // Search on alias.
 827          $query = 'couscous';
 828          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, false, 'CONCEPT', 'ASC', 0, 20, array());
 829          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 830          $this->assertCount(1, $return['entries']);
 831          $this->assertEquals(1, $return['count']);
 832          $this->assertEquals($e7->id, $return['entries'][0]['id']);
 833          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, true, 'CONCEPT', 'ASC', 0, 20, array());
 834          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 835          $this->assertCount(1, $return['entries']);
 836          $this->assertEquals(1, $return['count']);
 837          $this->assertEquals($e7->id, $return['entries'][0]['id']);
 838  
 839          // Pagination and ordering on created date.
 840          $query = 'ou';
 841          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, false, 'CREATION', 'ASC', 0, 1, array());
 842          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 843          $this->assertCount(1, $return['entries']);
 844          $this->assertEquals(3, $return['count']);
 845          $this->assertEquals($e7->id, $return['entries'][0]['id']);
 846          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, false, 'CREATION', 'DESC', 0, 1, array());
 847          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 848          $this->assertCount(1, $return['entries']);
 849          $this->assertEquals(3, $return['count']);
 850          $this->assertEquals($e1->id, $return['entries'][0]['id']);
 851  
 852          // Ordering on updated date.
 853          $query = 'ou';
 854          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, false, 'UPDATE', 'ASC', 0, 1, array());
 855          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 856          $this->assertCount(1, $return['entries']);
 857          $this->assertEquals(3, $return['count']);
 858          $this->assertEquals($e2->id, $return['entries'][0]['id']);
 859          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, false, 'UPDATE', 'DESC', 0, 1, array());
 860          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 861          $this->assertCount(1, $return['entries']);
 862          $this->assertEquals(3, $return['count']);
 863          $this->assertEquals($e7->id, $return['entries'][0]['id']);
 864  
 865          // Including not approved.
 866          $query = 'ou';
 867          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, false, 'CONCEPT', 'ASC', 0, 20,
 868              array('includenotapproved' => true));
 869          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 870          $this->assertCount(4, $return['entries']);
 871          $this->assertEquals(4, $return['count']);
 872          $this->assertEquals($e1->id, $return['entries'][0]['id']);
 873          $this->assertEquals($e2->id, $return['entries'][1]['id']);
 874          $this->assertEquals($e4->id, $return['entries'][2]['id']);
 875          $this->assertEquals($e7->id, $return['entries'][3]['id']);
 876  
 877          // Advanced query string.
 878          $query = '+Heroes -Abcd';
 879          $return = mod_glossary_external::get_entries_by_search($g1->id, $query, true, 'CONCEPT', 'ASC', 0, 20,
 880              array('includenotapproved' => true));
 881          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
 882          $this->assertCount(2, $return['entries']);
 883          $this->assertEquals(2, $return['count']);
 884          $this->assertEquals($e6->id, $return['entries'][0]['id']);
 885          $this->assertEquals($e8->id, $return['entries'][1]['id']);
 886      }
 887  
 888      public function test_get_entries_by_term() {
 889          $this->resetAfterTest(true);
 890  
 891          // Generate all the things.
 892          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 893          $c1 = $this->getDataGenerator()->create_course();
 894          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 895          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 896          $u1 = $this->getDataGenerator()->create_user();
 897          $ctx = context_module::instance($g1->cmid);
 898          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 899  
 900          $this->setAdminUser();
 901  
 902          $e1 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1, 'concept' => 'cat',
 903              'tags' => array('Cats', 'Dogs')));
 904          $e2 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1), array('cat', 'dog'));
 905          $e3 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1), array('dog'));
 906          $e4 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 0, 'concept' => 'dog'));
 907          $e5 = $gg->create_content($g2, array('userid' => $u1->id, 'approved' => 1, 'concept' => 'dog'), array('cat'));
 908  
 909          // Search concept + alias.
 910          $return = mod_glossary_external::get_entries_by_term($g1->id, 'cat', 0, 20, array('includenotapproved' => false));
 911          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
 912          $this->assertCount(2, $return['entries']);
 913          $this->assertEquals(2, $return['count']);
 914          // Compare ids, ignore ordering of array, using canonicalize parameter of assertEquals.
 915          $expected = array($e1->id, $e2->id);
 916          $actual = array($return['entries'][0]['id'], $return['entries'][1]['id']);
 917          $this->assertEqualsCanonicalizing($expected, $actual);
 918          // Compare rawnames of all expected tags, ignore ordering of array, using canonicalize parameter of assertEquals.
 919          $expected = array('Cats', 'Dogs'); // Only $e1 has 2 tags.
 920          $actual = array(); // Accumulate all tags returned.
 921          foreach ($return['entries'] as $entry) {
 922              foreach ($entry['tags'] as $tag) {
 923                  $actual[] = $tag['rawname'];
 924              }
 925          }
 926          $this->assertEqualsCanonicalizing($expected, $actual);
 927  
 928          // Search alias.
 929          $return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, array('includenotapproved' => false));
 930          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
 931  
 932          $this->assertCount(2, $return['entries']);
 933          $this->assertEquals(2, $return['count']);
 934          // Compare ids, ignore ordering of array, using canonicalize parameter of assertEquals.
 935          $expected = array($e2->id, $e3->id);
 936          $actual = array($return['entries'][0]['id'], $return['entries'][1]['id']);
 937          $this->assertEqualsCanonicalizing($expected, $actual);
 938  
 939          // Search including not approved.
 940          $return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, array('includenotapproved' => true));
 941          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
 942          $this->assertCount(3, $return['entries']);
 943          $this->assertEquals(3, $return['count']);
 944          // Compare ids, ignore ordering of array, using canonicalize parameter of assertEquals.
 945          $expected = array($e4->id, $e2->id, $e3->id);
 946          $actual = array($return['entries'][0]['id'], $return['entries'][1]['id'], $return['entries'][2]['id']);
 947          $this->assertEqualsCanonicalizing($expected, $actual);
 948  
 949          // Pagination.
 950          $return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 1, array('includenotapproved' => true));
 951          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
 952          $this->assertCount(1, $return['entries']);
 953          // We don't compare the returned entry id because it may be different depending on the DBMS,
 954          // for example, Postgres does a random sorting in this case.
 955          $this->assertEquals(3, $return['count']);
 956          $return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 1, 1, array('includenotapproved' => true));
 957          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
 958          $this->assertCount(1, $return['entries']);
 959          $this->assertEquals(3, $return['count']);
 960      }
 961  
 962      public function test_get_entries_to_approve() {
 963          $this->resetAfterTest(true);
 964  
 965          // Generate all the things.
 966          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
 967          $c1 = $this->getDataGenerator()->create_course();
 968          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 969          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
 970          $u1 = $this->getDataGenerator()->create_user();
 971          $ctx = context_module::instance($g1->cmid);
 972          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
 973  
 974          $e1a = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Bob', 'userid' => $u1->id,
 975              'timecreated' => time() + 3600));
 976          $e1b = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Jane', 'userid' => $u1->id, 'timecreated' => 1));
 977          $e1c = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Alice', 'userid' => $u1->id, 'timemodified' => 1));
 978          $e1d = $gg->create_content($g1, array('approved' => 0, 'concept' => '0-day', 'userid' => $u1->id,
 979              'timemodified' => time() + 3600));
 980          $e1e = $gg->create_content($g1, array('approved' => 1, 'concept' => '1-day', 'userid' => $u1->id));
 981          $e2a = $gg->create_content($g2);
 982  
 983          $this->setAdminUser(true);
 984  
 985          // Simple listing.
 986          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'ASC', 0, 20);
 987          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
 988          $this->assertCount(4, $return['entries']);
 989          $this->assertEquals(4, $return['count']);
 990          $this->assertEquals($e1d->id, $return['entries'][0]['id']);
 991          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
 992          $this->assertEquals($e1a->id, $return['entries'][2]['id']);
 993          $this->assertEquals($e1b->id, $return['entries'][3]['id']);
 994  
 995          // Revert ordering of concept.
 996          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'DESC', 0, 20);
 997          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
 998          $this->assertCount(4, $return['entries']);
 999          $this->assertEquals(4, $return['count']);
1000          $this->assertEquals($e1b->id, $return['entries'][0]['id']);
1001          $this->assertEquals($e1a->id, $return['entries'][1]['id']);
1002          $this->assertEquals($e1c->id, $return['entries'][2]['id']);
1003          $this->assertEquals($e1d->id, $return['entries'][3]['id']);
1004  
1005          // Filtering by letter.
1006          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'a', 'CONCEPT', 'ASC', 0, 20);
1007          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
1008          $this->assertCount(1, $return['entries']);
1009          $this->assertEquals(1, $return['count']);
1010          $this->assertEquals($e1c->id, $return['entries'][0]['id']);
1011  
1012          // Filtering by special.
1013          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'SPECIAL', 'CONCEPT', 'ASC', 0, 20);
1014          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
1015          $this->assertCount(1, $return['entries']);
1016          $this->assertEquals(1, $return['count']);
1017          $this->assertEquals($e1d->id, $return['entries'][0]['id']);
1018  
1019          // Pagination.
1020          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'ASC', 0, 2);
1021          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
1022          $this->assertCount(2, $return['entries']);
1023          $this->assertEquals(4, $return['count']);
1024          $this->assertEquals($e1d->id, $return['entries'][0]['id']);
1025          $this->assertEquals($e1c->id, $return['entries'][1]['id']);
1026          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'ASC', 1, 2);
1027          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
1028          $this->assertCount(2, $return['entries']);
1029          $this->assertEquals(4, $return['count']);
1030          $this->assertEquals($e1c->id, $return['entries'][0]['id']);
1031          $this->assertEquals($e1a->id, $return['entries'][1]['id']);
1032  
1033          // Ordering by creation date.
1034          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CREATION', 'ASC', 0, 1);
1035          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
1036          $this->assertCount(1, $return['entries']);
1037          $this->assertEquals(4, $return['count']);
1038          $this->assertEquals($e1b->id, $return['entries'][0]['id']);
1039  
1040          // Ordering by creation date desc.
1041          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CREATION', 'DESC', 0, 1);
1042          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
1043          $this->assertCount(1, $return['entries']);
1044          $this->assertEquals(4, $return['count']);
1045          $this->assertEquals($e1a->id, $return['entries'][0]['id']);
1046  
1047          // Ordering by update date.
1048          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'UPDATE', 'ASC', 0, 1);
1049          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
1050          $this->assertCount(1, $return['entries']);
1051          $this->assertEquals(4, $return['count']);
1052          $this->assertEquals($e1c->id, $return['entries'][0]['id']);
1053  
1054          // Ordering by update date desc.
1055          $return = mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'UPDATE', 'DESC', 0, 1);
1056          $return = external_api::clean_returnvalue(mod_glossary_external::get_entries_to_approve_returns(), $return);
1057          $this->assertCount(1, $return['entries']);
1058          $this->assertEquals(4, $return['count']);
1059          $this->assertEquals($e1d->id, $return['entries'][0]['id']);
1060  
1061          // Permissions are checked.
1062          $this->setUser($u1);
1063          $this->expectException('required_capability_exception');
1064          mod_glossary_external::get_entries_to_approve($g1->id, 'ALL', 'CONCEPT', 'ASC', 0, 1);
1065          $this->fail('Do not test anything else after this.');
1066      }
1067  
1068      public function test_get_entry_by_id() {
1069          $this->resetAfterTest(true);
1070  
1071          // Generate all the things.
1072          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
1073          $c1 = $this->getDataGenerator()->create_course();
1074          $c2 = $this->getDataGenerator()->create_course();
1075          $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
1076          $g2 = $this->getDataGenerator()->create_module('glossary', array('course' => $c2->id, 'visible' => 0));
1077          $u1 = $this->getDataGenerator()->create_user();
1078          $u2 = $this->getDataGenerator()->create_user();
1079          $u3 = $this->getDataGenerator()->create_user();
1080          $ctx = context_module::instance($g1->cmid);
1081          $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
1082          $this->getDataGenerator()->enrol_user($u2->id, $c1->id);
1083          $this->getDataGenerator()->enrol_user($u3->id, $c1->id);
1084  
1085          $e1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id, 'tags' => array('Cats', 'Dogs')));
1086          // Add a fake inline image to the entry.
1087          $filename = 'shouldbeanimage.jpg';
1088          $filerecordinline = array(
1089              'contextid' => $ctx->id,
1090              'component' => 'mod_glossary',
1091              'filearea'  => 'entry',
1092              'itemid'    => $e1->id,
1093              'filepath'  => '/',
1094              'filename'  => $filename,
1095          );
1096          $fs = get_file_storage();
1097          $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
1098  
1099          $e2 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u1->id));
1100          $e3 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u2->id));
1101          $e4 = $gg->create_content($g2, array('approved' => 1));
1102  
1103          $this->setUser($u1);
1104          $return = mod_glossary_external::get_entry_by_id($e1->id);
1105          $return = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $return);
1106          $this->assertEquals($e1->id, $return['entry']['id']);
1107          $this->assertEquals('Cats', $return['entry']['tags'][0]['rawname']);
1108          $this->assertEquals('Dogs', $return['entry']['tags'][1]['rawname']);
1109          $this->assertEquals($filename, $return['entry']['definitioninlinefiles'][0]['filename']);
1110          $this->assertTrue($return['permissions']['candelete']);
1111  
1112          $return = mod_glossary_external::get_entry_by_id($e2->id);
1113          $return = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $return);
1114          $this->assertEquals($e2->id, $return['entry']['id']);
1115          $this->assertTrue($return['permissions']['candelete']);
1116  
1117          try {
1118              $return = mod_glossary_external::get_entry_by_id($e3->id);
1119              $this->fail('Cannot view unapproved entries of others.');
1120          } catch (invalid_parameter_exception $e) {
1121              // All good.
1122          }
1123  
1124          try {
1125              $return = mod_glossary_external::get_entry_by_id($e4->id);
1126              $this->fail('Cannot view entries from another course.');
1127          } catch (require_login_exception $e) {
1128              // All good.
1129          }
1130  
1131          // An admin can see other's entries to be approved.
1132          $this->setAdminUser();
1133          $return = mod_glossary_external::get_entry_by_id($e3->id);
1134          $return = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $return);
1135          $this->assertEquals($e3->id, $return['entry']['id']);
1136          $this->assertTrue($return['permissions']['candelete']);
1137  
1138          // Students can see other students approved entries but they will not be able to delete them.
1139          $this->setUser($u3);
1140          $return = mod_glossary_external::get_entry_by_id($e1->id);
1141          $return = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $return);
1142          $this->assertEquals($e1->id, $return['entry']['id']);
1143          $this->assertFalse($return['permissions']['candelete']);
1144      }
1145  
1146      public function test_add_entry_without_optional_settings() {
1147          global $CFG, $DB;
1148          $this->resetAfterTest(true);
1149  
1150          $course = $this->getDataGenerator()->create_course();
1151          $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id));
1152  
1153          $this->setAdminUser();
1154          $concept = 'A concept';
1155          $definition = '<p>A definition</p>';
1156          $return = mod_glossary_external::add_entry($glossary->id, $concept, $definition, FORMAT_HTML);
1157          $return = external_api::clean_returnvalue(mod_glossary_external::add_entry_returns(), $return);
1158  
1159          // Get entry from DB.
1160          $entry = $DB->get_record('glossary_entries', array('id' => $return['entryid']));
1161  
1162          $this->assertEquals($concept, $entry->concept);
1163          $this->assertEquals($definition, $entry->definition);
1164          $this->assertEquals($CFG->glossary_linkentries, $entry->usedynalink);
1165          $this->assertEquals($CFG->glossary_casesensitive, $entry->casesensitive);
1166          $this->assertEquals($CFG->glossary_fullmatch, $entry->fullmatch);
1167          $this->assertEmpty($DB->get_records('glossary_alias', array('entryid' => $return['entryid'])));
1168          $this->assertEmpty($DB->get_records('glossary_entries_categories', array('entryid' => $return['entryid'])));
1169      }
1170  
1171      public function test_add_entry_with_aliases() {
1172          global $DB;
1173          $this->resetAfterTest(true);
1174  
1175          $course = $this->getDataGenerator()->create_course();
1176          $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id));
1177  
1178          $this->setAdminUser();
1179          $concept = 'A concept';
1180          $definition = 'A definition';
1181          $paramaliases = 'abc, def, gez';
1182          $options = array(
1183              array(
1184                  'name' => 'aliases',
1185                  'value' => $paramaliases,
1186              )
1187          );
1188          $return = mod_glossary_external::add_entry($glossary->id, $concept, $definition, FORMAT_HTML, $options);
1189          $return = external_api::clean_returnvalue(mod_glossary_external::add_entry_returns(), $return);
1190  
1191          $aliases = $DB->get_records('glossary_alias', array('entryid' => $return['entryid']));
1192          $this->assertCount(3, $aliases);
1193          foreach ($aliases as $alias) {
1194              $this->assertStringContainsString($alias->alias, $paramaliases);
1195          }
1196      }
1197  
1198      public function test_add_entry_in_categories() {
1199          global $DB;
1200          $this->resetAfterTest(true);
1201  
1202          $course = $this->getDataGenerator()->create_course();
1203          $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id));
1204          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
1205          $cat1 = $gg->create_category($glossary);
1206          $cat2 = $gg->create_category($glossary);
1207  
1208          $this->setAdminUser();
1209          $concept = 'A concept';
1210          $definition = 'A definition';
1211          $paramcategories = "$cat1->id, $cat2->id";
1212          $options = array(
1213              array(
1214                  'name' => 'categories',
1215                  'value' => $paramcategories,
1216              )
1217          );
1218          $return = mod_glossary_external::add_entry($glossary->id, $concept, $definition, FORMAT_HTML, $options);
1219          $return = external_api::clean_returnvalue(mod_glossary_external::add_entry_returns(), $return);
1220  
1221          $categories = $DB->get_records('glossary_entries_categories', array('entryid' => $return['entryid']));
1222          $this->assertCount(2, $categories);
1223          foreach ($categories as $category) {
1224              $this->assertStringContainsString($category->categoryid, $paramcategories);
1225          }
1226      }
1227  
1228      public function test_add_entry_with_attachments() {
1229          global $DB, $USER;
1230          $this->resetAfterTest(true);
1231  
1232          $course = $this->getDataGenerator()->create_course();
1233          $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id));
1234          $context = context_module::instance($glossary->cmid);
1235  
1236          $this->setAdminUser();
1237          $concept = 'A concept';
1238          $definition = 'A definition';
1239  
1240          // Draft files.
1241          $draftidinlineattach = file_get_unused_draft_itemid();
1242          $draftidattach = file_get_unused_draft_itemid();
1243          $usercontext = context_user::instance($USER->id);
1244          $filerecordinline = array(
1245              'contextid' => $usercontext->id,
1246              'component' => 'user',
1247              'filearea'  => 'draft',
1248              'itemid'    => $draftidinlineattach,
1249              'filepath'  => '/',
1250              'filename'  => 'shouldbeanimage.txt',
1251          );
1252          $fs = get_file_storage();
1253  
1254          // Create a file in a draft area for regular attachments.
1255          $filerecordattach = $filerecordinline;
1256          $attachfilename = 'attachment.txt';
1257          $filerecordattach['filename'] = $attachfilename;
1258          $filerecordattach['itemid'] = $draftidattach;
1259          $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
1260          $fs->create_file_from_string($filerecordattach, 'simple text attachment');
1261  
1262          $options = array(
1263              array(
1264                  'name' => 'inlineattachmentsid',
1265                  'value' => $draftidinlineattach,
1266              ),
1267              array(
1268                  'name' => 'attachmentsid',
1269                  'value' => $draftidattach,
1270              )
1271          );
1272          $return = mod_glossary_external::add_entry($glossary->id, $concept, $definition, FORMAT_HTML, $options);
1273          $return = external_api::clean_returnvalue(mod_glossary_external::add_entry_returns(), $return);
1274  
1275          $editorfiles = external_util::get_area_files($context->id, 'mod_glossary', 'entry', $return['entryid']);
1276          $attachmentfiles = external_util::get_area_files($context->id, 'mod_glossary', 'attachment', $return['entryid']);
1277  
1278          $this->assertCount(1, $editorfiles);
1279          $this->assertCount(1, $attachmentfiles);
1280  
1281          $this->assertEquals('shouldbeanimage.txt', $editorfiles[0]['filename']);
1282          $this->assertEquals('attachment.txt', $attachmentfiles[0]['filename']);
1283      }
1284  
1285      /**
1286       *   Test get entry including rating information.
1287       */
1288      public function test_get_entry_rating_information() {
1289          $this->resetAfterTest(true);
1290  
1291          global $DB, $CFG;
1292          require_once($CFG->dirroot . '/rating/lib.php');
1293  
1294          $this->resetAfterTest(true);
1295  
1296          $user1 = self::getDataGenerator()->create_user();
1297          $user2 = self::getDataGenerator()->create_user();
1298          $user3 = self::getDataGenerator()->create_user();
1299          $teacher = self::getDataGenerator()->create_user();
1300  
1301          // Create course to add the module.
1302          $course = self::getDataGenerator()->create_course();
1303  
1304          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1305          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
1306          $this->getDataGenerator()->enrol_user($user1->id, $course->id, $studentrole->id, 'manual');
1307          $this->getDataGenerator()->enrol_user($user2->id, $course->id, $studentrole->id, 'manual');
1308          $this->getDataGenerator()->enrol_user($user3->id, $course->id, $studentrole->id, 'manual');
1309          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual');
1310  
1311          // Create the glossary and contents.
1312          $record = new stdClass();
1313          $record->course = $course->id;
1314          $record->assessed = RATING_AGGREGATE_AVERAGE;
1315          $scale = $this->getDataGenerator()->create_scale(array('scale' => 'A,B,C,D'));
1316          $record->scale = "-$scale->id";
1317          $glossary = $this->getDataGenerator()->create_module('glossary', $record);
1318          $context = context_module::instance($glossary->cmid);
1319  
1320          $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
1321          $entry = $gg->create_content($glossary, array('approved' => 1, 'userid' => $user1->id));
1322  
1323          // Rate the entry as user2.
1324          $rating1 = new stdClass();
1325          $rating1->contextid = $context->id;
1326          $rating1->component = 'mod_glossary';
1327          $rating1->ratingarea = 'entry';
1328          $rating1->itemid = $entry->id;
1329          $rating1->rating = 1; // 1 is A.
1330          $rating1->scaleid = "-$scale->id";
1331          $rating1->userid = $user2->id;
1332          $rating1->timecreated = time();
1333          $rating1->timemodified = time();
1334          $rating1->id = $DB->insert_record('rating', $rating1);
1335  
1336          // Rate the entry as user3.
1337          $rating2 = new stdClass();
1338          $rating2->contextid = $context->id;
1339          $rating2->component = 'mod_glossary';
1340          $rating2->ratingarea = 'entry';
1341          $rating2->itemid = $entry->id;
1342          $rating2->rating = 3; // 3 is C.
1343          $rating2->scaleid = "-$scale->id";
1344          $rating2->userid = $user3->id;
1345          $rating2->timecreated = time() + 1;
1346          $rating2->timemodified = time() + 1;
1347          $rating2->id = $DB->insert_record('rating', $rating2);
1348  
1349          // As student, retrieve ratings information.
1350          $this->setUser($user1);
1351          $result = mod_glossary_external::get_entry_by_id($entry->id);
1352          $result = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $result);
1353          $this->assertCount(1, $result['ratinginfo']['ratings']);
1354          $this->assertFalse($result['ratinginfo']['ratings'][0]['canviewaggregate']);
1355          $this->assertFalse($result['ratinginfo']['canviewall']);
1356          $this->assertFalse($result['ratinginfo']['ratings'][0]['canrate']);
1357          $this->assertTrue(!isset($result['ratinginfo']['ratings'][0]['count']));
1358  
1359          // Now, as teacher, I should see the info correctly.
1360          $this->setUser($teacher);
1361          $result = mod_glossary_external::get_entry_by_id($entry->id);
1362          $result = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $result);
1363          $this->assertCount(1, $result['ratinginfo']['ratings']);
1364          $this->assertTrue($result['ratinginfo']['ratings'][0]['canviewaggregate']);
1365          $this->assertTrue($result['ratinginfo']['canviewall']);
1366          $this->assertTrue($result['ratinginfo']['ratings'][0]['canrate']);
1367          $this->assertEquals(2, $result['ratinginfo']['ratings'][0]['count']);
1368          $this->assertEquals(2, $result['ratinginfo']['ratings'][0]['aggregate']);   // 2 is B, that is the average of A + C.
1369      }
1370  }