Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

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