Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  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                      $retpage['contentsize'] = strlen($cachedcontent);
 518                      // TODO: Remove this block of code once PHP 8.0 is the min version supported.
 519                      // For PHP < 8.0, if strlen() was overloaded, calculate
 520                      // the bytes using mb_strlen(..., '8bit').
 521                      if (PHP_VERSION_ID < 80000) {
 522                          if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
 523                              $retpage['contentsize'] = mb_strlen($cachedcontent, '8bit');
 524                          }
 525                      }
 526                  }
 527  
 528                  $returnedpages[] = $retpage;
 529              }
 530          }
 531  
 532          $result = array();
 533          $result['pages'] = $returnedpages;
 534          $result['warnings'] = $warnings;
 535          return $result;
 536      }
 537  
 538      /**
 539       * Describes the get_subwiki_pages return value.
 540       *
 541       * @return external_single_structure
 542       * @since Moodle 3.1
 543       */
 544      public static function get_subwiki_pages_returns() {
 545  
 546          return new external_single_structure(
 547              array(
 548                  'pages' => new external_multiple_structure(
 549                      new external_single_structure(
 550                          array(
 551                              'id' => new external_value(PARAM_INT, 'Page ID.'),
 552                              'subwikiid' => new external_value(PARAM_INT, 'Page\'s subwiki ID.'),
 553                              'title' => new external_value(PARAM_RAW, 'Page title.'),
 554                              'timecreated' => new external_value(PARAM_INT, 'Time of creation.'),
 555                              'timemodified' => new external_value(PARAM_INT, 'Time of last modification.'),
 556                              'timerendered' => new external_value(PARAM_INT, 'Time of last renderization.'),
 557                              'userid' => new external_value(PARAM_INT, 'ID of the user that last modified the page.'),
 558                              'pageviews' => new external_value(PARAM_INT, 'Number of times the page has been viewed.'),
 559                              'readonly' => new external_value(PARAM_INT, '1 if readonly, 0 otherwise.'),
 560                              'caneditpage' => new external_value(PARAM_BOOL, 'True if user can edit the page.'),
 561                              'firstpage' => new external_value(PARAM_BOOL, 'True if it\'s the first page.'),
 562                              'cachedcontent' => new external_value(PARAM_RAW, 'Page contents.', VALUE_OPTIONAL),
 563                              'contentformat' => new external_format_value('cachedcontent', VALUE_OPTIONAL),
 564                              'contentsize' => new external_value(PARAM_INT, 'Size of page contents in bytes (doesn\'t include'.
 565                                                                              ' size of attached files).', VALUE_OPTIONAL),
 566                              'tags' => new external_multiple_structure(
 567                                  \core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
 568                              ),
 569                          ), 'Pages'
 570                      )
 571                  ),
 572                  'warnings' => new external_warnings(),
 573              )
 574          );
 575      }
 576  
 577      /**
 578       * Describes the parameters for get_page_contents.
 579       *
 580       * @return external_function_parameters
 581       * @since Moodle 3.1
 582       */
 583      public static function get_page_contents_parameters() {
 584          return new external_function_parameters (
 585              array(
 586                  'pageid' => new external_value(PARAM_INT, 'Page ID.')
 587              )
 588          );
 589      }
 590  
 591      /**
 592       * Get a page contents.
 593       *
 594       * @param int $pageid The page ID.
 595       * @return array of warnings and page data.
 596       * @since Moodle 3.1
 597       */
 598      public static function get_page_contents($pageid) {
 599  
 600          $params = self::validate_parameters(self::get_page_contents_parameters(),
 601                                              array(
 602                                                  'pageid' => $pageid
 603                                              )
 604              );
 605          $warnings = array();
 606  
 607          // Get wiki page.
 608          if (!$page = wiki_get_page($params['pageid'])) {
 609              throw new moodle_exception('incorrectpageid', 'wiki');
 610          }
 611  
 612          // Get wiki instance.
 613          if (!$wiki = wiki_get_wiki_from_pageid($params['pageid'])) {
 614              throw new moodle_exception('incorrectwikiid', 'wiki');
 615          }
 616  
 617          // Permission validation.
 618          $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
 619          $context = context_module::instance($cm->id);
 620          self::validate_context($context);
 621  
 622          // Check if user can view this wiki.
 623          if (!$subwiki = wiki_get_subwiki($page->subwikiid)) {
 624              throw new moodle_exception('incorrectsubwikiid', 'wiki');
 625          }
 626          if (!wiki_user_can_view($subwiki, $wiki)) {
 627              throw new moodle_exception('cannotviewpage', 'wiki');
 628          }
 629  
 630          $returnedpage = array();
 631          $returnedpage['id'] = $page->id;
 632          $returnedpage['wikiid'] = $wiki->id;
 633          $returnedpage['subwikiid'] = $page->subwikiid;
 634          $returnedpage['groupid'] = $subwiki->groupid;
 635          $returnedpage['userid'] = $subwiki->userid;
 636          $returnedpage['title'] = $page->title;
 637          $returnedpage['tags'] = \core_tag\external\util::get_item_tags('mod_wiki', 'wiki_pages', $page->id);
 638  
 639          // Refresh page cached content if needed.
 640          if ($page->timerendered + WIKI_REFRESH_CACHE_TIME < time()) {
 641              if ($content = wiki_refresh_cachedcontent($page)) {
 642                  $page = $content['page'];
 643              }
 644          }
 645  
 646          list($returnedpage['cachedcontent'], $returnedpage['contentformat']) = external_format_text(
 647                              $page->cachedcontent, FORMAT_HTML, $context->id, 'mod_wiki', 'attachments', $subwiki->id);
 648          $returnedpage['caneditpage'] = wiki_user_can_edit($subwiki);
 649  
 650          // Get page version.
 651          $version = wiki_get_current_version($page->id);
 652          if (!empty($version)) {
 653              $returnedpage['version'] = $version->version;
 654          }
 655  
 656          $result = array();
 657          $result['page'] = $returnedpage;
 658          $result['warnings'] = $warnings;
 659          return $result;
 660      }
 661  
 662      /**
 663       * Describes the get_page_contents return value.
 664       *
 665       * @return external_single_structure
 666       * @since Moodle 3.1
 667       */
 668      public static function get_page_contents_returns() {
 669          return new external_single_structure(
 670              array(
 671                  'page' => new external_single_structure(
 672                      array(
 673                          'id' => new external_value(PARAM_INT, 'Page ID.'),
 674                          'wikiid' => new external_value(PARAM_INT, 'Page\'s wiki ID.'),
 675                          'subwikiid' => new external_value(PARAM_INT, 'Page\'s subwiki ID.'),
 676                          'groupid' => new external_value(PARAM_INT, 'Page\'s group ID.'),
 677                          'userid' => new external_value(PARAM_INT, 'Page\'s user ID.'),
 678                          'title' => new external_value(PARAM_RAW, 'Page title.'),
 679                          'cachedcontent' => new external_value(PARAM_RAW, 'Page contents.'),
 680                          'contentformat' => new external_format_value('cachedcontent', VALUE_OPTIONAL),
 681                          'caneditpage' => new external_value(PARAM_BOOL, 'True if user can edit the page.'),
 682                          'version' => new external_value(PARAM_INT, 'Latest version of the page.', VALUE_OPTIONAL),
 683                          'tags' => new external_multiple_structure(
 684                              \core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
 685                          ),
 686                      ), 'Page'
 687                  ),
 688                  'warnings' => new external_warnings()
 689              )
 690          );
 691      }
 692  
 693      /**
 694       * Describes the parameters for get_subwiki_files.
 695       *
 696       * @return external_function_parameters
 697       * @since Moodle 3.1
 698       */
 699      public static function get_subwiki_files_parameters() {
 700          return new external_function_parameters (
 701              array(
 702                  'wikiid' => new external_value(PARAM_INT, 'Wiki instance ID.'),
 703                  'groupid' => new external_value(PARAM_INT, 'Subwiki\'s group ID, -1 means current group. It will be ignored'
 704                                          . ' if the wiki doesn\'t use groups.', VALUE_DEFAULT, -1),
 705                  'userid' => new external_value(PARAM_INT, 'Subwiki\'s user ID, 0 means current user. It will be ignored'
 706                                          .' in collaborative wikis.', VALUE_DEFAULT, 0)
 707              )
 708          );
 709      }
 710  
 711      /**
 712       * Returns the list of files from a specific subwiki.
 713       *
 714       * @param int $wikiid The wiki instance ID.
 715       * @param int $groupid The group ID. If not defined, use current group.
 716       * @param int $userid The user ID. If not defined, use current user.
 717       * @return array Containing a list of warnings and a list of files.
 718       * @since Moodle 3.1
 719       * @throws moodle_exception
 720       */
 721      public static function get_subwiki_files($wikiid, $groupid = -1, $userid = 0) {
 722  
 723          $returnedfiles = array();
 724          $warnings = array();
 725  
 726          $params = self::validate_parameters(self::get_subwiki_files_parameters(),
 727                                              array(
 728                                                  'wikiid' => $wikiid,
 729                                                  'groupid' => $groupid,
 730                                                  'userid' => $userid
 731                                                  )
 732              );
 733  
 734          // Get wiki instance.
 735          if (!$wiki = wiki_get_wiki($params['wikiid'])) {
 736              throw new moodle_exception('incorrectwikiid', 'wiki');
 737          }
 738          list($course, $cm) = get_course_and_cm_from_instance($wiki, 'wiki');
 739          $context = context_module::instance($cm->id);
 740          self::validate_context($context);
 741  
 742          // Determine groupid and userid to use.
 743          list($groupid, $userid) = self::determine_group_and_user($cm, $wiki, $params['groupid'], $params['userid']);
 744  
 745          // Get subwiki and validate it.
 746          $subwiki = wiki_get_subwiki_by_group_and_user_with_validation($wiki, $groupid, $userid);
 747  
 748          // Get subwiki based on group and user.
 749          if ($subwiki === false) {
 750              throw new moodle_exception('cannotviewfiles', 'wiki');
 751          } else if ($subwiki->id != -1) {
 752              // The subwiki exists, let's get the files.
 753              $returnedfiles = external_util::get_area_files($context->id, 'mod_wiki', 'attachments', $subwiki->id);
 754          }
 755  
 756          $result = array();
 757          $result['files'] = $returnedfiles;
 758          $result['warnings'] = $warnings;
 759          return $result;
 760      }
 761  
 762      /**
 763       * Describes the get_subwiki_pages return value.
 764       *
 765       * @return external_single_structure
 766       * @since Moodle 3.1
 767       */
 768      public static function get_subwiki_files_returns() {
 769  
 770          return new external_single_structure(
 771              array(
 772                  'files' => new external_files('Files'),
 773                  'warnings' => new external_warnings(),
 774              )
 775          );
 776      }
 777  
 778      /**
 779       * Utility function for determining the groupid and userid to use.
 780       *
 781       * @param stdClass $cm The course module.
 782       * @param stdClass $wiki The wiki.
 783       * @param int $groupid Group ID. If not defined, use current group.
 784       * @param int $userid User ID. If not defined, use current user.
 785       * @return array Array containing the courseid and userid.
 786       * @since  Moodle 3.1
 787       */
 788      protected static function determine_group_and_user($cm, $wiki, $groupid = -1, $userid = 0) {
 789          global $USER;
 790  
 791          $currentgroup = groups_get_activity_group($cm);
 792          if ($currentgroup === false) {
 793              // Activity doesn't use groups.
 794              $groupid = 0;
 795          } else if ($groupid == -1) {
 796              // Use current group.
 797              $groupid = !empty($currentgroup) ? $currentgroup : 0;
 798          }
 799  
 800          // Determine user.
 801          if ($wiki->wikimode == 'collaborative') {
 802              // Collaborative wikis don't use userid in subwikis.
 803              $userid = 0;
 804          } else if (empty($userid)) {
 805              // Use current user.
 806              $userid = $USER->id;
 807          }
 808  
 809          return array($groupid, $userid);
 810      }
 811  
 812      /**
 813       * Describes the parameters for get_page_for_editing.
 814       *
 815       * @return external_function_parameters
 816       * @since Moodle 3.1
 817       */
 818      public static function get_page_for_editing_parameters() {
 819          return new external_function_parameters (
 820              array(
 821                  'pageid' => new external_value(PARAM_INT, 'Page ID to edit.'),
 822                  'section' => new external_value(PARAM_RAW, 'Section page title.', VALUE_DEFAULT, null),
 823                  'lockonly' => new external_value(PARAM_BOOL, 'Just renew lock and not return content.', VALUE_DEFAULT, false)
 824              )
 825          );
 826      }
 827  
 828      /**
 829       * Locks and retrieves info of page-section to be edited.
 830       *
 831       * @param int $pageid The page ID.
 832       * @param string $section Section page title.
 833       * @param boolean $lockonly If true: Just renew lock and not return content.
 834       * @return array of warnings and page data.
 835       * @since Moodle 3.1
 836       */
 837      public static function get_page_for_editing($pageid, $section = null, $lockonly = false) {
 838          global $USER;
 839  
 840          $params = self::validate_parameters(self::get_page_for_editing_parameters(),
 841                                              array(
 842                                                  'pageid' => $pageid,
 843                                                  'section' => $section,
 844                                                  'lockonly' => $lockonly
 845                                              )
 846              );
 847  
 848          $warnings = array();
 849  
 850          // Get wiki page.
 851          if (!$page = wiki_get_page($params['pageid'])) {
 852              throw new moodle_exception('incorrectpageid', 'wiki');
 853          }
 854  
 855          // Get wiki instance.
 856          if (!$wiki = wiki_get_wiki_from_pageid($params['pageid'])) {
 857              throw new moodle_exception('incorrectwikiid', 'wiki');
 858          }
 859  
 860          // Get subwiki instance.
 861          if (!$subwiki = wiki_get_subwiki($page->subwikiid)) {
 862              throw new moodle_exception('incorrectsubwikiid', 'wiki');
 863          }
 864  
 865          // Permission validation.
 866          $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
 867          $context = context_module::instance($cm->id);
 868          self::validate_context($context);
 869  
 870          if (!wiki_user_can_edit($subwiki)) {
 871              throw new moodle_exception('cannoteditpage', 'wiki');
 872          }
 873  
 874          if (!wiki_set_lock($params['pageid'], $USER->id, $params['section'], true)) {
 875              throw new moodle_exception('pageislocked', 'wiki');
 876          }
 877  
 878          $version = wiki_get_current_version($page->id);
 879          if (empty($version)) {
 880              throw new moodle_exception('versionerror', 'wiki');
 881          }
 882  
 883          $pagesection = array();
 884          $pagesection['version'] = $version->version;
 885  
 886          // Content requested to be returned.
 887          if (!$lockonly) {
 888              if (!is_null($params['section'])) {
 889                  $content = wiki_parser_proxy::get_section($version->content, $version->contentformat, $params['section']);
 890              } else {
 891                  $content = $version->content;
 892              }
 893  
 894              $pagesection['content'] = $content;
 895              $pagesection['contentformat'] = $version->contentformat;
 896          }
 897  
 898          $result = array();
 899          $result['pagesection'] = $pagesection;
 900          $result['warnings'] = $warnings;
 901          return $result;
 902  
 903      }
 904  
 905      /**
 906       * Describes the get_page_for_editing return value.
 907       *
 908       * @return external_single_structure
 909       * @since Moodle 3.1
 910       */
 911      public static function get_page_for_editing_returns() {
 912          return new external_single_structure(
 913              array(
 914                  'pagesection' => new external_single_structure(
 915                      array(
 916                          'content' => new external_value(PARAM_RAW, 'The contents of the page-section to be edited.',
 917                              VALUE_OPTIONAL),
 918                          'contentformat' => new external_value(PARAM_TEXT, 'Format of the original content of the page.',
 919                              VALUE_OPTIONAL),
 920                          'version' => new external_value(PARAM_INT, 'Latest version of the page.'),
 921                          'warnings' => new external_warnings()
 922                      )
 923                  )
 924              )
 925          );
 926      }
 927  
 928      /**
 929       * Describes the parameters for new_page.
 930       *
 931       * @return external_function_parameters
 932       * @since Moodle 3.1
 933       */
 934      public static function new_page_parameters() {
 935          return new external_function_parameters (
 936              array(
 937                  'title' => new external_value(PARAM_TEXT, 'New page title.'),
 938                  'content' => new external_value(PARAM_RAW, 'Page contents.'),
 939                  'contentformat' => new external_value(PARAM_TEXT, 'Page contents format. If an invalid format is provided, default
 940                      wiki format is used.', VALUE_DEFAULT, null),
 941                  'subwikiid' => new external_value(PARAM_INT, 'Page\'s subwiki ID.', VALUE_DEFAULT, null),
 942                  'wikiid' => new external_value(PARAM_INT, 'Page\'s wiki ID. Used if subwiki does not exists.', VALUE_DEFAULT,
 943                      null),
 944                  'userid' => new external_value(PARAM_INT, 'Subwiki\'s user ID. Used if subwiki does not exists.', VALUE_DEFAULT,
 945                      null),
 946                  'groupid' => new external_value(PARAM_INT, 'Subwiki\'s group ID. Used if subwiki does not exists.', VALUE_DEFAULT,
 947                      null)
 948              )
 949          );
 950      }
 951  
 952      /**
 953       * Creates a new page.
 954       *
 955       * @param string $title New page title.
 956       * @param string $content Page contents.
 957       * @param int $contentformat Page contents format. If an invalid format is provided, default wiki format is used.
 958       * @param int $subwikiid The Subwiki ID where to store the page.
 959       * @param int $wikiid Page\'s wiki ID. Used if subwiki does not exists.
 960       * @param int $userid Subwiki\'s user ID. Used if subwiki does not exists.
 961       * @param int $groupid Subwiki\'s group ID. Used if subwiki does not exists.
 962       * @return array of warnings and page data.
 963       * @since Moodle 3.1
 964       */
 965      public static function new_page($title, $content, $contentformat = null, $subwikiid = null, $wikiid = null, $userid = null,
 966          $groupid = null) {
 967          global $USER;
 968  
 969          $params = self::validate_parameters(self::new_page_parameters(),
 970                                              array(
 971                                                  'title' => $title,
 972                                                  'content' => $content,
 973                                                  'contentformat' => $contentformat,
 974                                                  'subwikiid' => $subwikiid,
 975                                                  'wikiid' => $wikiid,
 976                                                  'userid' => $userid,
 977                                                  'groupid' => $groupid
 978                                              )
 979              );
 980  
 981          $warnings = array();
 982  
 983          // Get wiki and subwiki instances.
 984          if (!empty($params['subwikiid'])) {
 985              if (!$subwiki = wiki_get_subwiki($params['subwikiid'])) {
 986                  throw new moodle_exception('incorrectsubwikiid', 'wiki');
 987              }
 988  
 989              if (!$wiki = wiki_get_wiki($subwiki->wikiid)) {
 990                  throw new moodle_exception('incorrectwikiid', 'wiki');
 991              }
 992  
 993              // Permission validation.
 994              $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
 995              $context = context_module::instance($cm->id);
 996              self::validate_context($context);
 997  
 998          } else {
 999              if (!$wiki = wiki_get_wiki($params['wikiid'])) {
1000                  throw new moodle_exception('incorrectwikiid', 'wiki');
1001              }
1002  
1003              // Permission validation.
1004              $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
1005              $context = context_module::instance($cm->id);
1006              self::validate_context($context);
1007  
1008              // Determine groupid and userid to use.
1009              list($groupid, $userid) = self::determine_group_and_user($cm, $wiki, $params['groupid'], $params['userid']);
1010  
1011              // Get subwiki and validate it.
1012              $subwiki = wiki_get_subwiki_by_group_and_user_with_validation($wiki, $groupid, $userid);
1013  
1014              if ($subwiki === false) {
1015                  // User cannot view page.
1016                  throw new moodle_exception('cannoteditpage', 'wiki');
1017              } else if ($subwiki->id < 0) {
1018                  // Subwiki needed to check edit permissions.
1019                  if (!wiki_user_can_edit($subwiki)) {
1020                      throw new moodle_exception('cannoteditpage', 'wiki');
1021                  }
1022  
1023                  // Subwiki does not exists and it can be created.
1024                  $swid = wiki_add_subwiki($wiki->id, $groupid, $userid);
1025                  if (!$subwiki = wiki_get_subwiki($swid)) {
1026                      throw new moodle_exception('incorrectsubwikiid', 'wiki');
1027                  }
1028              }
1029          }
1030  
1031          // Subwiki needed to check edit permissions.
1032          if (!wiki_user_can_edit($subwiki)) {
1033              throw new moodle_exception('cannoteditpage', 'wiki');
1034          }
1035  
1036          if ($page = wiki_get_page_by_title($subwiki->id, $params['title'])) {
1037              throw new moodle_exception('pageexists', 'wiki');
1038          }
1039  
1040          // Ignore invalid formats and use default instead.
1041          if (!$params['contentformat'] || $wiki->forceformat) {
1042              $params['contentformat'] = $wiki->defaultformat;
1043          } else {
1044              $formats = wiki_get_formats();
1045              if (!in_array($params['contentformat'], $formats)) {
1046                  $params['contentformat'] = $wiki->defaultformat;
1047              }
1048          }
1049  
1050          $newpageid = wiki_create_page($subwiki->id, $params['title'], $params['contentformat'], $USER->id);
1051  
1052          if (!$page = wiki_get_page($newpageid)) {
1053              throw new moodle_exception('incorrectpageid', 'wiki');
1054          }
1055  
1056          // Save content.
1057          $save = wiki_save_page($page, $params['content'], $USER->id);
1058  
1059          if (!$save) {
1060              throw new moodle_exception('savingerror', 'wiki');
1061          }
1062  
1063          $result = array();
1064          $result['pageid'] = $page->id;
1065          $result['warnings'] = $warnings;
1066          return $result;
1067      }
1068  
1069      /**
1070       * Describes the new_page return value.
1071       *
1072       * @return external_single_structure
1073       * @since Moodle 3.1
1074       */
1075      public static function new_page_returns() {
1076          return new external_single_structure(
1077              array(
1078                  'pageid' => new external_value(PARAM_INT, 'New page id.'),
1079                  'warnings' => new external_warnings()
1080              )
1081          );
1082      }
1083  
1084      /**
1085       * Describes the parameters for edit_page.
1086       *
1087       * @return external_function_parameters
1088       * @since Moodle 3.1
1089       */
1090      public static function edit_page_parameters() {
1091          return new external_function_parameters (
1092              array(
1093                  'pageid' => new external_value(PARAM_INT, 'Page ID.'),
1094                  'content' => new external_value(PARAM_RAW, 'Page contents.'),
1095                  'section' => new external_value(PARAM_RAW, 'Section page title.', VALUE_DEFAULT, null)
1096              )
1097          );
1098      }
1099  
1100      /**
1101       * Edit a page contents.
1102       *
1103       * @param int $pageid The page ID.
1104       * @param string $content Page contents.
1105       * @param int $section Section to be edited.
1106       * @return array of warnings and page data.
1107       * @since Moodle 3.1
1108       */
1109      public static function edit_page($pageid, $content, $section = null) {
1110          global $USER;
1111  
1112          $params = self::validate_parameters(self::edit_page_parameters(),
1113                                              array(
1114                                                  'pageid' => $pageid,
1115                                                  'content' => $content,
1116                                                  'section' => $section
1117                                              )
1118              );
1119          $warnings = array();
1120  
1121          // Get wiki page.
1122          if (!$page = wiki_get_page($params['pageid'])) {
1123              throw new moodle_exception('incorrectpageid', 'wiki');
1124          }
1125  
1126          // Get wiki instance.
1127          if (!$wiki = wiki_get_wiki_from_pageid($params['pageid'])) {
1128              throw new moodle_exception('incorrectwikiid', 'wiki');
1129          }
1130  
1131          // Get subwiki instance.
1132          if (!$subwiki = wiki_get_subwiki($page->subwikiid)) {
1133              throw new moodle_exception('incorrectsubwikiid', 'wiki');
1134          }
1135  
1136          // Permission validation.
1137          $cm = get_coursemodule_from_instance('wiki', $wiki->id, $wiki->course);
1138          $context = context_module::instance($cm->id);
1139          self::validate_context($context);
1140  
1141          if (!wiki_user_can_edit($subwiki)) {
1142              throw new moodle_exception('cannoteditpage', 'wiki');
1143          }
1144  
1145          if (wiki_is_page_section_locked($page->id, $USER->id, $params['section'])) {
1146              throw new moodle_exception('pageislocked', 'wiki');
1147          }
1148  
1149          // Save content.
1150          if (!is_null($params['section'])) {
1151              $version = wiki_get_current_version($page->id);
1152              $content = wiki_parser_proxy::get_section($version->content, $version->contentformat, $params['section'], false);
1153              if (!$content) {
1154                  throw new moodle_exception('invalidsection', 'wiki');
1155              }
1156  
1157              $save = wiki_save_section($page, $params['section'], $params['content'], $USER->id);
1158          } else {
1159              $save = wiki_save_page($page, $params['content'], $USER->id);
1160          }
1161  
1162          wiki_delete_locks($page->id, $USER->id, $params['section']);
1163  
1164          if (!$save) {
1165              throw new moodle_exception('savingerror', 'wiki');
1166          }
1167  
1168          $result = array();
1169          $result['pageid'] = $page->id;
1170          $result['warnings'] = $warnings;
1171          return $result;
1172      }
1173  
1174      /**
1175       * Describes the edit_page return value.
1176       *
1177       * @return external_single_structure
1178       * @since Moodle 3.1
1179       */
1180      public static function edit_page_returns() {
1181          return new external_single_structure(
1182              array(
1183                  'pageid' => new external_value(PARAM_INT, 'Edited page id.'),
1184                  'warnings' => new external_warnings()
1185              )
1186          );
1187      }
1188  
1189  }