Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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