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  /**
  18   * Wiki module external API.
  19   *
  20   * @package    mod_wiki
  21   * @category   external
  22   * @copyright  2015 Dani Palou <dani@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   * @since      Moodle 3.1
  25   */
  26  
  27  use core_course\external\helper_for_get_mods_by_courses;
  28  use core_external\external_api;
  29  use core_external\external_files;
  30  use core_external\external_format_value;
  31  use core_external\external_function_parameters;
  32  use core_external\external_multiple_structure;
  33  use core_external\external_single_structure;
  34  use core_external\external_value;
  35  use core_external\external_warnings;
  36  use core_external\util;
  37  
  38  defined('MOODLE_INTERNAL') || die;
  39  
  40  require_once($CFG->dirroot . '/mod/wiki/lib.php');
  41  require_once($CFG->dirroot . '/mod/wiki/locallib.php');
  42  
  43  /**
  44   * Wiki module external functions.
  45   *
  46   * @package    mod_wiki
  47   * @category   external
  48   * @copyright  2015 Dani Palou <dani@moodle.com>
  49   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  50   * @since      Moodle 3.1
  51   */
  52  class mod_wiki_external extends external_api {
  53  
  54      /**
  55       * Describes the parameters for get_wikis_by_courses.
  56       *
  57       * @return external_function_parameters
  58       * @since Moodle 3.1
  59       */
  60      public static function get_wikis_by_courses_parameters() {
  61          return new external_function_parameters (
  62              array(
  63                  'courseids' => new external_multiple_structure(
  64                      new external_value(PARAM_INT, 'Course ID'), 'Array of course ids.', VALUE_DEFAULT, array()
  65                  ),
  66              )
  67          );
  68      }
  69  
  70      /**
  71       * Returns a list of wikis in a provided list of courses,
  72       * if no list is provided all wikis that the user can view will be returned.
  73       *
  74       * @param array $courseids The courses IDs.
  75       * @return array Containing a list of warnings and a list of wikis.
  76       * @since Moodle 3.1
  77       */
  78      public static function get_wikis_by_courses($courseids = array()) {
  79  
  80          $returnedwikis = array();
  81          $warnings = array();
  82  
  83          $params = self::validate_parameters(self::get_wikis_by_courses_parameters(), array('courseids' => $courseids));
  84  
  85          $mycourses = array();
  86          if (empty($params['courseids'])) {
  87              $mycourses = enrol_get_my_courses();
  88              $params['courseids'] = array_keys($mycourses);
  89          }
  90  
  91          // Ensure there are courseids to loop through.
  92          if (!empty($params['courseids'])) {
  93  
  94              list($courses, $warnings) = util::validate_courses($params['courseids'], $mycourses);
  95  
  96              // Get the wikis in this course, this function checks users visibility permissions.
  97              // We can avoid then additional validate_context calls.
  98              $wikis = get_all_instances_in_courses('wiki', $courses);
  99  
 100              foreach ($wikis as $wiki) {
 101  
 102                  $context = context_module::instance($wiki->coursemodule);
 103  
 104                  // Entry to return.
 105                  $module = helper_for_get_mods_by_courses::standard_coursemodule_element_values(
 106                          $wiki, 'mod_wiki', 'mod/wiki:viewpage', 'mod/wiki:viewpage');
 107  
 108                  $viewablefields = [];
 109                  if (has_capability('mod/wiki:viewpage', $context)) {
 110                      $viewablefields = array('firstpagetitle', 'wikimode', 'defaultformat', 'forceformat', 'editbegin', 'editend',
 111                                              'section', 'visible', 'groupmode', 'groupingid');
 112                  }
 113  
 114                  // Check additional permissions for returning optional private settings.
 115                  if (has_capability('moodle/course:manageactivities', $context)) {
 116                      $additionalfields = array('timecreated', 'timemodified');
 117                      $viewablefields = array_merge($viewablefields, $additionalfields);
 118                  }
 119  
 120                  foreach ($viewablefields as $field) {
 121                      $module[$field] = $wiki->{$field};
 122                  }
 123  
 124                  // Check if user can add new pages.
 125                  $module['cancreatepages'] = wiki_can_create_pages($context);
 126  
 127                  $returnedwikis[] = $module;
 128              }
 129          }
 130  
 131          $result = array();
 132          $result['wikis'] = $returnedwikis;
 133          $result['warnings'] = $warnings;
 134          return $result;
 135      }
 136  
 137      /**
 138       * Describes the get_wikis_by_courses return value.
 139       *
 140       * @return external_single_structure
 141       * @since Moodle 3.1
 142       */
 143      public static function get_wikis_by_courses_returns() {
 144  
 145          return new external_single_structure(
 146              array(
 147                  'wikis' => new external_multiple_structure(
 148                      new external_single_structure(array_merge(
 149                          helper_for_get_mods_by_courses::standard_coursemodule_elements_returns(true),
 150                          [
 151                              'timecreated' => new external_value(PARAM_INT, 'Time of creation.', VALUE_OPTIONAL),
 152                              'timemodified' => new external_value(PARAM_INT, 'Time of last modification.', VALUE_OPTIONAL),
 153                              'firstpagetitle' => new external_value(PARAM_RAW, 'First page title.', VALUE_OPTIONAL),
 154                              'wikimode' => new external_value(PARAM_TEXT, 'Wiki mode (individual, collaborative).', VALUE_OPTIONAL),
 155                              'defaultformat' => new external_value(PARAM_TEXT, 'Wiki\'s default format (html, creole, nwiki).',
 156                                                                              VALUE_OPTIONAL),
 157                              'forceformat' => new external_value(PARAM_INT, '1 if format is forced, 0 otherwise.',
 158                                                                              VALUE_OPTIONAL),
 159                              'editbegin' => new external_value(PARAM_INT, 'Edit begin.', VALUE_OPTIONAL),
 160                              'editend' => new external_value(PARAM_INT, 'Edit end.', VALUE_OPTIONAL),
 161                              'cancreatepages' => new external_value(PARAM_BOOL, 'True if user can create pages.'),
 162                          ]
 163                      ), 'Wikis')
 164                  ),
 165                  'warnings' => new external_warnings(),
 166              )
 167          );
 168      }
 169  
 170      /**
 171       * Describes the parameters for view_wiki.
 172       *
 173       * @return external_function_parameters
 174       * @since Moodle 3.1
 175       */
 176      public static function view_wiki_parameters() {
 177          return new external_function_parameters (
 178              array(
 179                  'wikiid' => new external_value(PARAM_INT, 'Wiki instance ID.')
 180              )
 181          );
 182      }
 183  
 184      /**
 185       * Trigger the course module viewed event and update the module completion status.
 186       *
 187       * @param int $wikiid The wiki instance ID.
 188       * @return array of warnings and status result.
 189       * @since Moodle 3.1
 190       */
 191      public static function view_wiki($wikiid) {
 192  
 193          $params = self::validate_parameters(self::view_wiki_parameters(),
 194                                              array(
 195                                                  'wikiid' => $wikiid
 196                                              ));
 197          $warnings = array();
 198  
 199          // Get wiki instance.
 200          if (!$wiki = wiki_get_wiki($params['wikiid'])) {
 201              throw new moodle_exception('incorrectwikiid', 'wiki');
 202          }
 203  
 204          // Permission validation.
 205          list($course, $cm) = get_course_and_cm_from_instance($wiki, 'wiki');
 206          $context = context_module::instance($cm->id);
 207          self::validate_context($context);
 208  
 209          // Check if user can view this wiki.
 210          // We don't use wiki_user_can_view because it requires to have a valid subwiki for the user.
 211          if (!has_capability('mod/wiki:viewpage', $context)) {
 212              throw new moodle_exception('cannotviewpage', 'wiki');
 213          }
 214  
 215          // Trigger course_module_viewed event and completion.
 216          wiki_view($wiki, $course, $cm, $context);
 217  
 218          $result = array();
 219          $result['status'] = true;
 220          $result['warnings'] = $warnings;
 221          return $result;
 222      }
 223  
 224      /**
 225       * Describes the view_wiki return value.
 226       *
 227       * @return external_single_structure
 228       * @since Moodle 3.1
 229       */
 230      public static function view_wiki_returns() {
 231          return new external_single_structure(
 232              array(
 233                  'status' => new external_value(PARAM_BOOL, 'Status: true if success.'),
 234                  'warnings' => new external_warnings()
 235              )
 236          );
 237      }
 238  
 239      /**
 240       * Describes the parameters for view_page.
 241       *
 242       * @return external_function_parameters
 243       * @since Moodle 3.1
 244       */
 245      public static function view_page_parameters() {
 246          return new external_function_parameters (
 247              array(
 248                  'pageid' => new external_value(PARAM_INT, 'Wiki page ID.'),
 249              )
 250          );
 251      }
 252  
 253      /**
 254       * Trigger the page viewed event and update the module completion status.
 255       *
 256       * @param int $pageid The page ID.
 257       * @return array of warnings and status result.
 258       * @since Moodle 3.1
 259       * @throws moodle_exception if page is not valid.
 260       */
 261      public static function view_page($pageid) {
 262  
 263          $params = self::validate_parameters(self::view_page_parameters(),
 264                                              array(
 265                                                  'pageid' => $pageid
 266                                              ));
 267          $warnings = array();
 268  
 269          // Get wiki page.
 270          if (!$page = wiki_get_page($params['pageid'])) {
 271              throw new moodle_exception('incorrectpageid', 'wiki');
 272          }
 273  
 274          // Get wiki instance.
 275          if (!$wiki = wiki_get_wiki_from_pageid($params['pageid'])) {
 276              throw new moodle_exception('incorrectwikiid', 'wiki');
 277          }
 278  
 279          // Permission validation.
 280          list($course, $cm) = get_course_and_cm_from_instance($wiki, 'wiki');
 281          $context = context_module::instance($cm->id);
 282          self::validate_context($context);
 283  
 284          // Check if user can view this wiki.
 285          if (!$subwiki = wiki_get_subwiki($page->subwikiid)) {
 286              throw new moodle_exception('incorrectsubwikiid', 'wiki');
 287          }
 288          if (!wiki_user_can_view($subwiki, $wiki)) {
 289              throw new moodle_exception('cannotviewpage', 'wiki');
 290          }
 291  
 292          // Trigger page_viewed event and completion.
 293          wiki_page_view($wiki, $page, $course, $cm, $context);
 294  
 295          $result = array();
 296          $result['status'] = true;
 297          $result['warnings'] = $warnings;
 298          return $result;
 299      }
 300  
 301      /**
 302       * Describes the view_page return value.
 303       *
 304       * @return external_single_structure
 305       * @since Moodle 3.1
 306       */
 307      public static function view_page_returns() {
 308          return new external_single_structure(
 309              array(
 310                  'status' => new external_value(PARAM_BOOL, 'Status: true if success.'),
 311                  'warnings' => new external_warnings()
 312              )
 313          );
 314      }
 315  
 316      /**
 317       * Describes the parameters for get_subwikis.
 318       *
 319       * @return external_function_parameters
 320       * @since Moodle 3.1
 321       */
 322      public static function get_subwikis_parameters() {
 323          return new external_function_parameters (
 324              array(
 325                  'wikiid' => new external_value(PARAM_INT, 'Wiki instance ID.')
 326              )
 327          );
 328      }
 329  
 330      /**
 331       * Returns the list of subwikis the user can see in a specific wiki.
 332       *
 333       * @param int $wikiid The wiki instance ID.
 334       * @return array Containing a list of warnings and a list of subwikis.
 335       * @since Moodle 3.1
 336       */
 337      public static function get_subwikis($wikiid) {
 338          global $USER;
 339  
 340          $warnings = array();
 341  
 342          $params = self::validate_parameters(self::get_subwikis_parameters(), array('wikiid' => $wikiid));
 343  
 344          // Get wiki instance.
 345          if (!$wiki = wiki_get_wiki($params['wikiid'])) {
 346              throw new moodle_exception('incorrectwikiid', 'wiki');
 347          }
 348  
 349          // Validate context and capabilities.
 350          list($course, $cm) = get_course_and_cm_from_instance($wiki, 'wiki');
 351          $context = context_module::instance($cm->id);
 352          self::validate_context($context);
 353          require_capability('mod/wiki:viewpage', $context);
 354  
 355          $returnedsubwikis = wiki_get_visible_subwikis($wiki, $cm, $context);
 356          foreach ($returnedsubwikis as $subwiki) {
 357              $subwiki->canedit = wiki_user_can_edit($subwiki);
 358          }
 359  
 360          $result = array();
 361          $result['subwikis'] = $returnedsubwikis;
 362          $result['warnings'] = $warnings;
 363          return $result;
 364      }
 365  
 366      /**
 367       * Describes the get_subwikis return value.
 368       *
 369       * @return external_single_structure
 370       * @since Moodle 3.1
 371       */
 372      public static function get_subwikis_returns() {
 373          return new external_single_structure(
 374              array(
 375                  'subwikis' => new external_multiple_structure(
 376                      new external_single_structure(
 377                          array(
 378                              'id' => new external_value(PARAM_INT, 'Subwiki ID.'),
 379                              'wikiid' => new external_value(PARAM_INT, 'Wiki ID.'),
 380                              'groupid' => new external_value(PARAM_RAW, 'Group ID.'),
 381                              'userid' => new external_value(PARAM_INT, 'User ID.'),
 382                              'canedit' => new external_value(PARAM_BOOL, 'True if user can edit the subwiki.'),
 383                          ), 'Subwikis'
 384                      )
 385                  ),
 386                  'warnings' => new external_warnings(),
 387              )
 388          );
 389      }
 390  
 391      /**
 392       * Describes the parameters for get_subwiki_pages.
 393       *
 394       * @return external_function_parameters
 395       * @since Moodle 3.1
 396       */
 397      public static function get_subwiki_pages_parameters() {
 398          return new external_function_parameters (
 399              array(
 400                  'wikiid' => new external_value(PARAM_INT, 'Wiki instance ID.'),
 401                  'groupid' => new external_value(PARAM_INT, 'Subwiki\'s group ID, -1 means current group. It will be ignored'
 402                                          . ' if the wiki doesn\'t use groups.', VALUE_DEFAULT, -1),
 403                  'userid' => new external_value(PARAM_INT, 'Subwiki\'s user ID, 0 means current user. It will be ignored'
 404                                          .' in collaborative wikis.', VALUE_DEFAULT, 0),
 405                  'options' => new external_single_structure(
 406                              array(
 407                                      'sortby' => new external_value(PARAM_ALPHA,
 408                                              'Field to sort by (id, title, ...).', VALUE_DEFAULT, 'title'),
 409                                      'sortdirection' => new external_value(PARAM_ALPHA,
 410                                              'Sort direction: ASC or DESC.', VALUE_DEFAULT, 'ASC'),
 411                                      'includecontent' => new external_value(PARAM_INT,
 412                                              'Include each page contents or just the contents size.', VALUE_DEFAULT, 1),
 413                              ), 'Options', VALUE_DEFAULT, array()),
 414              )
 415          );
 416      }
 417  
 418      /**
 419       * Returns the list of pages from a specific subwiki.
 420       *
 421       * @param int $wikiid The wiki instance ID.
 422       * @param int $groupid The group ID. If not defined, use current group.
 423       * @param int $userid The user ID. If not defined, use current user.
 424       * @param array $options Several options like sort by, sort direction, ...
 425       * @return array Containing a list of warnings and a list of pages.
 426       * @since Moodle 3.1
 427       */
 428      public static function get_subwiki_pages($wikiid, $groupid = -1, $userid = 0, $options = array()) {
 429  
 430          $returnedpages = array();
 431          $warnings = array();
 432  
 433          $params = self::validate_parameters(self::get_subwiki_pages_parameters(),
 434                                              array(
 435                                                  'wikiid' => $wikiid,
 436                                                  'groupid' => $groupid,
 437                                                  'userid' => $userid,
 438                                                  'options' => $options
 439                                                  )
 440              );
 441  
 442          // Get wiki instance.
 443          if (!$wiki = wiki_get_wiki($params['wikiid'])) {
 444              throw new moodle_exception('incorrectwikiid', 'wiki');
 445          }
 446          list($course, $cm) = get_course_and_cm_from_instance($wiki, 'wiki');
 447          $context = context_module::instance($cm->id);
 448          self::validate_context($context);
 449  
 450          // Determine groupid and userid to use.
 451          list($groupid, $userid) = self::determine_group_and_user($cm, $wiki, $params['groupid'], $params['userid']);
 452  
 453          // Get subwiki and validate it.
 454          $subwiki = wiki_get_subwiki_by_group_and_user_with_validation($wiki, $groupid, $userid);
 455  
 456          if ($subwiki === false) {
 457              throw new moodle_exception('cannotviewpage', 'wiki');
 458          } else if ($subwiki->id != -1) {
 459  
 460              $options = $params['options'];
 461  
 462              // Set sort param.
 463              $sort = get_safe_orderby([
 464                  'id' => 'id',
 465                  'title' => 'title',
 466                  'timecreated' => 'timecreated',
 467                  'timemodified' => 'timemodified',
 468                  'pageviews' => 'pageviews',
 469                  'default' => 'title',
 470              ], $options['sortby'], $options['sortdirection'], false);
 471  
 472              $pages = wiki_get_page_list($subwiki->id, $sort);
 473              $caneditpages = wiki_user_can_edit($subwiki);
 474              $firstpage = wiki_get_first_page($subwiki->id);
 475  
 476              foreach ($pages as $page) {
 477                  $retpage = array(
 478                          'id' => $page->id,
 479                          'subwikiid' => $page->subwikiid,
 480                          'title' => \core_external\util::format_string($page->title, $context),
 481                          'timecreated' => $page->timecreated,
 482                          'timemodified' => $page->timemodified,
 483                          'timerendered' => $page->timerendered,
 484                          'userid' => $page->userid,
 485                          'pageviews' => $page->pageviews,
 486                          'readonly' => $page->readonly,
 487                          'caneditpage' => $caneditpages,
 488                          'firstpage' => $page->id == $firstpage->id,
 489                          'tags' => \core_tag\external\util::get_item_tags('mod_wiki', 'wiki_pages', $page->id),
 490                      );
 491  
 492                  // Refresh page cached content if needed.
 493                  if ($page->timerendered + WIKI_REFRESH_CACHE_TIME < time()) {
 494                      if ($content = wiki_refresh_cachedcontent($page)) {
 495                          $page = $content['page'];
 496                      }
 497                  }
 498                  list($cachedcontent, $contentformat) = \core_external\util::format_text(
 499                      $page->cachedcontent,
 500                      FORMAT_HTML,
 501                      $context,
 502                      'mod_wiki',
 503                      'attachments',
 504                      $subwiki->id
 505                  );
 506  
 507                  if ($options['includecontent']) {
 508                      // Return the page content.
 509                      $retpage['cachedcontent'] = $cachedcontent;
 510                      $retpage['contentformat'] = $contentformat;
 511                  } else {
 512                      // Return the size of the content.
 513                      $retpage['contentsize'] = \core_text::strlen($cachedcontent);
 514                  }
 515  
 516                  $returnedpages[] = $retpage;
 517              }
 518          }
 519  
 520          $result = array();
 521          $result['pages'] = $returnedpages;
 522          $result['warnings'] = $warnings;
 523          return $result;
 524      }
 525  
 526      /**
 527       * Describes the get_subwiki_pages return value.
 528       *
 529       * @return external_single_structure
 530       * @since Moodle 3.1
 531       */
 532      public static function get_subwiki_pages_returns() {
 533  
 534          return new external_single_structure(
 535              array(
 536                  'pages' => new external_multiple_structure(
 537                      new external_single_structure(
 538                          array(
 539                              'id' => new external_value(PARAM_INT, 'Page ID.'),
 540                              'subwikiid' => new external_value(PARAM_INT, 'Page\'s subwiki ID.'),
 541                              'title' => new external_value(PARAM_RAW, 'Page title.'),
 542                              'timecreated' => new external_value(PARAM_INT, 'Time of creation.'),
 543                              'timemodified' => new external_value(PARAM_INT, 'Time of last modification.'),
 544                              'timerendered' => new external_value(PARAM_INT, 'Time of last renderization.'),
 545                              'userid' => new external_value(PARAM_INT, 'ID of the user that last modified the page.'),
 546                              'pageviews' => new external_value(PARAM_INT, 'Number of times the page has been viewed.'),
 547                              'readonly' => new external_value(PARAM_INT, '1 if readonly, 0 otherwise.'),
 548                              'caneditpage' => new external_value(PARAM_BOOL, 'True if user can edit the page.'),
 549                              'firstpage' => new external_value(PARAM_BOOL, 'True if it\'s the first page.'),
 550                              'cachedcontent' => new external_value(PARAM_RAW, 'Page contents.', VALUE_OPTIONAL),
 551                              'contentformat' => new external_format_value('cachedcontent', VALUE_OPTIONAL),
 552                              'contentsize' => new external_value(PARAM_INT, 'Size of page contents in bytes (doesn\'t include'.
 553                                                                              ' size of attached files).', VALUE_OPTIONAL),
 554                              'tags' => new external_multiple_structure(
 555                                  \core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
 556                              ),
 557                          ), 'Pages'
 558                      )
 559                  ),
 560                  'warnings' => new external_warnings(),
 561              )
 562          );
 563      }
 564  
 565      /**
 566       * Describes the parameters for get_page_contents.
 567       *
 568       * @return external_function_parameters
 569       * @since Moodle 3.1
 570       */
 571      public static function get_page_contents_parameters() {
 572          return new external_function_parameters (
 573              array(
 574                  'pageid' => new external_value(PARAM_INT, 'Page ID.')
 575              )
 576          );
 577      }
 578  
 579      /**
 580       * Get a page contents.
 581       *
 582       * @param int $pageid The page ID.
 583       * @return array of warnings and page data.
 584       * @since Moodle 3.1
 585       */
 586      public static function get_page_contents($pageid) {
 587  
 588          $params = self::validate_parameters(self::get_page_contents_parameters(),
 589                                              array(
 590                                                  'pageid' => $pageid
 591                                              )
 592              );
 593          $warnings = array();
 594  
 595          // Get wiki page.
 596          if (!$page = wiki_get_page($params['pageid'])) {
 597              throw new moodle_exception('incorrectpageid', 'wiki');
 598          }
 599  
 600          // Get wiki instance.
 601          if (!$wiki = wiki_get_wiki_from_pageid($params['pageid'])) {
 602              throw new moodle_exception('incorrectwikiid', 'wiki');
 603          }
 604  
 605          // Permission validation.
 606          $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
 607          $context = context_module::instance($cm->id);
 608          self::validate_context($context);
 609  
 610          // Check if user can view this wiki.
 611          if (!$subwiki = wiki_get_subwiki($page->subwikiid)) {
 612              throw new moodle_exception('incorrectsubwikiid', 'wiki');
 613          }
 614          if (!wiki_user_can_view($subwiki, $wiki)) {
 615              throw new moodle_exception('cannotviewpage', 'wiki');
 616          }
 617  
 618          $returnedpage = array();
 619          $returnedpage['id'] = $page->id;
 620          $returnedpage['wikiid'] = $wiki->id;
 621          $returnedpage['subwikiid'] = $page->subwikiid;
 622          $returnedpage['groupid'] = $subwiki->groupid;
 623          $returnedpage['userid'] = $subwiki->userid;
 624          $returnedpage['title'] = $page->title;
 625          $returnedpage['tags'] = \core_tag\external\util::get_item_tags('mod_wiki', 'wiki_pages', $page->id);
 626  
 627          // Refresh page cached content if needed.
 628          if ($page->timerendered + WIKI_REFRESH_CACHE_TIME < time()) {
 629              if ($content = wiki_refresh_cachedcontent($page)) {
 630                  $page = $content['page'];
 631              }
 632          }
 633  
 634          list($returnedpage['cachedcontent'], $returnedpage['contentformat']) = \core_external\util::format_text(
 635              $page->cachedcontent,
 636              FORMAT_HTML,
 637              $context,
 638              'mod_wiki',
 639              'attachments',
 640              $subwiki->id
 641          );
 642          $returnedpage['caneditpage'] = wiki_user_can_edit($subwiki);
 643  
 644          // Get page version.
 645          $version = wiki_get_current_version($page->id);
 646          if (!empty($version)) {
 647              $returnedpage['version'] = $version->version;
 648          }
 649  
 650          $result = array();
 651          $result['page'] = $returnedpage;
 652          $result['warnings'] = $warnings;
 653          return $result;
 654      }
 655  
 656      /**
 657       * Describes the get_page_contents return value.
 658       *
 659       * @return external_single_structure
 660       * @since Moodle 3.1
 661       */
 662      public static function get_page_contents_returns() {
 663          return new external_single_structure(
 664              array(
 665                  'page' => new external_single_structure(
 666                      array(
 667                          'id' => new external_value(PARAM_INT, 'Page ID.'),
 668                          'wikiid' => new external_value(PARAM_INT, 'Page\'s wiki ID.'),
 669                          'subwikiid' => new external_value(PARAM_INT, 'Page\'s subwiki ID.'),
 670                          'groupid' => new external_value(PARAM_INT, 'Page\'s group ID.'),
 671                          'userid' => new external_value(PARAM_INT, 'Page\'s user ID.'),
 672                          'title' => new external_value(PARAM_RAW, 'Page title.'),
 673                          'cachedcontent' => new external_value(PARAM_RAW, 'Page contents.'),
 674                          'contentformat' => new external_format_value('cachedcontent', VALUE_OPTIONAL),
 675                          'caneditpage' => new external_value(PARAM_BOOL, 'True if user can edit the page.'),
 676                          'version' => new external_value(PARAM_INT, 'Latest version of the page.', VALUE_OPTIONAL),
 677                          'tags' => new external_multiple_structure(
 678                              \core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
 679                          ),
 680                      ), 'Page'
 681                  ),
 682                  'warnings' => new external_warnings()
 683              )
 684          );
 685      }
 686  
 687      /**
 688       * Describes the parameters for get_subwiki_files.
 689       *
 690       * @return external_function_parameters
 691       * @since Moodle 3.1
 692       */
 693      public static function get_subwiki_files_parameters() {
 694          return new external_function_parameters (
 695              array(
 696                  'wikiid' => new external_value(PARAM_INT, 'Wiki instance ID.'),
 697                  'groupid' => new external_value(PARAM_INT, 'Subwiki\'s group ID, -1 means current group. It will be ignored'
 698                                          . ' if the wiki doesn\'t use groups.', VALUE_DEFAULT, -1),
 699                  'userid' => new external_value(PARAM_INT, 'Subwiki\'s user ID, 0 means current user. It will be ignored'
 700                                          .' in collaborative wikis.', VALUE_DEFAULT, 0)
 701              )
 702          );
 703      }
 704  
 705      /**
 706       * Returns the list of files from a specific subwiki.
 707       *
 708       * @param int $wikiid The wiki instance ID.
 709       * @param int $groupid The group ID. If not defined, use current group.
 710       * @param int $userid The user ID. If not defined, use current user.
 711       * @return array Containing a list of warnings and a list of files.
 712       * @since Moodle 3.1
 713       * @throws moodle_exception
 714       */
 715      public static function get_subwiki_files($wikiid, $groupid = -1, $userid = 0) {
 716  
 717          $returnedfiles = array();
 718          $warnings = array();
 719  
 720          $params = self::validate_parameters(self::get_subwiki_files_parameters(),
 721                                              array(
 722                                                  'wikiid' => $wikiid,
 723                                                  'groupid' => $groupid,
 724                                                  'userid' => $userid
 725                                                  )
 726              );
 727  
 728          // Get wiki instance.
 729          if (!$wiki = wiki_get_wiki($params['wikiid'])) {
 730              throw new moodle_exception('incorrectwikiid', 'wiki');
 731          }
 732          list($course, $cm) = get_course_and_cm_from_instance($wiki, 'wiki');
 733          $context = context_module::instance($cm->id);
 734          self::validate_context($context);
 735  
 736          // Determine groupid and userid to use.
 737          list($groupid, $userid) = self::determine_group_and_user($cm, $wiki, $params['groupid'], $params['userid']);
 738  
 739          // Get subwiki and validate it.
 740          $subwiki = wiki_get_subwiki_by_group_and_user_with_validation($wiki, $groupid, $userid);
 741  
 742          // Get subwiki based on group and user.
 743          if ($subwiki === false) {
 744              throw new moodle_exception('cannotviewfiles', 'wiki');
 745          } else if ($subwiki->id != -1) {
 746              // The subwiki exists, let's get the files.
 747              $returnedfiles = util::get_area_files($context->id, 'mod_wiki', 'attachments', $subwiki->id);
 748          }
 749  
 750          $result = array();
 751          $result['files'] = $returnedfiles;
 752          $result['warnings'] = $warnings;
 753          return $result;
 754      }
 755  
 756      /**
 757       * Describes the get_subwiki_pages return value.
 758       *
 759       * @return external_single_structure
 760       * @since Moodle 3.1
 761       */
 762      public static function get_subwiki_files_returns() {
 763  
 764          return new external_single_structure(
 765              array(
 766                  'files' => new external_files('Files'),
 767                  'warnings' => new external_warnings(),
 768              )
 769          );
 770      }
 771  
 772      /**
 773       * Utility function for determining the groupid and userid to use.
 774       *
 775       * @param stdClass $cm The course module.
 776       * @param stdClass $wiki The wiki.
 777       * @param int $groupid Group ID. If not defined, use current group.
 778       * @param int $userid User ID. If not defined, use current user.
 779       * @return array Array containing the courseid and userid.
 780       * @since  Moodle 3.1
 781       */
 782      protected static function determine_group_and_user($cm, $wiki, $groupid = -1, $userid = 0) {
 783          global $USER;
 784  
 785          $currentgroup = groups_get_activity_group($cm);
 786          if ($currentgroup === false) {
 787              // Activity doesn't use groups.
 788              $groupid = 0;
 789          } else if ($groupid == -1) {
 790              // Use current group.
 791              $groupid = !empty($currentgroup) ? $currentgroup : 0;
 792          }
 793  
 794          // Determine user.
 795          if ($wiki->wikimode == 'collaborative') {
 796              // Collaborative wikis don't use userid in subwikis.
 797              $userid = 0;
 798          } else if (empty($userid)) {
 799              // Use current user.
 800              $userid = $USER->id;
 801          }
 802  
 803          return array($groupid, $userid);
 804      }
 805  
 806      /**
 807       * Describes the parameters for get_page_for_editing.
 808       *
 809       * @return external_function_parameters
 810       * @since Moodle 3.1
 811       */
 812      public static function get_page_for_editing_parameters() {
 813          return new external_function_parameters (
 814              array(
 815                  'pageid' => new external_value(PARAM_INT, 'Page ID to edit.'),
 816                  'section' => new external_value(PARAM_RAW, 'Section page title.', VALUE_DEFAULT, null),
 817                  'lockonly' => new external_value(PARAM_BOOL, 'Just renew lock and not return content.', VALUE_DEFAULT, false)
 818              )
 819          );
 820      }
 821  
 822      /**
 823       * Locks and retrieves info of page-section to be edited.
 824       *
 825       * @param int $pageid The page ID.
 826       * @param string $section Section page title.
 827       * @param boolean $lockonly If true: Just renew lock and not return content.
 828       * @return array of warnings and page data.
 829       * @since Moodle 3.1
 830       */
 831      public static function get_page_for_editing($pageid, $section = null, $lockonly = false) {
 832          global $USER;
 833  
 834          $params = self::validate_parameters(self::get_page_for_editing_parameters(),
 835                                              array(
 836                                                  'pageid' => $pageid,
 837                                                  'section' => $section,
 838                                                  'lockonly' => $lockonly
 839                                              )
 840              );
 841  
 842          $warnings = array();
 843  
 844          // Get wiki page.
 845          if (!$page = wiki_get_page($params['pageid'])) {
 846              throw new moodle_exception('incorrectpageid', 'wiki');
 847          }
 848  
 849          // Get wiki instance.
 850          if (!$wiki = wiki_get_wiki_from_pageid($params['pageid'])) {
 851              throw new moodle_exception('incorrectwikiid', 'wiki');
 852          }
 853  
 854          // Get subwiki instance.
 855          if (!$subwiki = wiki_get_subwiki($page->subwikiid)) {
 856              throw new moodle_exception('incorrectsubwikiid', 'wiki');
 857          }
 858  
 859          // Permission validation.
 860          $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
 861          $context = context_module::instance($cm->id);
 862          self::validate_context($context);
 863  
 864          if (!wiki_user_can_edit($subwiki)) {
 865              throw new moodle_exception('cannoteditpage', 'wiki');
 866          }
 867  
 868          if (!wiki_set_lock($params['pageid'], $USER->id, $params['section'], true)) {
 869              throw new moodle_exception('pageislocked', 'wiki');
 870          }
 871  
 872          $version = wiki_get_current_version($page->id);
 873          if (empty($version)) {
 874              throw new moodle_exception('versionerror', 'wiki');
 875          }
 876  
 877          $pagesection = array();
 878          $pagesection['version'] = $version->version;
 879  
 880          // Content requested to be returned.
 881          if (!$lockonly) {
 882              if (!is_null($params['section'])) {
 883                  $content = wiki_parser_proxy::get_section($version->content, $version->contentformat, $params['section']);
 884              } else {
 885                  $content = $version->content;
 886              }
 887  
 888              $pagesection['content'] = $content;
 889              $pagesection['contentformat'] = $version->contentformat;
 890          }
 891  
 892          $result = array();
 893          $result['pagesection'] = $pagesection;
 894          $result['warnings'] = $warnings;
 895          return $result;
 896  
 897      }
 898  
 899      /**
 900       * Describes the get_page_for_editing return value.
 901       *
 902       * @return external_single_structure
 903       * @since Moodle 3.1
 904       */
 905      public static function get_page_for_editing_returns() {
 906          return new external_single_structure(
 907              array(
 908                  'pagesection' => new external_single_structure(
 909                      array(
 910                          'content' => new external_value(PARAM_RAW, 'The contents of the page-section to be edited.',
 911                              VALUE_OPTIONAL),
 912                          'contentformat' => new external_value(PARAM_TEXT, 'Format of the original content of the page.',
 913                              VALUE_OPTIONAL),
 914                          'version' => new external_value(PARAM_INT, 'Latest version of the page.'),
 915                          'warnings' => new external_warnings()
 916                      )
 917                  )
 918              )
 919          );
 920      }
 921  
 922      /**
 923       * Describes the parameters for new_page.
 924       *
 925       * @return external_function_parameters
 926       * @since Moodle 3.1
 927       */
 928      public static function new_page_parameters() {
 929          return new external_function_parameters (
 930              array(
 931                  'title' => new external_value(PARAM_TEXT, 'New page title.'),
 932                  'content' => new external_value(PARAM_RAW, 'Page contents.'),
 933                  'contentformat' => new external_value(PARAM_TEXT, 'Page contents format. If an invalid format is provided, default
 934                      wiki format is used.', VALUE_DEFAULT, null),
 935                  'subwikiid' => new external_value(PARAM_INT, 'Page\'s subwiki ID.', VALUE_DEFAULT, null),
 936                  'wikiid' => new external_value(PARAM_INT, 'Page\'s wiki ID. Used if subwiki does not exists.', VALUE_DEFAULT,
 937                      null),
 938                  'userid' => new external_value(PARAM_INT, 'Subwiki\'s user ID. Used if subwiki does not exists.', VALUE_DEFAULT,
 939                      null),
 940                  'groupid' => new external_value(PARAM_INT, 'Subwiki\'s group ID. Used if subwiki does not exists.', VALUE_DEFAULT,
 941                      null)
 942              )
 943          );
 944      }
 945  
 946      /**
 947       * Creates a new page.
 948       *
 949       * @param string $title New page title.
 950       * @param string $content Page contents.
 951       * @param int $contentformat Page contents format. If an invalid format is provided, default wiki format is used.
 952       * @param int $subwikiid The Subwiki ID where to store the page.
 953       * @param int $wikiid Page\'s wiki ID. Used if subwiki does not exists.
 954       * @param int $userid Subwiki\'s user ID. Used if subwiki does not exists.
 955       * @param int $groupid Subwiki\'s group ID. Used if subwiki does not exists.
 956       * @return array of warnings and page data.
 957       * @since Moodle 3.1
 958       */
 959      public static function new_page($title, $content, $contentformat = null, $subwikiid = null, $wikiid = null, $userid = null,
 960          $groupid = null) {
 961          global $USER;
 962  
 963          $params = self::validate_parameters(self::new_page_parameters(),
 964                                              array(
 965                                                  'title' => $title,
 966                                                  'content' => $content,
 967                                                  'contentformat' => $contentformat,
 968                                                  'subwikiid' => $subwikiid,
 969                                                  'wikiid' => $wikiid,
 970                                                  'userid' => $userid,
 971                                                  'groupid' => $groupid
 972                                              )
 973              );
 974  
 975          $warnings = array();
 976  
 977          // Get wiki and subwiki instances.
 978          if (!empty($params['subwikiid'])) {
 979              if (!$subwiki = wiki_get_subwiki($params['subwikiid'])) {
 980                  throw new moodle_exception('incorrectsubwikiid', 'wiki');
 981              }
 982  
 983              if (!$wiki = wiki_get_wiki($subwiki->wikiid)) {
 984                  throw new moodle_exception('incorrectwikiid', 'wiki');
 985              }
 986  
 987              // Permission validation.
 988              $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
 989              $context = context_module::instance($cm->id);
 990              self::validate_context($context);
 991  
 992          } else {
 993              if (!$wiki = wiki_get_wiki($params['wikiid'])) {
 994                  throw new moodle_exception('incorrectwikiid', 'wiki');
 995              }
 996  
 997              // Permission validation.
 998              $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
 999              $context = context_module::instance($cm->id);
1000              self::validate_context($context);
1001  
1002              // Determine groupid and userid to use.
1003              list($groupid, $userid) = self::determine_group_and_user($cm, $wiki, $params['groupid'], $params['userid']);
1004  
1005              // Get subwiki and validate it.
1006              $subwiki = wiki_get_subwiki_by_group_and_user_with_validation($wiki, $groupid, $userid);
1007  
1008              if ($subwiki === false) {
1009                  // User cannot view page.
1010                  throw new moodle_exception('cannoteditpage', 'wiki');
1011              } else if ($subwiki->id < 0) {
1012                  // Subwiki needed to check edit permissions.
1013                  if (!wiki_user_can_edit($subwiki)) {
1014                      throw new moodle_exception('cannoteditpage', 'wiki');
1015                  }
1016  
1017                  // Subwiki does not exists and it can be created.
1018                  $swid = wiki_add_subwiki($wiki->id, $groupid, $userid);
1019                  if (!$subwiki = wiki_get_subwiki($swid)) {
1020                      throw new moodle_exception('incorrectsubwikiid', 'wiki');
1021                  }
1022              }
1023          }
1024  
1025          // Subwiki needed to check edit permissions.
1026          if (!wiki_user_can_edit($subwiki)) {
1027              throw new moodle_exception('cannoteditpage', 'wiki');
1028          }
1029  
1030          if ($page = wiki_get_page_by_title($subwiki->id, $params['title'])) {
1031              throw new moodle_exception('pageexists', 'wiki');
1032          }
1033  
1034          // Ignore invalid formats and use default instead.
1035          if (!$params['contentformat'] || $wiki->forceformat) {
1036              $params['contentformat'] = $wiki->defaultformat;
1037          } else {
1038              $formats = wiki_get_formats();
1039              if (!in_array($params['contentformat'], $formats)) {
1040                  $params['contentformat'] = $wiki->defaultformat;
1041              }
1042          }
1043  
1044          $newpageid = wiki_create_page($subwiki->id, $params['title'], $params['contentformat'], $USER->id);
1045  
1046          if (!$page = wiki_get_page($newpageid)) {
1047              throw new moodle_exception('incorrectpageid', 'wiki');
1048          }
1049  
1050          // Save content.
1051          $save = wiki_save_page($page, $params['content'], $USER->id);
1052  
1053          if (!$save) {
1054              throw new moodle_exception('savingerror', 'wiki');
1055          }
1056  
1057          $result = array();
1058          $result['pageid'] = $page->id;
1059          $result['warnings'] = $warnings;
1060          return $result;
1061      }
1062  
1063      /**
1064       * Describes the new_page return value.
1065       *
1066       * @return external_single_structure
1067       * @since Moodle 3.1
1068       */
1069      public static function new_page_returns() {
1070          return new external_single_structure(
1071              array(
1072                  'pageid' => new external_value(PARAM_INT, 'New page id.'),
1073                  'warnings' => new external_warnings()
1074              )
1075          );
1076      }
1077  
1078      /**
1079       * Describes the parameters for edit_page.
1080       *
1081       * @return external_function_parameters
1082       * @since Moodle 3.1
1083       */
1084      public static function edit_page_parameters() {
1085          return new external_function_parameters (
1086              array(
1087                  'pageid' => new external_value(PARAM_INT, 'Page ID.'),
1088                  'content' => new external_value(PARAM_RAW, 'Page contents.'),
1089                  'section' => new external_value(PARAM_RAW, 'Section page title.', VALUE_DEFAULT, null)
1090              )
1091          );
1092      }
1093  
1094      /**
1095       * Edit a page contents.
1096       *
1097       * @param int $pageid The page ID.
1098       * @param string $content Page contents.
1099       * @param int $section Section to be edited.
1100       * @return array of warnings and page data.
1101       * @since Moodle 3.1
1102       */
1103      public static function edit_page($pageid, $content, $section = null) {
1104          global $USER;
1105  
1106          $params = self::validate_parameters(self::edit_page_parameters(),
1107                                              array(
1108                                                  'pageid' => $pageid,
1109                                                  'content' => $content,
1110                                                  'section' => $section
1111                                              )
1112              );
1113          $warnings = array();
1114  
1115          // Get wiki page.
1116          if (!$page = wiki_get_page($params['pageid'])) {
1117              throw new moodle_exception('incorrectpageid', 'wiki');
1118          }
1119  
1120          // Get wiki instance.
1121          if (!$wiki = wiki_get_wiki_from_pageid($params['pageid'])) {
1122              throw new moodle_exception('incorrectwikiid', 'wiki');
1123          }
1124  
1125          // Get subwiki instance.
1126          if (!$subwiki = wiki_get_subwiki($page->subwikiid)) {
1127              throw new moodle_exception('incorrectsubwikiid', 'wiki');
1128          }
1129  
1130          // Permission validation.
1131          $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
1132          $context = context_module::instance($cm->id);
1133          self::validate_context($context);
1134  
1135          if (!wiki_user_can_edit($subwiki)) {
1136              throw new moodle_exception('cannoteditpage', 'wiki');
1137          }
1138  
1139          if (wiki_is_page_section_locked($page->id, $USER->id, $params['section'])) {
1140              throw new moodle_exception('pageislocked', 'wiki');
1141          }
1142  
1143          // Save content.
1144          if (!is_null($params['section'])) {
1145              $version = wiki_get_current_version($page->id);
1146              $content = wiki_parser_proxy::get_section($version->content, $version->contentformat, $params['section'], false);
1147              if (!$content) {
1148                  throw new moodle_exception('invalidsection', 'wiki');
1149              }
1150  
1151              $save = wiki_save_section($page, $params['section'], $params['content'], $USER->id);
1152          } else {
1153              $save = wiki_save_page($page, $params['content'], $USER->id);
1154          }
1155  
1156          wiki_delete_locks($page->id, $USER->id, $params['section']);
1157  
1158          if (!$save) {
1159              throw new moodle_exception('savingerror', 'wiki');
1160          }
1161  
1162          $result = array();
1163          $result['pageid'] = $page->id;
1164          $result['warnings'] = $warnings;
1165          return $result;
1166      }
1167  
1168      /**
1169       * Describes the edit_page return value.
1170       *
1171       * @return external_single_structure
1172       * @since Moodle 3.1
1173       */
1174      public static function edit_page_returns() {
1175          return new external_single_structure(
1176              array(
1177                  'pageid' => new external_value(PARAM_INT, 'Edited page id.'),
1178                  'warnings' => new external_warnings()
1179              )
1180          );
1181      }
1182  
1183  }