Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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