Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 402] [Versions 311 and 403]

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