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 310 and 311] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   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  namespace mod_wiki;
  18  
  19  use externallib_advanced_testcase;
  20  use mod_wiki_external;
  21  
  22  defined('MOODLE_INTERNAL') || die();
  23  
  24  global $CFG;
  25  
  26  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  27  require_once($CFG->dirroot . '/mod/wiki/lib.php');
  28  
  29  /**
  30   * Wiki module external functions tests
  31   *
  32   * @package    mod_wiki
  33   * @category   external
  34   * @copyright  2015 Dani Palou <dani@moodle.com>
  35   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   * @since      Moodle 3.1
  37   */
  38  class externallib_test extends externallib_advanced_testcase {
  39  
  40      /**
  41       * Set up for every test
  42       */
  43      public function setUp(): void {
  44          global $DB;
  45          $this->resetAfterTest();
  46          $this->setAdminUser();
  47  
  48          // Setup test data.
  49          $this->course = $this->getDataGenerator()->create_course();
  50          $this->wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $this->course->id));
  51          $this->context = \context_module::instance($this->wiki->cmid);
  52          $this->cm = get_coursemodule_from_instance('wiki', $this->wiki->id);
  53  
  54          // Create users.
  55          $this->student = self::getDataGenerator()->create_user();
  56          $this->student2 = self::getDataGenerator()->create_user();
  57          $this->teacher = self::getDataGenerator()->create_user();
  58  
  59          // Users enrolments.
  60          $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
  61          $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
  62          $this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual');
  63          $this->getDataGenerator()->enrol_user($this->student2->id, $this->course->id, $this->studentrole->id, 'manual');
  64          $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
  65  
  66          // Create first pages.
  67          $this->firstpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_first_page($this->wiki,
  68              array('tags' => array('Cats', 'Dogs')));
  69      }
  70  
  71      /**
  72       * Create two collaborative wikis (separate/visible groups), 2 groups and a first page for each wiki and group.
  73       */
  74      private function create_collaborative_wikis_with_groups() {
  75          // Create groups and add student to one of them.
  76          if (!isset($this->group1)) {
  77              $this->group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
  78              $this->getDataGenerator()->create_group_member(array('userid' => $this->student->id, 'groupid' => $this->group1->id));
  79              $this->getDataGenerator()->create_group_member(array('userid' => $this->student2->id, 'groupid' => $this->group1->id));
  80          }
  81          if (!isset($this->group2)) {
  82              $this->group2 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
  83          }
  84  
  85          // Create two collaborative wikis.
  86          $this->wikisep = $this->getDataGenerator()->create_module('wiki',
  87                                                          array('course' => $this->course->id, 'groupmode' => SEPARATEGROUPS));
  88          $this->wikivis = $this->getDataGenerator()->create_module('wiki',
  89                                                          array('course' => $this->course->id, 'groupmode' => VISIBLEGROUPS));
  90  
  91          // Create pages.
  92          $wikigenerator = $this->getDataGenerator()->get_plugin_generator('mod_wiki');
  93          $this->fpsepg1 = $wikigenerator->create_first_page($this->wikisep, array('group' => $this->group1->id));
  94          $this->fpsepg2 = $wikigenerator->create_first_page($this->wikisep, array('group' => $this->group2->id));
  95          $this->fpsepall = $wikigenerator->create_first_page($this->wikisep, array('group' => 0)); // All participants.
  96          $this->fpvisg1 = $wikigenerator->create_first_page($this->wikivis, array('group' => $this->group1->id));
  97          $this->fpvisg2 = $wikigenerator->create_first_page($this->wikivis, array('group' => $this->group2->id));
  98          $this->fpvisall = $wikigenerator->create_first_page($this->wikivis, array('group' => 0)); // All participants.
  99      }
 100  
 101      /**
 102       * Create two individual wikis (separate/visible groups), 2 groups and a first page for each wiki and group.
 103       */
 104      private function create_individual_wikis_with_groups() {
 105          // Create groups and add student to one of them.
 106          if (!isset($this->group1)) {
 107              $this->group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
 108              $this->getDataGenerator()->create_group_member(array('userid' => $this->student->id, 'groupid' => $this->group1->id));
 109              $this->getDataGenerator()->create_group_member(array('userid' => $this->student2->id, 'groupid' => $this->group1->id));
 110          }
 111          if (!isset($this->group2)) {
 112              $this->group2 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
 113          }
 114  
 115          // Create two individual wikis.
 116          $this->wikisepind = $this->getDataGenerator()->create_module('wiki', array('course' => $this->course->id,
 117                                                          'groupmode' => SEPARATEGROUPS, 'wikimode' => 'individual'));
 118          $this->wikivisind = $this->getDataGenerator()->create_module('wiki', array('course' => $this->course->id,
 119                                                          'groupmode' => VISIBLEGROUPS, 'wikimode' => 'individual'));
 120  
 121          // Create pages. Student can only create pages in his groups.
 122          $wikigenerator = $this->getDataGenerator()->get_plugin_generator('mod_wiki');
 123          $this->setUser($this->teacher);
 124          $this->fpsepg1indt = $wikigenerator->create_first_page($this->wikisepind, array('group' => $this->group1->id));
 125          $this->fpsepg2indt = $wikigenerator->create_first_page($this->wikisepind, array('group' => $this->group2->id));
 126          $this->fpsepallindt = $wikigenerator->create_first_page($this->wikisepind, array('group' => 0)); // All participants.
 127          $this->fpvisg1indt = $wikigenerator->create_first_page($this->wikivisind, array('group' => $this->group1->id));
 128          $this->fpvisg2indt = $wikigenerator->create_first_page($this->wikivisind, array('group' => $this->group2->id));
 129          $this->fpvisallindt = $wikigenerator->create_first_page($this->wikivisind, array('group' => 0)); // All participants.
 130  
 131          $this->setUser($this->student);
 132          $this->fpsepg1indstu = $wikigenerator->create_first_page($this->wikisepind, array('group' => $this->group1->id));
 133          $this->fpvisg1indstu = $wikigenerator->create_first_page($this->wikivisind, array('group' => $this->group1->id));
 134  
 135          $this->setUser($this->student2);
 136          $this->fpsepg1indstu2 = $wikigenerator->create_first_page($this->wikisepind, array('group' => $this->group1->id));
 137          $this->fpvisg1indstu2 = $wikigenerator->create_first_page($this->wikivisind, array('group' => $this->group1->id));
 138  
 139      }
 140  
 141      /*
 142       * Test get wikis by courses
 143       */
 144      public function test_mod_wiki_get_wikis_by_courses() {
 145  
 146          // Create additional course.
 147          $course2 = self::getDataGenerator()->create_course();
 148  
 149          // Second wiki.
 150          $record = new \stdClass();
 151          $record->course = $course2->id;
 152          $wiki2 = self::getDataGenerator()->create_module('wiki', $record);
 153  
 154          // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
 155          $enrol = enrol_get_plugin('manual');
 156          $enrolinstances = enrol_get_instances($course2->id, true);
 157          foreach ($enrolinstances as $courseenrolinstance) {
 158              if ($courseenrolinstance->enrol == "manual") {
 159                  $instance2 = $courseenrolinstance;
 160                  break;
 161              }
 162          }
 163          $enrol->enrol_user($instance2, $this->student->id, $this->studentrole->id);
 164  
 165          self::setUser($this->student);
 166  
 167          $returndescription = mod_wiki_external::get_wikis_by_courses_returns();
 168  
 169          // Create what we expect to be returned when querying the two courses.
 170          // First for the student user.
 171          $expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'firstpagetitle',
 172                                  'wikimode', 'defaultformat', 'forceformat', 'editbegin', 'editend', 'section', 'visible',
 173                                  'groupmode', 'groupingid');
 174  
 175          // Add expected coursemodule and data.
 176          $wiki1 = $this->wiki;
 177          $wiki1->coursemodule = $wiki1->cmid;
 178          $wiki1->introformat = 1;
 179          $wiki1->section = 0;
 180          $wiki1->visible = true;
 181          $wiki1->groupmode = 0;
 182          $wiki1->groupingid = 0;
 183          $wiki1->introfiles = [];
 184  
 185          $wiki2->coursemodule = $wiki2->cmid;
 186          $wiki2->introformat = 1;
 187          $wiki2->section = 0;
 188          $wiki2->visible = true;
 189          $wiki2->groupmode = 0;
 190          $wiki2->groupingid = 0;
 191          $wiki2->introfiles = [];
 192  
 193          foreach ($expectedfields as $field) {
 194              $expected1[$field] = $wiki1->{$field};
 195              $expected2[$field] = $wiki2->{$field};
 196          }
 197          // Users can create pages by default.
 198          $expected1['cancreatepages'] = true;
 199          $expected2['cancreatepages'] = true;
 200  
 201          $expectedwikis = array($expected2, $expected1);
 202  
 203          // Call the external function passing course ids.
 204          $result = mod_wiki_external::get_wikis_by_courses(array($course2->id, $this->course->id));
 205          $result = \external_api::clean_returnvalue($returndescription, $result);
 206  
 207          $this->assertEquals($expectedwikis, $result['wikis']);
 208          $this->assertCount(0, $result['warnings']);
 209  
 210          // Call the external function without passing course id.
 211          $result = mod_wiki_external::get_wikis_by_courses();
 212          $result = \external_api::clean_returnvalue($returndescription, $result);
 213          $this->assertEquals($expectedwikis, $result['wikis']);
 214          $this->assertCount(0, $result['warnings']);
 215  
 216          // Unenrol user from second course and alter expected wikis.
 217          $enrol->unenrol_user($instance2, $this->student->id);
 218          array_shift($expectedwikis);
 219  
 220          // Call the external function without passing course id.
 221          $result = mod_wiki_external::get_wikis_by_courses();
 222          $result = \external_api::clean_returnvalue($returndescription, $result);
 223          $this->assertEquals($expectedwikis, $result['wikis']);
 224  
 225          // Call for the second course we unenrolled the user from, expected warning.
 226          $result = mod_wiki_external::get_wikis_by_courses(array($course2->id));
 227          $this->assertCount(1, $result['warnings']);
 228          $this->assertEquals('1', $result['warnings'][0]['warningcode']);
 229          $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
 230  
 231          // Now, try as a teacher for getting all the additional fields.
 232          self::setUser($this->teacher);
 233  
 234          $additionalfields = array('timecreated', 'timemodified');
 235  
 236          foreach ($additionalfields as $field) {
 237              $expectedwikis[0][$field] = $wiki1->{$field};
 238          }
 239  
 240          $result = mod_wiki_external::get_wikis_by_courses();
 241          $result = \external_api::clean_returnvalue($returndescription, $result);
 242          $this->assertEquals($expectedwikis, $result['wikis']);
 243  
 244          // Admin also should get all the information.
 245          self::setAdminUser();
 246  
 247          $result = mod_wiki_external::get_wikis_by_courses(array($this->course->id));
 248          $result = \external_api::clean_returnvalue($returndescription, $result);
 249          $this->assertEquals($expectedwikis, $result['wikis']);
 250  
 251          // Now, prohibit capabilities.
 252          $this->setUser($this->student);
 253          $contextcourse1 = \context_course::instance($this->course->id);
 254  
 255          // Default student role allows to view wiki and create pages.
 256          $wikis = mod_wiki_external::get_wikis_by_courses(array($this->course->id));
 257          $wikis = \external_api::clean_returnvalue(mod_wiki_external::get_wikis_by_courses_returns(), $wikis);
 258          $this->assertEquals('Test wiki 1', $wikis['wikis'][0]['intro']);
 259          $this->assertEquals(1, $wikis['wikis'][0]['cancreatepages']);
 260  
 261          // Prohibit capability = mod:wiki:viewpage on Course1 for students.
 262          assign_capability('mod/wiki:viewpage', CAP_PROHIBIT, $this->studentrole->id, $contextcourse1->id, true);
 263          accesslib_clear_all_caches_for_unit_testing();
 264          \course_modinfo::clear_instance_cache(null);
 265  
 266          $wikis = mod_wiki_external::get_wikis_by_courses(array($this->course->id));
 267          $wikis = \external_api::clean_returnvalue(mod_wiki_external::get_wikis_by_courses_returns(), $wikis);
 268          $this->assertEquals(0, count($wikis['wikis']));
 269  
 270          // Prohibit capability = mod:wiki:createpage on Course1 for students.
 271          assign_capability('mod/wiki:viewpage', CAP_ALLOW, $this->studentrole->id, $contextcourse1->id, true);
 272          assign_capability('mod/wiki:createpage', CAP_PROHIBIT, $this->studentrole->id, $contextcourse1->id);
 273          accesslib_clear_all_caches_for_unit_testing();
 274          \course_modinfo::clear_instance_cache(null);
 275  
 276          $wikis = mod_wiki_external::get_wikis_by_courses(array($this->course->id));
 277          $wikis = \external_api::clean_returnvalue(mod_wiki_external::get_wikis_by_courses_returns(), $wikis);
 278          $this->assertFalse($wikis['wikis'][0]['cancreatepages']);
 279  
 280      }
 281  
 282      /**
 283       * Test view_wiki.
 284       */
 285      public function test_view_wiki() {
 286  
 287          // Test invalid instance id.
 288          try {
 289              mod_wiki_external::view_wiki(0);
 290              $this->fail('Exception expected due to invalid mod_wiki instance id.');
 291          } catch (\moodle_exception $e) {
 292              $this->assertEquals('incorrectwikiid', $e->errorcode);
 293          }
 294  
 295          // Test not-enrolled user.
 296          $usernotenrolled = self::getDataGenerator()->create_user();
 297          $this->setUser($usernotenrolled);
 298          try {
 299              mod_wiki_external::view_wiki($this->wiki->id);
 300              $this->fail('Exception expected due to not enrolled user.');
 301          } catch (\moodle_exception $e) {
 302              $this->assertEquals('requireloginerror', $e->errorcode);
 303          }
 304  
 305          // Test user with full capabilities.
 306          $this->setUser($this->student);
 307  
 308          // Trigger and capture the event.
 309          $sink = $this->redirectEvents();
 310  
 311          $result = mod_wiki_external::view_wiki($this->wiki->id);
 312          $result = \external_api::clean_returnvalue(mod_wiki_external::view_wiki_returns(), $result);
 313  
 314          $events = $sink->get_events();
 315          $this->assertCount(1, $events);
 316          $event = array_shift($events);
 317  
 318          // Checking that the event contains the expected values.
 319          $this->assertInstanceOf('\mod_wiki\event\course_module_viewed', $event);
 320          $this->assertEquals($this->context, $event->get_context());
 321          $moodlewiki = new \moodle_url('/mod/wiki/view.php', array('id' => $this->cm->id));
 322          $this->assertEquals($moodlewiki, $event->get_url());
 323          $this->assertEventContextNotUsed($event);
 324          $this->assertNotEmpty($event->get_name());
 325  
 326          // Test user with no capabilities.
 327          // We need a explicit prohibit since this capability is allowed for students by default.
 328          assign_capability('mod/wiki:viewpage', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
 329          accesslib_clear_all_caches_for_unit_testing();
 330  
 331          try {
 332              mod_wiki_external::view_wiki($this->wiki->id);
 333              $this->fail('Exception expected due to missing capability.');
 334          } catch (\moodle_exception $e) {
 335              $this->assertEquals('cannotviewpage', $e->errorcode);
 336          }
 337  
 338      }
 339  
 340      /**
 341       * Test view_page.
 342       */
 343      public function test_view_page() {
 344  
 345          // Test invalid page id.
 346          try {
 347              mod_wiki_external::view_page(0);
 348              $this->fail('Exception expected due to invalid view_page page id.');
 349          } catch (\moodle_exception $e) {
 350              $this->assertEquals('incorrectpageid', $e->errorcode);
 351          }
 352  
 353          // Test not-enrolled user.
 354          $usernotenrolled = self::getDataGenerator()->create_user();
 355          $this->setUser($usernotenrolled);
 356          try {
 357              mod_wiki_external::view_page($this->firstpage->id);
 358              $this->fail('Exception expected due to not enrolled user.');
 359          } catch (\moodle_exception $e) {
 360              $this->assertEquals('requireloginerror', $e->errorcode);
 361          }
 362  
 363          // Test user with full capabilities.
 364          $this->setUser($this->student);
 365  
 366          // Trigger and capture the event.
 367          $sink = $this->redirectEvents();
 368  
 369          $result = mod_wiki_external::view_page($this->firstpage->id);
 370          $result = \external_api::clean_returnvalue(mod_wiki_external::view_page_returns(), $result);
 371  
 372          $events = $sink->get_events();
 373          $this->assertCount(1, $events);
 374          $event = array_shift($events);
 375  
 376          // Checking that the event contains the expected values.
 377          $this->assertInstanceOf('\mod_wiki\event\page_viewed', $event);
 378          $this->assertEquals($this->context, $event->get_context());
 379          $pageurl = new \moodle_url('/mod/wiki/view.php', array('pageid' => $this->firstpage->id));
 380          $this->assertEquals($pageurl, $event->get_url());
 381          $this->assertEventContextNotUsed($event);
 382          $this->assertNotEmpty($event->get_name());
 383  
 384          // Test user with no capabilities.
 385          // We need a explicit prohibit since this capability is allowed for students by default.
 386          assign_capability('mod/wiki:viewpage', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
 387          accesslib_clear_all_caches_for_unit_testing();
 388  
 389          try {
 390              mod_wiki_external::view_page($this->firstpage->id);
 391              $this->fail('Exception expected due to missing capability.');
 392          } catch (\moodle_exception $e) {
 393              $this->assertEquals('cannotviewpage', $e->errorcode);
 394          }
 395  
 396      }
 397  
 398      /**
 399       * Test get_subwikis.
 400       */
 401      public function test_get_subwikis() {
 402  
 403          // Test invalid wiki id.
 404          try {
 405              mod_wiki_external::get_subwikis(0);
 406              $this->fail('Exception expected due to invalid get_subwikis wiki id.');
 407          } catch (\moodle_exception $e) {
 408              $this->assertEquals('incorrectwikiid', $e->errorcode);
 409          }
 410  
 411          // Test not-enrolled user.
 412          $usernotenrolled = self::getDataGenerator()->create_user();
 413          $this->setUser($usernotenrolled);
 414          try {
 415              mod_wiki_external::get_subwikis($this->wiki->id);
 416              $this->fail('Exception expected due to not enrolled user.');
 417          } catch (\moodle_exception $e) {
 418              $this->assertEquals('requireloginerror', $e->errorcode);
 419          }
 420  
 421          // Test user with full capabilities.
 422          $this->setUser($this->student);
 423  
 424          // Create what we expect to be returned. We only test a basic case because deep testing is already done
 425          // in the tests for wiki_get_visible_subwikis.
 426          $expectedsubwikis = array();
 427          $expectedsubwiki = array(
 428                  'id' => $this->firstpage->subwikiid,
 429                  'wikiid' => $this->wiki->id,
 430                  'groupid' => 0,
 431                  'userid' => 0,
 432                  'canedit' => true
 433              );
 434          $expectedsubwikis[] = $expectedsubwiki;
 435  
 436          $result = mod_wiki_external::get_subwikis($this->wiki->id);
 437          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwikis_returns(), $result);
 438          $this->assertEquals($expectedsubwikis, $result['subwikis']);
 439          $this->assertCount(0, $result['warnings']);
 440  
 441          // Test user with no capabilities.
 442          // We need a explicit prohibit since this capability is allowed for students by default.
 443          assign_capability('mod/wiki:viewpage', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
 444          accesslib_clear_all_caches_for_unit_testing();
 445  
 446          try {
 447              mod_wiki_external::get_subwikis($this->wiki->id);
 448              $this->fail('Exception expected due to missing capability.');
 449          } catch (\moodle_exception $e) {
 450              $this->assertEquals('nopermissions', $e->errorcode);
 451          }
 452  
 453      }
 454  
 455      /**
 456       * Test get_subwiki_pages using an invalid wiki instance.
 457       */
 458      public function test_get_subwiki_pages_invalid_instance() {
 459          $this->expectException(\moodle_exception::class);
 460          mod_wiki_external::get_subwiki_pages(0);
 461      }
 462  
 463      /**
 464       * Test get_subwiki_pages using a user not enrolled in the course.
 465       */
 466      public function test_get_subwiki_pages_unenrolled_user() {
 467          // Create and use the user.
 468          $usernotenrolled = self::getDataGenerator()->create_user();
 469          $this->setUser($usernotenrolled);
 470  
 471          $this->expectException(\require_login_exception::class);
 472          mod_wiki_external::get_subwiki_pages($this->wiki->id);
 473      }
 474  
 475      /**
 476       * Test get_subwiki_pages using a hidden wiki as student.
 477       */
 478      public function test_get_subwiki_pages_hidden_wiki_as_student() {
 479          // Create a hidden wiki and try to get the list of pages.
 480          $hiddenwiki = $this->getDataGenerator()->create_module('wiki',
 481                              array('course' => $this->course->id, 'visible' => false));
 482  
 483          $this->setUser($this->student);
 484          $this->expectException(\require_login_exception::class);
 485          mod_wiki_external::get_subwiki_pages($hiddenwiki->id);
 486      }
 487  
 488      /**
 489       * Test get_subwiki_pages without the viewpage capability.
 490       */
 491      public function test_get_subwiki_pages_without_viewpage_capability() {
 492          // Prohibit capability = mod/wiki:viewpage on the course for students.
 493          $contextcourse = \context_course::instance($this->course->id);
 494          assign_capability('mod/wiki:viewpage', CAP_PROHIBIT, $this->studentrole->id, $contextcourse->id);
 495          accesslib_clear_all_caches_for_unit_testing();
 496  
 497          $this->setUser($this->student);
 498          $this->expectException(\moodle_exception::class);
 499          mod_wiki_external::get_subwiki_pages($this->wiki->id);
 500      }
 501  
 502      /**
 503       * Test get_subwiki_pages using an invalid userid.
 504       */
 505      public function test_get_subwiki_pages_invalid_userid() {
 506          // Create an individual wiki.
 507          $indwiki = $this->getDataGenerator()->create_module('wiki',
 508                                  array('course' => $this->course->id, 'wikimode' => 'individual'));
 509  
 510          $this->expectException(\moodle_exception::class);
 511          mod_wiki_external::get_subwiki_pages($indwiki->id, 0, -10);
 512      }
 513  
 514      /**
 515       * Test get_subwiki_pages using an invalid groupid.
 516       */
 517      public function test_get_subwiki_pages_invalid_groupid() {
 518          // Create testing data.
 519          $this->create_collaborative_wikis_with_groups();
 520  
 521          $this->expectException(\moodle_exception::class);
 522          mod_wiki_external::get_subwiki_pages($this->wikisep->id, -111);
 523      }
 524  
 525      /**
 526       * Test get_subwiki_pages, check that a student can't see another user pages in an individual wiki without groups.
 527       */
 528      public function test_get_subwiki_pages_individual_student_see_other_user() {
 529          // Create an individual wiki.
 530          $indwiki = $this->getDataGenerator()->create_module('wiki',
 531                                  array('course' => $this->course->id, 'wikimode' => 'individual'));
 532  
 533          $this->setUser($this->student);
 534          $this->expectException(\moodle_exception::class);
 535          mod_wiki_external::get_subwiki_pages($indwiki->id, 0, $this->teacher->id);
 536      }
 537  
 538      /**
 539       * Test get_subwiki_pages, check that a student can't get the pages from another group in
 540       * a collaborative wiki using separate groups.
 541       */
 542      public function test_get_subwiki_pages_collaborative_separate_groups_student_see_other_group() {
 543          // Create testing data.
 544          $this->create_collaborative_wikis_with_groups();
 545  
 546          $this->setUser($this->student);
 547          $this->expectException(\moodle_exception::class);
 548          mod_wiki_external::get_subwiki_pages($this->wikisep->id, $this->group2->id);
 549      }
 550  
 551      /**
 552       * Test get_subwiki_pages, check that a student can't get the pages from another group in
 553       * an individual wiki using separate groups.
 554       */
 555      public function test_get_subwiki_pages_individual_separate_groups_student_see_other_group() {
 556          // Create testing data.
 557          $this->create_individual_wikis_with_groups();
 558  
 559          $this->setUser($this->student);
 560          $this->expectException(\moodle_exception::class);
 561          mod_wiki_external::get_subwiki_pages($this->wikisepind->id, $this->group2->id, $this->teacher->id);
 562      }
 563  
 564      /**
 565       * Test get_subwiki_pages, check that a student can't get the pages from all participants in
 566       * a collaborative wiki using separate groups.
 567       */
 568      public function test_get_subwiki_pages_collaborative_separate_groups_student_see_all_participants() {
 569          // Create testing data.
 570          $this->create_collaborative_wikis_with_groups();
 571  
 572          $this->setUser($this->student);
 573          $this->expectException(\moodle_exception::class);
 574          mod_wiki_external::get_subwiki_pages($this->wikisep->id, 0);
 575      }
 576  
 577      /**
 578       * Test get_subwiki_pages, check that a student can't get the pages from all participants in
 579       * an individual wiki using separate groups.
 580       */
 581      public function test_get_subwiki_pages_individual_separate_groups_student_see_all_participants() {
 582          // Create testing data.
 583          $this->create_individual_wikis_with_groups();
 584  
 585          $this->setUser($this->student);
 586          $this->expectException(\moodle_exception::class);
 587          mod_wiki_external::get_subwiki_pages($this->wikisepind->id, 0, $this->teacher->id);
 588      }
 589  
 590      /**
 591       * Test get_subwiki_pages without groups and collaborative wiki.
 592       */
 593      public function test_get_subwiki_pages_collaborative() {
 594  
 595          // Test user with full capabilities.
 596          $this->setUser($this->student);
 597  
 598          // Set expected result: first page.
 599          $expectedpages = array();
 600          $expectedfirstpage = (array) $this->firstpage;
 601          $expectedfirstpage['caneditpage'] = true; // No groups and students have 'mod/wiki:editpage' capability.
 602          $expectedfirstpage['firstpage'] = true;
 603          $expectedfirstpage['contentformat'] = 1;
 604          $expectedfirstpage['tags'] = \core_tag\external\util::get_item_tags('mod_wiki', 'wiki_pages', $this->firstpage->id);
 605          // Cast to expected.
 606          $expectedfirstpage['tags'][0]['isstandard'] = (bool) $expectedfirstpage['tags'][0]['isstandard'];
 607          $expectedfirstpage['tags'][1]['isstandard'] = (bool) $expectedfirstpage['tags'][1]['isstandard'];
 608          $expectedpages[] = $expectedfirstpage;
 609  
 610          $result = mod_wiki_external::get_subwiki_pages($this->wiki->id);
 611          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 612          $this->assertEquals($expectedpages, $result['pages']);
 613  
 614          // Check that groupid param is ignored since the wiki isn't using groups.
 615          $result = mod_wiki_external::get_subwiki_pages($this->wiki->id, 1234);
 616          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 617          $this->assertEquals($expectedpages, $result['pages']);
 618  
 619          // Check that userid param is ignored since the wiki is collaborative.
 620          $result = mod_wiki_external::get_subwiki_pages($this->wiki->id, 1234, 1234);
 621          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 622          $this->assertEquals($expectedpages, $result['pages']);
 623  
 624          // Add a new page to the wiki and test again. We'll use a custom title so it's returned first if sorted by title.
 625          $newpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_page(
 626                                  $this->wiki, array('title' => 'AAA'));
 627  
 628          $expectednewpage = (array) $newpage;
 629          $expectednewpage['caneditpage'] = true; // No groups and students have 'mod/wiki:editpage' capability.
 630          $expectednewpage['firstpage'] = false;
 631          $expectednewpage['contentformat'] = 1;
 632          $expectednewpage['tags'] = array();
 633          array_unshift($expectedpages, $expectednewpage); // Add page to the beginning since it orders by title by default.
 634  
 635          $result = mod_wiki_external::get_subwiki_pages($this->wiki->id);
 636          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 637          $this->assertEquals($expectedpages, $result['pages']);
 638  
 639          // Now we'll order by ID. Since first page was created first it'll have a lower ID.
 640          $expectedpages = array($expectedfirstpage, $expectednewpage);
 641          $result = mod_wiki_external::get_subwiki_pages($this->wiki->id, 0, 0, array('sortby' => 'id'));
 642          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 643          $this->assertEquals($expectedpages, $result['pages']);
 644  
 645          // Check that WS doesn't return page content if includecontent is false, it returns the size instead.
 646          foreach ($expectedpages as $i => $expectedpage) {
 647              $expectedpages[$i]['contentsize'] = strlen($expectedpages[$i]['cachedcontent']);
 648              // TODO: Remove this block of code once PHP 8.0 is the min version supported.
 649              // For PHP < 8.0, if strlen() was overloaded, calculate
 650              // the bytes using mb_strlen(..., '8bit').
 651              if (PHP_VERSION_ID < 80000) {
 652                  if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
 653                      $expectedpages[$i]['contentsize'] = mb_strlen($expectedpages[$i]['cachedcontent'], '8bit');
 654                  }
 655              }
 656              unset($expectedpages[$i]['cachedcontent']);
 657              unset($expectedpages[$i]['contentformat']);
 658          }
 659          $result = mod_wiki_external::get_subwiki_pages($this->wiki->id, 0, 0, array('sortby' => 'id', 'includecontent' => 0));
 660          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 661          $this->assertEquals($expectedpages, $result['pages']);
 662      }
 663  
 664      /**
 665       * Test get_subwiki_pages without groups.
 666       */
 667      public function test_get_subwiki_pages_individual() {
 668  
 669          // Create an individual wiki to test userid param.
 670          $indwiki = $this->getDataGenerator()->create_module('wiki',
 671                                  array('course' => $this->course->id, 'wikimode' => 'individual'));
 672  
 673          // Perform a request before creating any page to check that an empty array is returned if subwiki doesn't exist.
 674          $result = mod_wiki_external::get_subwiki_pages($indwiki->id);
 675          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 676          $this->assertEquals(array(), $result['pages']);
 677  
 678          // Create first pages as student and teacher.
 679          $this->setUser($this->student);
 680          $indfirstpagestudent = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_first_page($indwiki);
 681          $this->setUser($this->teacher);
 682          $indfirstpageteacher = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_first_page($indwiki);
 683  
 684          // Check that teacher can get his pages.
 685          $expectedteacherpage = (array) $indfirstpageteacher;
 686          $expectedteacherpage['caneditpage'] = true;
 687          $expectedteacherpage['firstpage'] = true;
 688          $expectedteacherpage['contentformat'] = 1;
 689          $expectedteacherpage['tags'] = array();
 690          $expectedpages = array($expectedteacherpage);
 691  
 692          $result = mod_wiki_external::get_subwiki_pages($indwiki->id, 0, $this->teacher->id);
 693          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 694          $this->assertEquals($expectedpages, $result['pages']);
 695  
 696          // Check that the teacher can see the student's pages.
 697          $expectedstudentpage = (array) $indfirstpagestudent;
 698          $expectedstudentpage['caneditpage'] = true;
 699          $expectedstudentpage['firstpage'] = true;
 700          $expectedstudentpage['contentformat'] = 1;
 701          $expectedstudentpage['tags'] = array();
 702          $expectedpages = array($expectedstudentpage);
 703  
 704          $result = mod_wiki_external::get_subwiki_pages($indwiki->id, 0, $this->student->id);
 705          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 706          $this->assertEquals($expectedpages, $result['pages']);
 707  
 708          // Now check that student can get his pages.
 709          $this->setUser($this->student);
 710  
 711          $result = mod_wiki_external::get_subwiki_pages($indwiki->id, 0, $this->student->id);
 712          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 713          $this->assertEquals($expectedpages, $result['pages']);
 714  
 715          // Check that not using userid uses current user.
 716          $result = mod_wiki_external::get_subwiki_pages($indwiki->id, 0);
 717          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 718          $this->assertEquals($expectedpages, $result['pages']);
 719      }
 720  
 721      /**
 722       * Test get_subwiki_pages with groups and collaborative wikis.
 723       */
 724      public function test_get_subwiki_pages_separate_groups_collaborative() {
 725  
 726          // Create testing data.
 727          $this->create_collaborative_wikis_with_groups();
 728  
 729          $this->setUser($this->student);
 730  
 731          // Try to get pages from a valid group in separate groups wiki.
 732  
 733          $expectedpage = (array) $this->fpsepg1;
 734          $expectedpage['caneditpage'] = true; // User belongs to group and has 'mod/wiki:editpage' capability.
 735          $expectedpage['firstpage'] = true;
 736          $expectedpage['contentformat'] = 1;
 737          $expectedpage['tags'] = array();
 738          $expectedpages = array($expectedpage);
 739  
 740          $result = mod_wiki_external::get_subwiki_pages($this->wikisep->id, $this->group1->id);
 741          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 742          $this->assertEquals($expectedpages, $result['pages']);
 743  
 744          // Let's check that not using groupid returns the same result (current group).
 745          $result = mod_wiki_external::get_subwiki_pages($this->wikisep->id);
 746          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 747          $this->assertEquals($expectedpages, $result['pages']);
 748  
 749          // Check that teacher can view a group pages without belonging to it.
 750          $this->setUser($this->teacher);
 751          $result = mod_wiki_external::get_subwiki_pages($this->wikisep->id, $this->group1->id);
 752          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 753          $this->assertEquals($expectedpages, $result['pages']);
 754  
 755          // Check that teacher can get the pages from all participants.
 756          $expectedpage = (array) $this->fpsepall;
 757          $expectedpage['caneditpage'] = true;
 758          $expectedpage['firstpage'] = true;
 759          $expectedpage['contentformat'] = 1;
 760          $expectedpage['tags'] = array();
 761          $expectedpages = array($expectedpage);
 762  
 763          $result = mod_wiki_external::get_subwiki_pages($this->wikisep->id, 0);
 764          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 765          $this->assertEquals($expectedpages, $result['pages']);
 766      }
 767  
 768      /**
 769       * Test get_subwiki_pages with groups and collaborative wikis.
 770       */
 771      public function test_get_subwiki_pages_visible_groups_collaborative() {
 772  
 773          // Create testing data.
 774          $this->create_collaborative_wikis_with_groups();
 775  
 776          $this->setUser($this->student);
 777  
 778          // Try to get pages from a valid group in visible groups wiki.
 779  
 780          $expectedpage = (array) $this->fpvisg1;
 781          $expectedpage['caneditpage'] = true; // User belongs to group and has 'mod/wiki:editpage' capability.
 782          $expectedpage['firstpage'] = true;
 783          $expectedpage['contentformat'] = 1;
 784          $expectedpage['tags'] = array();
 785          $expectedpages = array($expectedpage);
 786  
 787          $result = mod_wiki_external::get_subwiki_pages($this->wikivis->id, $this->group1->id);
 788          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 789          $this->assertEquals($expectedpages, $result['pages']);
 790  
 791          // Check that with visible groups a student can get the pages of groups he doesn't belong to.
 792          $expectedpage = (array) $this->fpvisg2;
 793          $expectedpage['caneditpage'] = false; // User doesn't belong to group so he can't edit the page.
 794          $expectedpage['firstpage'] = true;
 795          $expectedpage['contentformat'] = 1;
 796          $expectedpage['tags'] = array();
 797          $expectedpages = array($expectedpage);
 798  
 799          $result = mod_wiki_external::get_subwiki_pages($this->wikivis->id, $this->group2->id);
 800          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 801          $this->assertEquals($expectedpages, $result['pages']);
 802  
 803          // Check that with visible groups a student can get the pages of all participants.
 804          $expectedpage = (array) $this->fpvisall;
 805          $expectedpage['caneditpage'] = false;
 806          $expectedpage['firstpage'] = true;
 807          $expectedpage['contentformat'] = 1;
 808          $expectedpage['tags'] = array();
 809          $expectedpages = array($expectedpage);
 810  
 811          $result = mod_wiki_external::get_subwiki_pages($this->wikivis->id, 0);
 812          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 813          $this->assertEquals($expectedpages, $result['pages']);
 814      }
 815  
 816      /**
 817       * Test get_subwiki_pages with groups and individual wikis.
 818       */
 819      public function test_get_subwiki_pages_separate_groups_individual() {
 820  
 821          // Create testing data.
 822          $this->create_individual_wikis_with_groups();
 823  
 824          $this->setUser($this->student);
 825  
 826          // Check that student can retrieve his pages from separate wiki.
 827          $expectedpage = (array) $this->fpsepg1indstu;
 828          $expectedpage['caneditpage'] = true;
 829          $expectedpage['firstpage'] = true;
 830          $expectedpage['contentformat'] = 1;
 831          $expectedpage['tags'] = array();
 832          $expectedpages = array($expectedpage);
 833  
 834          $result = mod_wiki_external::get_subwiki_pages($this->wikisepind->id, $this->group1->id, $this->student->id);
 835          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 836          $this->assertEquals($expectedpages, $result['pages']);
 837  
 838          // Check that not using userid uses current user.
 839          $result = mod_wiki_external::get_subwiki_pages($this->wikisepind->id, $this->group1->id);
 840          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 841          $this->assertEquals($expectedpages, $result['pages']);
 842  
 843          // Check that the teacher can see the student pages.
 844          $this->setUser($this->teacher);
 845          $result = mod_wiki_external::get_subwiki_pages($this->wikisepind->id, $this->group1->id, $this->student->id);
 846          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 847          $this->assertEquals($expectedpages, $result['pages']);
 848  
 849          // Check that a student can see pages from another user that belongs to his groups.
 850          $this->setUser($this->student);
 851          $expectedpage = (array) $this->fpsepg1indstu2;
 852          $expectedpage['caneditpage'] = false;
 853          $expectedpage['firstpage'] = true;
 854          $expectedpage['contentformat'] = 1;
 855          $expectedpage['tags'] = array();
 856          $expectedpages = array($expectedpage);
 857  
 858          $result = mod_wiki_external::get_subwiki_pages($this->wikisepind->id, $this->group1->id, $this->student2->id);
 859          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 860          $this->assertEquals($expectedpages, $result['pages']);
 861      }
 862  
 863      /**
 864       * Test get_subwiki_pages with groups and individual wikis.
 865       */
 866      public function test_get_subwiki_pages_visible_groups_individual() {
 867  
 868          // Create testing data.
 869          $this->create_individual_wikis_with_groups();
 870  
 871          $this->setUser($this->student);
 872  
 873          // Check that student can retrieve his pages from visible wiki.
 874          $expectedpage = (array) $this->fpvisg1indstu;
 875          $expectedpage['caneditpage'] = true;
 876          $expectedpage['firstpage'] = true;
 877          $expectedpage['contentformat'] = 1;
 878          $expectedpage['tags'] = array();
 879          $expectedpages = array($expectedpage);
 880  
 881          $result = mod_wiki_external::get_subwiki_pages($this->wikivisind->id, $this->group1->id, $this->student->id);
 882          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 883          $this->assertEquals($expectedpages, $result['pages']);
 884  
 885          // Check that student can see teacher pages in visible groups, even if the user doesn't belong to the group.
 886          $expectedpage = (array) $this->fpvisg2indt;
 887          $expectedpage['caneditpage'] = false;
 888          $expectedpage['firstpage'] = true;
 889          $expectedpage['contentformat'] = 1;
 890          $expectedpage['tags'] = array();
 891          $expectedpages = array($expectedpage);
 892  
 893          $result = mod_wiki_external::get_subwiki_pages($this->wikivisind->id, $this->group2->id, $this->teacher->id);
 894          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 895          $this->assertEquals($expectedpages, $result['pages']);
 896  
 897          // Check that with visible groups a student can get the pages of all participants.
 898          $expectedpage = (array) $this->fpvisallindt;
 899          $expectedpage['caneditpage'] = false;
 900          $expectedpage['firstpage'] = true;
 901          $expectedpage['contentformat'] = 1;
 902          $expectedpage['tags'] = array();
 903          $expectedpages = array($expectedpage);
 904  
 905          $result = mod_wiki_external::get_subwiki_pages($this->wikivisind->id, 0, $this->teacher->id);
 906          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_pages_returns(), $result);
 907          $this->assertEquals($expectedpages, $result['pages']);
 908      }
 909  
 910      /**
 911       * Test get_page_contents using an invalid pageid.
 912       */
 913      public function test_get_page_contents_invalid_pageid() {
 914          $this->expectException(\moodle_exception::class);
 915          mod_wiki_external::get_page_contents(0);
 916      }
 917  
 918      /**
 919       * Test get_page_contents using a user not enrolled in the course.
 920       */
 921      public function test_get_page_contents_unenrolled_user() {
 922          // Create and use the user.
 923          $usernotenrolled = self::getDataGenerator()->create_user();
 924          $this->setUser($usernotenrolled);
 925  
 926          $this->expectException(\require_login_exception::class);
 927          mod_wiki_external::get_page_contents($this->firstpage->id);
 928      }
 929  
 930      /**
 931       * Test get_page_contents using a hidden wiki as student.
 932       */
 933      public function test_get_page_contents_hidden_wiki_as_student() {
 934          // Create a hidden wiki and try to get a page contents.
 935          $hiddenwiki = $this->getDataGenerator()->create_module('wiki',
 936                              array('course' => $this->course->id, 'visible' => false));
 937          $hiddenpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_page($hiddenwiki);
 938  
 939          $this->setUser($this->student);
 940          $this->expectException(\require_login_exception::class);
 941          mod_wiki_external::get_page_contents($hiddenpage->id);
 942      }
 943  
 944      /**
 945       * Test get_page_contents without the viewpage capability.
 946       */
 947      public function test_get_page_contents_without_viewpage_capability() {
 948          // Prohibit capability = mod/wiki:viewpage on the course for students.
 949          $contextcourse = \context_course::instance($this->course->id);
 950          assign_capability('mod/wiki:viewpage', CAP_PROHIBIT, $this->studentrole->id, $contextcourse->id);
 951          accesslib_clear_all_caches_for_unit_testing();
 952  
 953          $this->setUser($this->student);
 954          $this->expectException(\moodle_exception::class);
 955          mod_wiki_external::get_page_contents($this->firstpage->id);
 956      }
 957  
 958      /**
 959       * Test get_page_contents, check that a student can't get a page from another group when
 960       * using separate groups.
 961       */
 962      public function test_get_page_contents_separate_groups_student_see_other_group() {
 963          // Create testing data.
 964          $this->create_individual_wikis_with_groups();
 965  
 966          $this->setUser($this->student);
 967          $this->expectException(\moodle_exception::class);
 968          mod_wiki_external::get_page_contents($this->fpsepg2indt->id);
 969      }
 970  
 971      /**
 972       * Test get_page_contents without groups. We won't test all the possible cases because that's already
 973       * done in the tests for get_subwiki_pages.
 974       */
 975      public function test_get_page_contents() {
 976  
 977          // Test user with full capabilities.
 978          $this->setUser($this->student);
 979  
 980          // Set expected result: first page.
 981          $expectedpage = array(
 982              'id' => $this->firstpage->id,
 983              'wikiid' => $this->wiki->id,
 984              'subwikiid' => $this->firstpage->subwikiid,
 985              'groupid' => 0, // No groups.
 986              'userid' => 0, // Collaborative.
 987              'title' => $this->firstpage->title,
 988              'cachedcontent' => $this->firstpage->cachedcontent,
 989              'contentformat' => 1,
 990              'caneditpage' => true,
 991              'version' => 1,
 992              'tags' => \core_tag\external\util::get_item_tags('mod_wiki', 'wiki_pages', $this->firstpage->id),
 993          );
 994          // Cast to expected.
 995          $expectedpage['tags'][0]['isstandard'] = (bool) $expectedpage['tags'][0]['isstandard'];
 996          $expectedpage['tags'][1]['isstandard'] = (bool) $expectedpage['tags'][1]['isstandard'];
 997  
 998          $result = mod_wiki_external::get_page_contents($this->firstpage->id);
 999          $result = \external_api::clean_returnvalue(mod_wiki_external::get_page_contents_returns(), $result);
1000          $this->assertEquals($expectedpage, $result['page']);
1001  
1002          // Add a new page to the wiki and test with it.
1003          $newpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_page($this->wiki);
1004  
1005          $expectedpage['id'] = $newpage->id;
1006          $expectedpage['title'] = $newpage->title;
1007          $expectedpage['cachedcontent'] = $newpage->cachedcontent;
1008          $expectedpage['tags'] = array();
1009  
1010          $result = mod_wiki_external::get_page_contents($newpage->id);
1011          $result = \external_api::clean_returnvalue(mod_wiki_external::get_page_contents_returns(), $result);
1012          $this->assertEquals($expectedpage, $result['page']);
1013      }
1014  
1015      /**
1016       * Test get_page_contents with groups. We won't test all the possible cases because that's already
1017       * done in the tests for get_subwiki_pages.
1018       */
1019      public function test_get_page_contents_with_groups() {
1020  
1021          // Create testing data.
1022          $this->create_individual_wikis_with_groups();
1023  
1024          // Try to get page from a valid group in separate groups wiki.
1025          $this->setUser($this->student);
1026  
1027          $expectedfpsepg1indstu = array(
1028              'id' => $this->fpsepg1indstu->id,
1029              'wikiid' => $this->wikisepind->id,
1030              'subwikiid' => $this->fpsepg1indstu->subwikiid,
1031              'groupid' => $this->group1->id,
1032              'userid' => $this->student->id,
1033              'title' => $this->fpsepg1indstu->title,
1034              'cachedcontent' => $this->fpsepg1indstu->cachedcontent,
1035              'contentformat' => 1,
1036              'caneditpage' => true,
1037              'version' => 1,
1038              'tags' => array(),
1039          );
1040  
1041          $result = mod_wiki_external::get_page_contents($this->fpsepg1indstu->id);
1042          $result = \external_api::clean_returnvalue(mod_wiki_external::get_page_contents_returns(), $result);
1043          $this->assertEquals($expectedfpsepg1indstu, $result['page']);
1044  
1045          // Check that teacher can view a group pages without belonging to it.
1046          $this->setUser($this->teacher);
1047          $result = mod_wiki_external::get_page_contents($this->fpsepg1indstu->id);
1048          $result = \external_api::clean_returnvalue(mod_wiki_external::get_page_contents_returns(), $result);
1049          $this->assertEquals($expectedfpsepg1indstu, $result['page']);
1050      }
1051  
1052      /**
1053       * Test get_subwiki_files using a wiki without files.
1054       */
1055      public function test_get_subwiki_files_no_files() {
1056          $result = mod_wiki_external::get_subwiki_files($this->wiki->id);
1057          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_files_returns(), $result);
1058          $this->assertCount(0, $result['files']);
1059          $this->assertCount(0, $result['warnings']);
1060      }
1061  
1062      /**
1063       * Test get_subwiki_files, check that a student can't get files from another group's subwiki when
1064       * using separate groups.
1065       */
1066      public function test_get_subwiki_files_separate_groups_student_see_other_group() {
1067          // Create testing data.
1068          $this->create_collaborative_wikis_with_groups();
1069  
1070          $this->setUser($this->student);
1071          $this->expectException(\moodle_exception::class);
1072          mod_wiki_external::get_subwiki_files($this->wikisep->id, $this->group2->id);
1073      }
1074  
1075      /**
1076       * Test get_subwiki_files using a collaborative wiki without groups.
1077       */
1078      public function test_get_subwiki_files_collaborative_no_groups() {
1079          $this->setUser($this->student);
1080  
1081          // Add a file as subwiki attachment.
1082          $fs = get_file_storage();
1083          $file = array('component' => 'mod_wiki', 'filearea' => 'attachments',
1084                  'contextid' => $this->context->id, 'itemid' => $this->firstpage->subwikiid,
1085                  'filename' => 'image.jpg', 'filepath' => '/', 'timemodified' => time());
1086          $content = 'IMAGE';
1087          $fs->create_file_from_string($file, $content);
1088  
1089          $expectedfile = array(
1090              'filename' => $file['filename'],
1091              'filepath' => $file['filepath'],
1092              'mimetype' => 'image/jpeg',
1093              'isexternalfile' => false,
1094              'filesize' => strlen($content),
1095              'timemodified' => $file['timemodified'],
1096              'fileurl' => \moodle_url::make_webservice_pluginfile_url($file['contextid'], $file['component'],
1097                              $file['filearea'], $file['itemid'], $file['filepath'], $file['filename']),
1098          );
1099  
1100          // Call the WS and check that it returns this file.
1101          $result = mod_wiki_external::get_subwiki_files($this->wiki->id);
1102          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_files_returns(), $result);
1103          $this->assertCount(1, $result['files']);
1104          $this->assertEquals($expectedfile, $result['files'][0]);
1105  
1106          // Now add another file to the same subwiki.
1107          $file['filename'] = 'Another image.jpg';
1108          $file['timemodified'] = time();
1109          $content = 'ANOTHER IMAGE';
1110          $fs->create_file_from_string($file, $content);
1111  
1112          $expectedfile['filename'] = $file['filename'];
1113          $expectedfile['timemodified'] = $file['timemodified'];
1114          $expectedfile['filesize'] = strlen($content);
1115          $expectedfile['fileurl'] = \moodle_url::make_webservice_pluginfile_url($file['contextid'], $file['component'],
1116                              $file['filearea'], $file['itemid'], $file['filepath'], $file['filename']);
1117  
1118          // Call the WS and check that it returns both files file.
1119          $result = mod_wiki_external::get_subwiki_files($this->wiki->id);
1120          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_files_returns(), $result);
1121          $this->assertCount(2, $result['files']);
1122          // The new file is returned first because they're returned in alphabetical order.
1123          $this->assertEquals($expectedfile, $result['files'][0]);
1124      }
1125  
1126      /**
1127       * Test get_subwiki_files using an individual wiki with visible groups.
1128       */
1129      public function test_get_subwiki_files_visible_groups_individual() {
1130          // Create testing data.
1131          $this->create_individual_wikis_with_groups();
1132  
1133          $this->setUser($this->student);
1134  
1135          // Add a file as subwiki attachment in the student group 1 subwiki.
1136          $fs = get_file_storage();
1137          $contextwiki = \context_module::instance($this->wikivisind->cmid);
1138          $file = array('component' => 'mod_wiki', 'filearea' => 'attachments',
1139                  'contextid' => $contextwiki->id, 'itemid' => $this->fpvisg1indstu->subwikiid,
1140                  'filename' => 'image.jpg', 'filepath' => '/', 'timemodified' => time());
1141          $content = 'IMAGE';
1142          $fs->create_file_from_string($file, $content);
1143  
1144          $expectedfile = array(
1145              'filename' => $file['filename'],
1146              'filepath' => $file['filepath'],
1147              'mimetype' => 'image/jpeg',
1148              'isexternalfile' => false,
1149              'filesize' => strlen($content),
1150              'timemodified' => $file['timemodified'],
1151              'fileurl' => \moodle_url::make_webservice_pluginfile_url($file['contextid'], $file['component'],
1152                              $file['filearea'], $file['itemid'], $file['filepath'], $file['filename']),
1153          );
1154  
1155          // Call the WS and check that it returns this file.
1156          $result = mod_wiki_external::get_subwiki_files($this->wikivisind->id, $this->group1->id);
1157          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_files_returns(), $result);
1158          $this->assertCount(1, $result['files']);
1159          $this->assertEquals($expectedfile, $result['files'][0]);
1160  
1161          // Now check that a teacher can see it too.
1162          $this->setUser($this->teacher);
1163          $result = mod_wiki_external::get_subwiki_files($this->wikivisind->id, $this->group1->id, $this->student->id);
1164          $result = \external_api::clean_returnvalue(mod_wiki_external::get_subwiki_files_returns(), $result);
1165          $this->assertCount(1, $result['files']);
1166          $this->assertEquals($expectedfile, $result['files'][0]);
1167      }
1168  
1169  
1170      /**
1171       * Test get_page_for_editing. We won't test all the possible cases because that's already
1172       * done in the tests for wiki_parser_proxy::get_section.
1173       */
1174      public function test_get_page_for_editing() {
1175  
1176          $this->create_individual_wikis_with_groups();
1177  
1178          // We add a <span> in the first title to verify the WS works sending HTML in section.
1179          $sectioncontent = '<h1><span>Title1</span></h1>Text inside section';
1180          $pagecontent = $sectioncontent.'<h1>Title2</h1>Text inside section';
1181          $newpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_page(
1182                                  $this->wiki, array('content' => $pagecontent));
1183  
1184          // Test user with full capabilities.
1185          $this->setUser($this->student);
1186  
1187          // Set expected result: Full Page content.
1188          $expected = array(
1189              'content' => $pagecontent,
1190              'contentformat' => 'html',
1191              'version' => '1'
1192          );
1193  
1194          $result = mod_wiki_external::get_page_for_editing($newpage->id);
1195          $result = \external_api::clean_returnvalue(mod_wiki_external::get_page_for_editing_returns(), $result);
1196          $this->assertEquals($expected, $result['pagesection']);
1197  
1198          // Set expected result: Section Page content.
1199          $expected = array(
1200              'content' => $sectioncontent,
1201              'contentformat' => 'html',
1202              'version' => '1'
1203          );
1204  
1205          $result = mod_wiki_external::get_page_for_editing($newpage->id, '<span>Title1</span>');
1206          $result = \external_api::clean_returnvalue(mod_wiki_external::get_page_for_editing_returns(), $result);
1207          $this->assertEquals($expected, $result['pagesection']);
1208      }
1209  
1210      /**
1211       * Test test_get_page_locking.
1212       */
1213      public function test_get_page_locking() {
1214  
1215          $this->create_individual_wikis_with_groups();
1216  
1217          $pagecontent = '<h1>Title1</h1>Text inside section<h1>Title2</h1>Text inside section';
1218          $newpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_page(
1219                                  $this->wiki, array('content' => $pagecontent));
1220  
1221          // Test user with full capabilities.
1222          $this->setUser($this->student);
1223  
1224          // Test Section locking.
1225          $expected = array(
1226              'version' => '1'
1227          );
1228  
1229          $result = mod_wiki_external::get_page_for_editing($newpage->id, 'Title1', true);
1230          $result = \external_api::clean_returnvalue(mod_wiki_external::get_page_for_editing_returns(), $result);
1231          $this->assertEquals($expected, $result['pagesection']);
1232  
1233          // Test the section is locked.
1234          $this->setUser($this->student2);
1235          try {
1236              mod_wiki_external::get_page_for_editing($newpage->id, 'Title1', true);
1237              $this->fail('Exception expected due to not page locking.');
1238          } catch (\moodle_exception $e) {
1239              $this->assertEquals('pageislocked', $e->errorcode);
1240          }
1241  
1242          // Test the page is locked.
1243          try {
1244              mod_wiki_external::get_page_for_editing($newpage->id, null, true);
1245              $this->fail('Exception expected due to not page locking.');
1246          } catch (\moodle_exception $e) {
1247              $this->assertEquals('pageislocked', $e->errorcode);
1248          }
1249  
1250          // Test the other section is not locked.
1251          $result = mod_wiki_external::get_page_for_editing($newpage->id, 'Title2', true);
1252          $result = \external_api::clean_returnvalue(mod_wiki_external::get_page_for_editing_returns(), $result);
1253          $this->assertEquals($expected, $result['pagesection']);
1254  
1255          // Back to the original user to test version change when editing.
1256          $this->setUser($this->student);
1257          $newsectioncontent = '<h1>Title2</h1>New test2';
1258          $result = mod_wiki_external::edit_page($newpage->id, $newsectioncontent, 'Title1');
1259  
1260          $expected = array(
1261              'version' => '2'
1262          );
1263          $result = mod_wiki_external::get_page_for_editing($newpage->id, 'Title1', true);
1264          $result = \external_api::clean_returnvalue(mod_wiki_external::get_page_for_editing_returns(), $result);
1265          $this->assertEquals($expected, $result['pagesection']);
1266      }
1267  
1268      /**
1269       * Test new_page. We won't test all the possible cases because that's already
1270       * done in the tests for wiki_create_page.
1271       */
1272      public function test_new_page() {
1273  
1274          $this->create_individual_wikis_with_groups();
1275  
1276          $sectioncontent = '<h1>Title1</h1>Text inside section';
1277          $pagecontent = $sectioncontent.'<h1>Title2</h1>Text inside section';
1278          $pagetitle = 'Page Title';
1279  
1280          // Test user with full capabilities.
1281          $this->setUser($this->student);
1282  
1283          // Test on existing subwiki.
1284          $result = mod_wiki_external::new_page($pagetitle, $pagecontent, 'html', $this->fpsepg1indstu->subwikiid);
1285          $result = \external_api::clean_returnvalue(mod_wiki_external::new_page_returns(), $result);
1286          $this->assertIsInt($result['pageid']);
1287  
1288          $version = wiki_get_current_version($result['pageid']);
1289          $this->assertEquals($pagecontent, $version->content);
1290          $this->assertEquals('html', $version->contentformat);
1291  
1292          $page = wiki_get_page($result['pageid']);
1293          $this->assertEquals($pagetitle, $page->title);
1294  
1295          // Test existing page creation.
1296          try {
1297              mod_wiki_external::new_page($pagetitle, $pagecontent, 'html', $this->fpsepg1indstu->subwikiid);
1298              $this->fail('Exception expected due to creation of an existing page.');
1299          } catch (\moodle_exception $e) {
1300              $this->assertEquals('pageexists', $e->errorcode);
1301          }
1302  
1303          // Test on non existing subwiki. Add student to group2 to have a new subwiki to be created.
1304          $this->getDataGenerator()->create_group_member(array('userid' => $this->student->id, 'groupid' => $this->group2->id));
1305          $result = mod_wiki_external::new_page($pagetitle, $pagecontent, 'html', null, $this->wikisepind->id, $this->student->id,
1306              $this->group2->id);
1307          $result = \external_api::clean_returnvalue(mod_wiki_external::new_page_returns(), $result);
1308          $this->assertIsInt($result['pageid']);
1309  
1310          $version = wiki_get_current_version($result['pageid']);
1311          $this->assertEquals($pagecontent, $version->content);
1312          $this->assertEquals('html', $version->contentformat);
1313  
1314          $page = wiki_get_page($result['pageid']);
1315          $this->assertEquals($pagetitle, $page->title);
1316  
1317          $subwiki = wiki_get_subwiki($page->subwikiid);
1318          $expected = new \stdClass();
1319          $expected->id = $subwiki->id;
1320          $expected->wikiid = $this->wikisepind->id;
1321          $expected->groupid = $this->group2->id;
1322          $expected->userid = $this->student->id;
1323          $this->assertEquals($expected, $subwiki);
1324  
1325          // Check page creation for a user not in course.
1326          $this->studentnotincourse = self::getDataGenerator()->create_user();
1327          $this->anothercourse = $this->getDataGenerator()->create_course();
1328          $this->groupnotincourse = $this->getDataGenerator()->create_group(array('courseid' => $this->anothercourse->id));
1329  
1330          try {
1331              mod_wiki_external::new_page($pagetitle, $pagecontent, 'html', null, $this->wikisepind->id,
1332                  $this->studentnotincourse->id, $this->groupnotincourse->id);
1333              $this->fail('Exception expected due to creation of an invalid subwiki creation.');
1334          } catch (\moodle_exception $e) {
1335              $this->assertEquals('cannoteditpage', $e->errorcode);
1336          }
1337  
1338      }
1339  
1340      /**
1341       * Test edit_page. We won't test all the possible cases because that's already
1342       * done in the tests for wiki_save_section / wiki_save_page.
1343       */
1344      public function test_edit_page() {
1345  
1346          $this->create_individual_wikis_with_groups();
1347  
1348          // Test user with full capabilities.
1349          $this->setUser($this->student);
1350  
1351          $newpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_page($this->wikisepind,
1352              array('group' => $this->group1->id, 'content' => 'Test'));
1353  
1354          // Test edit whole page.
1355          // We add <span> in the titles to verify the WS works sending HTML in section.
1356          $sectioncontent = '<h1><span>Title1</span></h1>Text inside section';
1357          $newpagecontent = $sectioncontent.'<h1><span>Title2</span></h1>Text inside section';
1358  
1359          $result = mod_wiki_external::edit_page($newpage->id, $newpagecontent);
1360          $result = \external_api::clean_returnvalue(mod_wiki_external::edit_page_returns(), $result);
1361          $this->assertIsInt($result['pageid']);
1362  
1363          $version = wiki_get_current_version($result['pageid']);
1364          $this->assertEquals($newpagecontent, $version->content);
1365  
1366          // Test edit section.
1367          $newsectioncontent = '<h1><span>Title2</span></h1>New test2';
1368          $section = '<span>Title2</span>';
1369  
1370          $result = mod_wiki_external::edit_page($newpage->id, $newsectioncontent, $section);
1371          $result = \external_api::clean_returnvalue(mod_wiki_external::edit_page_returns(), $result);
1372          $this->assertIsInt($result['pageid']);
1373  
1374          $expected = $sectioncontent . $newsectioncontent;
1375  
1376          $version = wiki_get_current_version($result['pageid']);
1377          $this->assertEquals($expected, $version->content);
1378  
1379          // Test locked section.
1380          $newsectioncontent = '<h1><span>Title2</span></h1>New test2';
1381          $section = '<span>Title2</span>';
1382  
1383          try {
1384              // Using user 1 to avoid other users to edit.
1385              wiki_set_lock($newpage->id, 1, $section, true);
1386              mod_wiki_external::edit_page($newpage->id, $newsectioncontent, $section);
1387              $this->fail('Exception expected due to locked section');
1388          } catch (\moodle_exception $e) {
1389              $this->assertEquals('pageislocked', $e->errorcode);
1390          }
1391  
1392          // Test edit non existing section.
1393          $newsectioncontent = '<h1>Title3</h1>New test3';
1394          $section = 'Title3';
1395  
1396          try {
1397              mod_wiki_external::edit_page($newpage->id, $newsectioncontent, $section);
1398              $this->fail('Exception expected due to non existing section in the page.');
1399          } catch (\moodle_exception $e) {
1400              $this->assertEquals('invalidsection', $e->errorcode);
1401          }
1402  
1403      }
1404  
1405  }