Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 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 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

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