Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

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

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

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  
  18  /**
  19   * External message API
  20   *
  21   * @package    core_message
  22   * @category   external
  23   * @copyright  2011 Jerome Mouneyrac
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  require_once("$CFG->libdir/externallib.php");
  30  require_once($CFG->dirroot . "/message/lib.php");
  31  
  32  /**
  33   * Message external functions
  34   *
  35   * @package    core_message
  36   * @category   external
  37   * @copyright  2011 Jerome Mouneyrac
  38   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   * @since Moodle 2.2
  40   */
  41  class core_message_external extends external_api {
  42      /**
  43       * Returns description of method parameters
  44       *
  45       * @return external_function_parameters
  46       * @since Moodle 3.6
  47       */
  48      public static function send_messages_to_conversation_parameters() {
  49          return new external_function_parameters(
  50              array(
  51                  'conversationid' => new external_value(PARAM_INT, 'id of the conversation'),
  52                  'messages' => new external_multiple_structure(
  53                      new external_single_structure(
  54                          array(
  55                              'text' => new external_value(PARAM_RAW, 'the text of the message'),
  56                              'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
  57                          )
  58                      )
  59                  )
  60              )
  61          );
  62      }
  63  
  64      /**
  65       * Send messages from the current USER to a conversation.
  66       *
  67       * This conversation may be any type of conversation, individual or group.
  68       *
  69       * @param int $conversationid the id of the conversation to which the messages will be sent.
  70       * @param array $messages An array of message to send.
  71       * @return array the array of messages which were sent (created).
  72       * @since Moodle 3.6
  73       */
  74      public static function send_messages_to_conversation(int $conversationid, array $messages = []) {
  75          global $CFG, $USER;
  76  
  77          // Check if messaging is enabled.
  78          if (empty($CFG->messaging)) {
  79              throw new moodle_exception('disabled', 'message');
  80          }
  81  
  82          // Ensure the current user is allowed to run this function.
  83          $context = context_system::instance();
  84          self::validate_context($context);
  85  
  86          $params = self::validate_parameters(self::send_messages_to_conversation_parameters(), [
  87              'conversationid' => $conversationid,
  88              'messages' => $messages
  89          ]);
  90  
  91          // Validate messages content before posting them.
  92          foreach ($params['messages'] as $message) {
  93              // Check message length.
  94              if (strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
  95                  throw new moodle_exception('errormessagetoolong', 'message');
  96              }
  97          }
  98  
  99          $messages = [];
 100          foreach ($params['messages'] as $message) {
 101              $createdmessage = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
 102                  $message['textformat']);
 103              $createdmessage->text = message_format_message_text((object) [
 104                  'smallmessage' => $createdmessage->text,
 105                  'fullmessageformat' => external_validate_format($message['textformat']),
 106                  'fullmessagetrust' => $createdmessage->fullmessagetrust
 107              ]);
 108              $messages[] = $createdmessage;
 109          }
 110  
 111          return $messages;
 112      }
 113  
 114      /**
 115       * Returns description of method result value.
 116       *
 117       * @return external_description
 118       * @since Moodle 3.6
 119       */
 120      public static function send_messages_to_conversation_returns() {
 121          return new external_multiple_structure(
 122              self::get_conversation_message_structure()
 123          );
 124      }
 125  
 126  
 127      /**
 128       * Returns description of method parameters
 129       *
 130       * @return external_function_parameters
 131       * @since Moodle 2.2
 132       */
 133      public static function send_instant_messages_parameters() {
 134          return new external_function_parameters(
 135              array(
 136                  'messages' => new external_multiple_structure(
 137                      new external_single_structure(
 138                          array(
 139                              'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
 140                              'text' => new external_value(PARAM_RAW, 'the text of the message'),
 141                              'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
 142                              'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the message. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL),
 143                          )
 144                      )
 145                  )
 146              )
 147          );
 148      }
 149  
 150      /**
 151       * Send private messages from the current USER to other users
 152       *
 153       * @param array $messages An array of message to send.
 154       * @return array
 155       * @since Moodle 2.2
 156       */
 157      public static function send_instant_messages($messages = array()) {
 158          global $CFG, $USER, $DB;
 159  
 160          // Check if messaging is enabled.
 161          if (empty($CFG->messaging)) {
 162              throw new moodle_exception('disabled', 'message');
 163          }
 164  
 165          // Ensure the current user is allowed to run this function
 166          $context = context_system::instance();
 167          self::validate_context($context);
 168          require_capability('moodle/site:sendmessage', $context);
 169  
 170          // Ensure the current user is allowed to delete message for everyone.
 171          $candeletemessagesforallusers = has_capability('moodle/site:deleteanymessage', $context);
 172  
 173          $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
 174  
 175          //retrieve all tousers of the messages
 176          $receivers = array();
 177          foreach($params['messages'] as $message) {
 178              $receivers[] = $message['touserid'];
 179          }
 180          list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
 181          $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
 182  
 183          $resultmessages = array();
 184          $messageids = array();
 185          foreach ($params['messages'] as $message) {
 186              $resultmsg = array(); //the infos about the success of the operation
 187  
 188              // We are going to do some checking.
 189              // Code should match /messages/index.php checks.
 190              $success = true;
 191  
 192              // Check the user exists.
 193              if (empty($tousers[$message['touserid']])) {
 194                  $success = false;
 195                  $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
 196              }
 197  
 198              // Check message length.
 199              if ($success && strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
 200                  $success = false;
 201                  $errormessage = get_string('errormessagetoolong', 'message');
 202              }
 203  
 204              // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
 205              // Check if the recipient can be messaged by the sender.
 206              if ($success && !\core_message\api::can_send_message($tousers[$message['touserid']]->id, $USER->id)) {
 207                  $success = false;
 208                  $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
 209              }
 210  
 211              // Now we can send the message (at least try).
 212              if ($success) {
 213                  // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
 214                  $success = message_post_message($USER, $tousers[$message['touserid']],
 215                          $message['text'], external_validate_format($message['textformat']));
 216              }
 217  
 218              // Build the resultmsg.
 219              if (isset($message['clientmsgid'])) {
 220                  $resultmsg['clientmsgid'] = $message['clientmsgid'];
 221              }
 222              if ($success) {
 223                  $resultmsg['msgid'] = $success;
 224                  $resultmsg['timecreated'] = time();
 225                  $resultmsg['candeletemessagesforallusers'] = $candeletemessagesforallusers;
 226                  $messageids[] = $success;
 227              } else {
 228                  // WARNINGS: for backward compatibility we return this errormessage.
 229                  //          We should have thrown exceptions as these errors prevent results to be returned.
 230                  // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
 231                  $resultmsg['msgid'] = -1;
 232                  if (!isset($errormessage)) { // Nobody has set a message error or thrown an exception, let's set it.
 233                      $errormessage = get_string('messageundeliveredbynotificationsettings', 'error');
 234                  }
 235                  $resultmsg['errormessage'] = $errormessage;
 236              }
 237  
 238              $resultmessages[] = $resultmsg;
 239          }
 240  
 241          if (!empty($messageids)) {
 242              $messagerecords = $DB->get_records_list(
 243                  'messages',
 244                  'id',
 245                  $messageids,
 246                  '',
 247                  'id, conversationid, smallmessage, fullmessageformat, fullmessagetrust');
 248              $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) {
 249                  $id = $resultmessage['msgid'];
 250                  $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null;
 251                  $resultmessage['useridfrom'] = $USER->id;
 252                  $resultmessage['text'] = message_format_message_text((object) [
 253                      'smallmessage' => $messagerecords[$id]->smallmessage,
 254                      'fullmessageformat' => external_validate_format($messagerecords[$id]->fullmessageformat),
 255                      'fullmessagetrust' => $messagerecords[$id]->fullmessagetrust
 256                  ]);
 257                  return $resultmessage;
 258              }, $resultmessages);
 259          }
 260  
 261          return $resultmessages;
 262      }
 263  
 264      /**
 265       * Returns description of method result value
 266       *
 267       * @return external_description
 268       * @since Moodle 2.2
 269       */
 270      public static function send_instant_messages_returns() {
 271          return new external_multiple_structure(
 272              new external_single_structure(
 273                  array(
 274                      'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
 275                      'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
 276                      'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL),
 277                      'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL),
 278                      'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
 279                      'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
 280                      'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
 281                      'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
 282                          'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
 283                  )
 284              )
 285          );
 286      }
 287  
 288      /**
 289       * Create contacts parameters description.
 290       *
 291       * @deprecated since Moodle 3.6
 292       * @return external_function_parameters
 293       * @since Moodle 2.5
 294       */
 295      public static function create_contacts_parameters() {
 296          return new external_function_parameters(
 297              array(
 298                  'userids' => new external_multiple_structure(
 299                      new external_value(PARAM_INT, 'User ID'),
 300                      'List of user IDs'
 301                  ),
 302                  'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
 303                      current user', VALUE_DEFAULT, 0)
 304              )
 305          );
 306      }
 307  
 308      /**
 309       * Create contacts.
 310       *
 311       * @deprecated since Moodle 3.6
 312       * @param array $userids array of user IDs.
 313       * @param int $userid The id of the user we are creating the contacts for
 314       * @return external_description
 315       * @since Moodle 2.5
 316       */
 317      public static function create_contacts($userids, $userid = 0) {
 318          global $CFG, $USER;
 319  
 320          // Check if messaging is enabled.
 321          if (empty($CFG->messaging)) {
 322              throw new moodle_exception('disabled', 'message');
 323          }
 324  
 325          if (empty($userid)) {
 326              $userid = $USER->id;
 327          }
 328  
 329          // Validate context.
 330          $context = context_system::instance();
 331          self::validate_context($context);
 332  
 333          $params = array('userids' => $userids, 'userid' => $userid);
 334          $params = self::validate_parameters(self::create_contacts_parameters(), $params);
 335  
 336          $capability = 'moodle/site:manageallmessaging';
 337          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 338              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 339          }
 340  
 341          $warnings = array();
 342          foreach ($params['userids'] as $id) {
 343              if (!message_add_contact($id, 0, $params['userid'])) {
 344                  $warnings[] = array(
 345                      'item' => 'user',
 346                      'itemid' => $id,
 347                      'warningcode' => 'contactnotcreated',
 348                      'message' => 'The contact could not be created'
 349                  );
 350              }
 351          }
 352          return $warnings;
 353      }
 354  
 355      /**
 356       * Create contacts return description.
 357       *
 358       * @deprecated since Moodle 3.6
 359       * @return external_description
 360       * @since Moodle 2.5
 361       */
 362      public static function create_contacts_returns() {
 363          return new external_warnings();
 364      }
 365  
 366      /**
 367       * Marking the method as deprecated.
 368       *
 369       * @return bool
 370       */
 371      public static function create_contacts_is_deprecated() {
 372          return true;
 373      }
 374  
 375      /**
 376       * Delete contacts parameters description.
 377       *
 378       * @return external_function_parameters
 379       * @since Moodle 2.5
 380       */
 381      public static function delete_contacts_parameters() {
 382          return new external_function_parameters(
 383              array(
 384                  'userids' => new external_multiple_structure(
 385                      new external_value(PARAM_INT, 'User ID'),
 386                      'List of user IDs'
 387                  ),
 388                  'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
 389                      current user', VALUE_DEFAULT, 0)
 390              )
 391          );
 392      }
 393  
 394      /**
 395       * Delete contacts.
 396       *
 397       * @param array $userids array of user IDs.
 398       * @param int $userid The id of the user we are deleting the contacts for
 399       * @return null
 400       * @since Moodle 2.5
 401       */
 402      public static function delete_contacts($userids, $userid = 0) {
 403          global $CFG, $USER;
 404  
 405          // Check if messaging is enabled.
 406          if (empty($CFG->messaging)) {
 407              throw new moodle_exception('disabled', 'message');
 408          }
 409  
 410          if (empty($userid)) {
 411              $userid = $USER->id;
 412          }
 413  
 414          // Validate context.
 415          $context = context_system::instance();
 416          self::validate_context($context);
 417  
 418          $params = array('userids' => $userids, 'userid' => $userid);
 419          $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
 420  
 421          $capability = 'moodle/site:manageallmessaging';
 422          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 423              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 424          }
 425  
 426          foreach ($params['userids'] as $id) {
 427              \core_message\api::remove_contact($params['userid'], $id);
 428          }
 429  
 430          return null;
 431      }
 432  
 433      /**
 434       * Delete contacts return description.
 435       *
 436       * @return external_description
 437       * @since Moodle 2.5
 438       */
 439      public static function delete_contacts_returns() {
 440          return null;
 441      }
 442  
 443      /**
 444       * Mute conversations parameters description.
 445       *
 446       * @return external_function_parameters
 447       */
 448      public static function mute_conversations_parameters() {
 449          return new external_function_parameters(
 450              [
 451                  'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
 452                  'conversationids' => new external_multiple_structure(
 453                      new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
 454                  ),
 455              ]
 456          );
 457      }
 458  
 459      /**
 460       * Mutes conversations.
 461       *
 462       * @param int $userid The id of the user who is blocking
 463       * @param array $conversationids The list of conversations being muted
 464       * @return external_description
 465       */
 466      public static function mute_conversations(int $userid, array $conversationids) {
 467          global $CFG, $USER;
 468  
 469          // Check if messaging is enabled.
 470          if (empty($CFG->messaging)) {
 471              throw new moodle_exception('disabled', 'message');
 472          }
 473  
 474          // Validate context.
 475          $context = context_system::instance();
 476          self::validate_context($context);
 477  
 478          $params = ['userid' => $userid, 'conversationids' => $conversationids];
 479          $params = self::validate_parameters(self::mute_conversations_parameters(), $params);
 480  
 481          $capability = 'moodle/site:manageallmessaging';
 482          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 483              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 484          }
 485  
 486          foreach ($params['conversationids'] as $conversationid) {
 487              if (!\core_message\api::is_conversation_muted($params['userid'], $conversationid)) {
 488                  \core_message\api::mute_conversation($params['userid'], $conversationid);
 489              }
 490          }
 491  
 492          return [];
 493      }
 494  
 495      /**
 496       * Mute conversations return description.
 497       *
 498       * @return external_description
 499       */
 500      public static function mute_conversations_returns() {
 501          return new external_warnings();
 502      }
 503  
 504      /**
 505       * Unmute conversations parameters description.
 506       *
 507       * @return external_function_parameters
 508       */
 509      public static function unmute_conversations_parameters() {
 510          return new external_function_parameters(
 511              [
 512                  'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
 513                  'conversationids' => new external_multiple_structure(
 514                      new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
 515                  ),
 516              ]
 517          );
 518      }
 519  
 520      /**
 521       * Unmute conversations.
 522       *
 523       * @param int $userid The id of the user who is unblocking
 524       * @param array $conversationids The list of conversations being muted
 525       */
 526      public static function unmute_conversations(int $userid, array $conversationids) {
 527          global $CFG, $USER;
 528  
 529          // Check if messaging is enabled.
 530          if (empty($CFG->messaging)) {
 531              throw new moodle_exception('disabled', 'message');
 532          }
 533  
 534          // Validate context.
 535          $context = context_system::instance();
 536          self::validate_context($context);
 537  
 538          $params = ['userid' => $userid, 'conversationids' => $conversationids];
 539          $params = self::validate_parameters(self::unmute_conversations_parameters(), $params);
 540  
 541          $capability = 'moodle/site:manageallmessaging';
 542          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 543              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 544          }
 545  
 546          foreach ($params['conversationids'] as $conversationid) {
 547              \core_message\api::unmute_conversation($params['userid'], $conversationid);
 548          }
 549  
 550          return [];
 551      }
 552  
 553      /**
 554       * Unmute conversations return description.
 555       *
 556       * @return external_description
 557       */
 558      public static function unmute_conversations_returns() {
 559          return new external_warnings();
 560      }
 561  
 562      /**
 563       * Block user parameters description.
 564       *
 565       * @return external_function_parameters
 566       */
 567      public static function block_user_parameters() {
 568          return new external_function_parameters(
 569              [
 570                  'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
 571                  'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
 572              ]
 573          );
 574      }
 575  
 576      /**
 577       * Blocks a user.
 578       *
 579       * @param int $userid The id of the user who is blocking
 580       * @param int $blockeduserid The id of the user being blocked
 581       * @return external_description
 582       */
 583      public static function block_user(int $userid, int $blockeduserid) {
 584          global $CFG, $USER;
 585  
 586          // Check if messaging is enabled.
 587          if (empty($CFG->messaging)) {
 588              throw new moodle_exception('disabled', 'message');
 589          }
 590  
 591          // Validate context.
 592          $context = context_system::instance();
 593          self::validate_context($context);
 594  
 595          $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
 596          $params = self::validate_parameters(self::block_user_parameters(), $params);
 597  
 598          $capability = 'moodle/site:manageallmessaging';
 599          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 600              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 601          }
 602  
 603          // If the blocking is going to be useless then don't do it.
 604          if (\core_message\api::can_send_message($userid, $blockeduserid, true)) {
 605              return [];
 606          }
 607  
 608          if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
 609              \core_message\api::block_user($params['userid'], $params['blockeduserid']);
 610          }
 611  
 612          return [];
 613      }
 614  
 615      /**
 616       * Block user return description.
 617       *
 618       * @return external_description
 619       */
 620      public static function block_user_returns() {
 621          return new external_warnings();
 622      }
 623  
 624      /**
 625       * Unblock user parameters description.
 626       *
 627       * @return external_function_parameters
 628       */
 629      public static function unblock_user_parameters() {
 630          return new external_function_parameters(
 631              [
 632                  'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
 633                  'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
 634              ]
 635          );
 636      }
 637  
 638      /**
 639       * Unblock user.
 640       *
 641       * @param int $userid The id of the user who is unblocking
 642       * @param int $unblockeduserid The id of the user being unblocked
 643       */
 644      public static function unblock_user(int $userid, int $unblockeduserid) {
 645          global $CFG, $USER;
 646  
 647          // Check if messaging is enabled.
 648          if (empty($CFG->messaging)) {
 649              throw new moodle_exception('disabled', 'message');
 650          }
 651  
 652          // Validate context.
 653          $context = context_system::instance();
 654          self::validate_context($context);
 655  
 656          $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
 657          $params = self::validate_parameters(self::unblock_user_parameters(), $params);
 658  
 659          $capability = 'moodle/site:manageallmessaging';
 660          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 661              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 662          }
 663  
 664          \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
 665  
 666          return [];
 667      }
 668  
 669      /**
 670       * Unblock user return description.
 671       *
 672       * @return external_description
 673       */
 674      public static function unblock_user_returns() {
 675          return new external_warnings();
 676      }
 677  
 678      /**
 679       * Block contacts parameters description.
 680       *
 681       * @deprecated since Moodle 3.6
 682       * @return external_function_parameters
 683       * @since Moodle 2.5
 684       */
 685      public static function block_contacts_parameters() {
 686          return new external_function_parameters(
 687              array(
 688                  'userids' => new external_multiple_structure(
 689                      new external_value(PARAM_INT, 'User ID'),
 690                      'List of user IDs'
 691                  ),
 692                  'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
 693                      current user', VALUE_DEFAULT, 0)
 694              )
 695          );
 696      }
 697  
 698      /**
 699       * Block contacts.
 700       *
 701       * @deprecated since Moodle 3.6
 702       * @param array $userids array of user IDs.
 703       * @param int $userid The id of the user we are blocking the contacts for
 704       * @return external_description
 705       * @since Moodle 2.5
 706       */
 707      public static function block_contacts($userids, $userid = 0) {
 708          global $CFG, $USER;
 709  
 710          // Check if messaging is enabled.
 711          if (empty($CFG->messaging)) {
 712              throw new moodle_exception('disabled', 'message');
 713          }
 714  
 715          if (empty($userid)) {
 716              $userid = $USER->id;
 717          }
 718  
 719          // Validate context.
 720          $context = context_system::instance();
 721          self::validate_context($context);
 722  
 723          $params = array('userids' => $userids, 'userid' => $userid);
 724          $params = self::validate_parameters(self::block_contacts_parameters(), $params);
 725  
 726          $capability = 'moodle/site:manageallmessaging';
 727          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 728              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 729          }
 730  
 731          $warnings = array();
 732          foreach ($params['userids'] as $id) {
 733              if (!message_block_contact($id, $params['userid'])) {
 734                  $warnings[] = array(
 735                      'item' => 'user',
 736                      'itemid' => $id,
 737                      'warningcode' => 'contactnotblocked',
 738                      'message' => 'The contact could not be blocked'
 739                  );
 740              }
 741          }
 742          return $warnings;
 743      }
 744  
 745      /**
 746       * Block contacts return description.
 747       *
 748       * @deprecated since Moodle 3.6
 749       * @return external_description
 750       * @since Moodle 2.5
 751       */
 752      public static function block_contacts_returns() {
 753          return new external_warnings();
 754      }
 755  
 756      /**
 757       * Marking the method as deprecated.
 758       *
 759       * @return bool
 760       */
 761      public static function block_contacts_is_deprecated() {
 762          return true;
 763      }
 764  
 765      /**
 766       * Unblock contacts parameters description.
 767       *
 768       * @deprecated since Moodle 3.6
 769       * @return external_function_parameters
 770       * @since Moodle 2.5
 771       */
 772      public static function unblock_contacts_parameters() {
 773          return new external_function_parameters(
 774              array(
 775                  'userids' => new external_multiple_structure(
 776                      new external_value(PARAM_INT, 'User ID'),
 777                      'List of user IDs'
 778                  ),
 779                  'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
 780                      current user', VALUE_DEFAULT, 0)
 781              )
 782          );
 783      }
 784  
 785      /**
 786       * Unblock contacts.
 787       *
 788       * @param array $userids array of user IDs.
 789       * @param int $userid The id of the user we are unblocking the contacts for
 790       * @return null
 791       * @since Moodle 2.5
 792       */
 793      public static function unblock_contacts($userids, $userid = 0) {
 794          global $CFG, $USER;
 795  
 796          // Check if messaging is enabled.
 797          if (empty($CFG->messaging)) {
 798              throw new moodle_exception('disabled', 'message');
 799          }
 800  
 801          if (empty($userid)) {
 802              $userid = $USER->id;
 803          }
 804  
 805          // Validate context.
 806          $context = context_system::instance();
 807          self::validate_context($context);
 808  
 809          $params = array('userids' => $userids, 'userid' => $userid);
 810          $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
 811  
 812          $capability = 'moodle/site:manageallmessaging';
 813          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 814              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 815          }
 816  
 817          foreach ($params['userids'] as $id) {
 818              message_unblock_contact($id, $params['userid']);
 819          }
 820  
 821          return null;
 822      }
 823  
 824      /**
 825       * Unblock contacts return description.
 826       *
 827       * @deprecated since Moodle 3.6
 828       * @return external_description
 829       * @since Moodle 2.5
 830       */
 831      public static function unblock_contacts_returns() {
 832          return null;
 833      }
 834  
 835      /**
 836       * Marking the method as deprecated.
 837       *
 838       * @return bool
 839       */
 840      public static function unblock_contacts_is_deprecated() {
 841          return true;
 842      }
 843  
 844      /**
 845       * Returns contact requests parameters description.
 846       *
 847       * @return external_function_parameters
 848       */
 849      public static function get_contact_requests_parameters() {
 850          return new external_function_parameters(
 851              [
 852                  'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
 853                  'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
 854                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
 855              ]
 856          );
 857      }
 858  
 859      /**
 860       * Handles returning the contact requests for a user.
 861       *
 862       * This also includes the user data necessary to display information
 863       * about the user.
 864       *
 865       * It will not include blocked users.
 866       *
 867       * @param int $userid The id of the user we want to get the contact requests for
 868       * @param int $limitfrom
 869       * @param int $limitnum
 870       */
 871      public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
 872          global $CFG, $USER;
 873  
 874          // Check if messaging is enabled.
 875          if (empty($CFG->messaging)) {
 876              throw new moodle_exception('disabled', 'message');
 877          }
 878  
 879          // Validate context.
 880          $context = context_system::instance();
 881          self::validate_context($context);
 882  
 883          $params = [
 884              'userid' => $userid,
 885              'limitfrom' => $limitfrom,
 886              'limitnum' => $limitnum
 887          ];
 888          $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
 889  
 890          $capability = 'moodle/site:manageallmessaging';
 891          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 892              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 893          }
 894  
 895          return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
 896      }
 897  
 898      /**
 899       * Returns the contact requests return description.
 900       *
 901       * @return external_description
 902       */
 903      public static function get_contact_requests_returns() {
 904          return new external_multiple_structure(
 905              self::get_conversation_member_structure()
 906          );
 907      }
 908  
 909      /**
 910       * Returns the number of contact requests the user has received parameters description.
 911       *
 912       * @return external_function_parameters
 913       */
 914      public static function get_received_contact_requests_count_parameters() {
 915          return new external_function_parameters(
 916              array(
 917                  'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' .
 918                      'received contact requests for', VALUE_REQUIRED),
 919              )
 920          );
 921      }
 922  
 923      /**
 924       * Returns the number of contact requests the user has received.
 925       *
 926       * @param int $userid The ID of the user we want to return the number of received contact requests for
 927       * @return external_value
 928       */
 929      public static function get_received_contact_requests_count(int $userid) {
 930          global $CFG, $USER;
 931  
 932          // Check if messaging is enabled.
 933          if (empty($CFG->messaging)) {
 934              throw new moodle_exception('disabled', 'message');
 935          }
 936  
 937          // Validate context.
 938          $context = context_system::instance();
 939          self::validate_context($context);
 940  
 941          $params = [
 942              'userid' => $userid,
 943          ];
 944          $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params);
 945  
 946          $capability = 'moodle/site:manageallmessaging';
 947          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
 948              throw new required_capability_exception($context, $capability, 'nopermissions', '');
 949          }
 950  
 951          return \core_message\api::get_received_contact_requests_count($params['userid']);
 952      }
 953  
 954      /**
 955       * Returns the number of contact requests the user has received return description.
 956       *
 957       * @return external_value
 958       */
 959      public static function get_received_contact_requests_count_returns() {
 960          return new external_value(PARAM_INT, 'The number of received contact requests');
 961      }
 962  
 963      /**
 964       * Returns get conversation members parameters description.
 965       *
 966       * @return external_function_parameters
 967       */
 968      public static function get_conversation_members_parameters() {
 969          return new external_function_parameters(
 970              [
 971                  'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
 972                  'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
 973                  'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
 974                      VALUE_DEFAULT, false),
 975                  'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?',
 976                      VALUE_DEFAULT, false),
 977                  'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
 978                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
 979              ]
 980          );
 981      }
 982  
 983      /**
 984       * Returns a list of conversation members.
 985       *
 986       * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
 987       * @param int $conversationid The id of the conversation
 988       * @param bool $includecontactrequests Do we want to include contact requests with this data?
 989       * @param bool $includeprivacyinfo Do we want to include privacy info?
 990       * @param int $limitfrom
 991       * @param int $limitnum
 992       * @return array
 993       */
 994      public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
 995                                                      bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) {
 996          global $CFG, $USER;
 997  
 998          // Check if messaging is enabled.
 999          if (empty($CFG->messaging)) {
1000              throw new moodle_exception('disabled', 'message');
1001          }
1002  
1003          // Validate context.
1004          $context = context_system::instance();
1005          self::validate_context($context);
1006  
1007          $params = [
1008              'userid' => $userid,
1009              'conversationid' => $conversationid,
1010              'includecontactrequests' => $includecontactrequests,
1011              'includeprivacyinfo' => $includeprivacyinfo,
1012              'limitfrom' => $limitfrom,
1013              'limitnum' => $limitnum
1014          ];
1015          $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
1016  
1017          $capability = 'moodle/site:manageallmessaging';
1018          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
1019              throw new required_capability_exception($context, $capability, 'nopermissions', '');
1020          }
1021  
1022          // The user needs to be a part of the conversation before querying who the members are.
1023          if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
1024              throw new moodle_exception('You are not a member of this conversation.');
1025          }
1026  
1027          return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
1028              $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']);
1029      }
1030  
1031      /**
1032       * Returns the get conversation members return description.
1033       *
1034       * @return external_description
1035       */
1036      public static function get_conversation_members_returns() {
1037          return new external_multiple_structure(
1038              self::get_conversation_member_structure()
1039          );
1040      }
1041  
1042      /**
1043       * Creates a contact request parameters description.
1044       *
1045       * @return external_function_parameters
1046       */
1047      public static function create_contact_request_parameters() {
1048          return new external_function_parameters(
1049              [
1050                  'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
1051                  'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
1052              ]
1053          );
1054      }
1055  
1056      /**
1057       * Creates a contact request.
1058       *
1059       * @param int $userid The id of the user who is creating the contact request
1060       * @param int $requesteduserid The id of the user being requested
1061       */
1062      public static function create_contact_request(int $userid, int $requesteduserid) {
1063          global $CFG, $USER;
1064  
1065          // Check if messaging is enabled.
1066          if (empty($CFG->messaging)) {
1067              throw new moodle_exception('disabled', 'message');
1068          }
1069  
1070          // Validate context.
1071          $context = context_system::instance();
1072          self::validate_context($context);
1073  
1074          $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
1075          $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
1076  
1077          $capability = 'moodle/site:manageallmessaging';
1078          if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
1079              throw new required_capability_exception($context, $capability, 'nopermissions', '');
1080          }
1081  
1082          $result = [
1083              'warnings' => []
1084          ];
1085  
1086          if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
1087              $result['warnings'][] = [
1088                  'item' => 'user',
1089                  'itemid' => $params['requesteduserid'],
1090                  'warningcode' => 'cannotcreatecontactrequest',
1091                  'message' => 'You are unable to create a contact request for this user'
1092              ];
1093          } else {
1094              if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
1095                  // There should only ever be one but just in case there are multiple then we can return the first.
1096                  $result['request'] = array_shift($requests);
1097              } else {
1098                  $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
1099              }
1100          }
1101  
1102          return $result;
1103      }
1104  
1105      /**
1106       * Creates a contact request return description.
1107       *
1108       * @return external_description
1109       */
1110      public static function create_contact_request_returns() {
1111          return new external_single_structure(
1112              array(
1113                  'request' => new external_single_structure(
1114                      array(
1115                          'id' => new external_value(PARAM_INT, 'Message id'),
1116                          'userid' => new external_value(PARAM_INT, 'User from id'),
1117                          'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
1118                          'timecreated' => new external_value(PARAM_INT, 'Time created'),
1119                      ),
1120                      'request record',
1121                      VALUE_OPTIONAL
1122                  ),
1123                  'warnings' => new external_warnings()
1124              )
1125          );
1126      }
1127  
1128      /**
1129       * Confirm a contact request parameters description.
1130       *
1131       * @return external_function_parameters
1132       */
1133      public static function confirm_contact_request_parameters() {
1134          return new external_function_parameters(
1135              [
1136                  'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
1137                  'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
1138              ]
1139          );
1140      }
1141  
1142      /**
1143       * Confirm a contact request.
1144       *
1145       * @param int $userid The id of the user who is creating the contact request
1146       * @param int $requesteduserid The id of the user being requested
1147       */
1148      public static function confirm_contact_request(int $userid, int $requesteduserid) {
1149          global $CFG, $USER;
1150  
1151          // Check if messaging is enabled.
1152          if (empty($CFG->messaging)) {
1153              throw new moodle_exception('disabled', 'message');
1154          }
1155  
1156          // Validate context.
1157          $context = context_system::instance();
1158          self::validate_context($context);
1159  
1160          $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
1161          $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
1162  
1163          $capability = 'moodle/site:manageallmessaging';
1164          if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
1165              throw new required_capability_exception($context, $capability, 'nopermissions', '');
1166          }
1167  
1168          \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
1169  
1170          return [];
1171      }
1172  
1173      /**
1174       * Confirm a contact request return description.
1175       *
1176       * @return external_description
1177       */
1178      public static function confirm_contact_request_returns() {
1179          return new external_warnings();
1180      }
1181  
1182      /**
1183       * Declines a contact request parameters description.
1184       *
1185       * @return external_function_parameters
1186       */
1187      public static function decline_contact_request_parameters() {
1188          return new external_function_parameters(
1189              [
1190                  'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
1191                  'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
1192              ]
1193          );
1194      }
1195  
1196      /**
1197       * Declines a contact request.
1198       *
1199       * @param int $userid The id of the user who is creating the contact request
1200       * @param int $requesteduserid The id of the user being requested
1201       */
1202      public static function decline_contact_request(int $userid, int $requesteduserid) {
1203          global $CFG, $USER;
1204  
1205          // Check if messaging is enabled.
1206          if (empty($CFG->messaging)) {
1207              throw new moodle_exception('disabled', 'message');
1208          }
1209  
1210          // Validate context.
1211          $context = context_system::instance();
1212          self::validate_context($context);
1213  
1214          $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
1215          $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
1216  
1217          $capability = 'moodle/site:manageallmessaging';
1218          if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
1219              throw new required_capability_exception($context, $capability, 'nopermissions', '');
1220          }
1221  
1222          \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
1223  
1224          return [];
1225      }
1226  
1227      /**
1228       * Declines a contact request return description.
1229       *
1230       * @return external_description
1231       */
1232      public static function decline_contact_request_returns() {
1233          return new external_warnings();
1234      }
1235  
1236      /**
1237       * Return the structure of a message area contact.
1238       *
1239       * @return external_single_structure
1240       * @since Moodle 3.2
1241       */
1242      private static function get_messagearea_contact_structure() {
1243          return new external_single_structure(
1244              array(
1245                  'userid' => new external_value(PARAM_INT, 'The user\'s id'),
1246                  'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1247                  'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1248                  'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1249                  'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
1250                  'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
1251                  'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
1252                  'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null),
1253                  'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
1254                  'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1255                  'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1256                  'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
1257                  'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1258                  'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1259                      VALUE_DEFAULT, null),
1260                  'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null),
1261              )
1262          );
1263      }
1264  
1265      /**
1266       * Return the structure of a conversation.
1267       *
1268       * @return external_single_structure
1269       * @since Moodle 3.6
1270       */
1271      private static function get_conversation_structure() {
1272          return new external_single_structure(
1273              array(
1274                  'id' => new external_value(PARAM_INT, 'The conversation id'),
1275                  'name' => new external_value(PARAM_RAW, 'The conversation name, if set', VALUE_DEFAULT, null),
1276                  'subname' => new external_value(PARAM_RAW, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1277                  'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1278                  'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group,3=self)'),
1279                  'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1280                  'ismuted' => new external_value(PARAM_BOOL, 'If the user muted this conversation'),
1281                  'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this conversation as a favourite'),
1282                  'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1283                  'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1284                      VALUE_DEFAULT, null),
1285                  'members' => new external_multiple_structure(
1286                      self::get_conversation_member_structure()
1287                  ),
1288                  'messages' => new external_multiple_structure(
1289                      self::get_conversation_message_structure()
1290                  ),
1291                  'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
1292                      'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
1293              )
1294          );
1295      }
1296  
1297      /**
1298       * Return the structure of a conversation member.
1299       *
1300       * @return external_single_structure
1301       * @since Moodle 3.6
1302       */
1303      private static function get_conversation_member_structure() {
1304          $result = [
1305              'id' => new external_value(PARAM_INT, 'The user id'),
1306              'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1307              'profileurl' => new external_value(PARAM_URL, 'The link to the user\'s profile page'),
1308              'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1309              'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1310              'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1311              'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1312              'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1313              'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1314              'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1315              'canmessageevenifblocked' => new external_value(PARAM_BOOL,
1316                  'If the user can still message even if they get blocked'),
1317              'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1318              'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1319          ];
1320  
1321          $result['contactrequests'] = new external_multiple_structure(
1322              new external_single_structure(
1323                  [
1324                      'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1325                      'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1326                      'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1327                      'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1328                  ]
1329              ), 'The contact requests', VALUE_OPTIONAL
1330          );
1331  
1332          $result['conversations'] = new external_multiple_structure(new external_single_structure(
1333              array(
1334                  'id' => new external_value(PARAM_INT, 'Conversations id'),
1335                  'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1336                  'name' => new external_value(PARAM_RAW, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1337                  'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1338              ), 'information about conversation', VALUE_OPTIONAL),
1339              'Conversations between users', VALUE_OPTIONAL
1340          );
1341  
1342          return new external_single_structure(
1343              $result
1344          );
1345      }
1346  
1347      /**
1348       * Return the structure of a message area message.
1349       *
1350       * @return external_single_structure
1351       * @since Moodle 3.6
1352       */
1353      private static function get_conversation_message_structure() {
1354          return new external_single_structure(
1355              array(
1356                  'id' => new external_value(PARAM_INT, 'The id of the message'),
1357                  'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1358                  'text' => new external_value(PARAM_RAW, 'The text of the message'),
1359                  'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1360              )
1361          );
1362      }
1363  
1364      /**
1365       * Return the structure of a message area message.
1366       *
1367       * @return external_single_structure
1368       * @since Moodle 3.2
1369       */
1370      private static function get_messagearea_message_structure() {
1371          return new external_single_structure(
1372              array(
1373                  'id' => new external_value(PARAM_INT, 'The id of the message'),
1374                  'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1375                  'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1376                  'text' => new external_value(PARAM_RAW, 'The text of the message'),
1377                  'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1378                  'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1379                  'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1380                  'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1381                  'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1382                  'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1383              )
1384          );
1385      }
1386  
1387      /**
1388       * Get messagearea search users in course parameters.
1389       *
1390       * @deprecated since 3.6
1391       *
1392       * @return external_function_parameters
1393       * @since 3.2
1394       */
1395      public static function data_for_messagearea_search_users_in_course_parameters() {
1396          return new external_function_parameters(
1397              array(
1398                  'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1399                  'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1400                  'search' => new external_value(PARAM_RAW, 'The string being searched'),
1401                  'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1402                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1403              )
1404          );
1405      }
1406  
1407      /**
1408       * Get messagearea search users in course results.
1409       *
1410       * @deprecated since 3.6
1411       *
1412       * @param int $userid The id of the user who is performing the search
1413       * @param int $courseid The id of the course
1414       * @param string $search The string being searched
1415       * @param int $limitfrom
1416       * @param int $limitnum
1417       * @return stdClass
1418       * @throws moodle_exception
1419       * @since 3.2
1420       */
1421      public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1422                                                                         $limitnum = 0) {
1423          global $CFG, $PAGE, $USER;
1424  
1425          // Check if messaging is enabled.
1426          if (empty($CFG->messaging)) {
1427              throw new moodle_exception('disabled', 'message');
1428          }
1429  
1430          $systemcontext = context_system::instance();
1431  
1432          $params = array(
1433              'userid' => $userid,
1434              'courseid' => $courseid,
1435              'search' => $search,
1436              'limitfrom' => $limitfrom,
1437              'limitnum' => $limitnum
1438          );
1439          $params = self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1440          self::validate_context($systemcontext);
1441  
1442          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1443              throw new moodle_exception('You do not have permission to perform this action.');
1444          }
1445  
1446          $users = \core_message\api::search_users_in_course(
1447              $params['userid'],
1448              $params['courseid'],
1449              $params['search'],
1450              $params['limitfrom'],
1451              $params['limitnum']
1452          );
1453          $results = new \core_message\output\messagearea\user_search_results($users);
1454  
1455          $renderer = $PAGE->get_renderer('core_message');
1456          return $results->export_for_template($renderer);
1457      }
1458  
1459      /**
1460       * Get messagearea search users in course returns.
1461       *
1462       * @deprecated since 3.6
1463       *
1464       * @return external_single_structure
1465       * @since 3.2
1466       */
1467      public static function data_for_messagearea_search_users_in_course_returns() {
1468          return new external_single_structure(
1469              array(
1470                  'contacts' => new external_multiple_structure(
1471                      self::get_messagearea_contact_structure()
1472                  ),
1473              )
1474          );
1475      }
1476  
1477      /**
1478       * Marking the method as deprecated.
1479       *
1480       * @return bool
1481       */
1482      public static function data_for_messagearea_search_users_in_course_is_deprecated() {
1483          return true;
1484      }
1485  
1486      /**
1487       * Get messagearea search users parameters.
1488       *
1489       * @deprecated since 3.6
1490       *
1491       * @return external_function_parameters
1492       * @since 3.2
1493       */
1494      public static function data_for_messagearea_search_users_parameters() {
1495          return new external_function_parameters(
1496              array(
1497                  'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1498                  'search' => new external_value(PARAM_RAW, 'The string being searched'),
1499                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1500              )
1501          );
1502      }
1503  
1504      /**
1505       * Get messagearea search users results.
1506       *
1507       * @deprecated since 3.6
1508       *
1509       * @param int $userid The id of the user who is performing the search
1510       * @param string $search The string being searched
1511       * @param int $limitnum
1512       * @return stdClass
1513       * @throws moodle_exception
1514       * @since 3.2
1515       */
1516      public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1517          global $CFG, $PAGE, $USER;
1518  
1519          // Check if messaging is enabled.
1520          if (empty($CFG->messaging)) {
1521              throw new moodle_exception('disabled', 'message');
1522          }
1523  
1524          $systemcontext = context_system::instance();
1525  
1526          $params = array(
1527              'userid' => $userid,
1528              'search' => $search,
1529              'limitnum' => $limitnum
1530          );
1531          $params = self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1532          self::validate_context($systemcontext);
1533  
1534          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1535              throw new moodle_exception('You do not have permission to perform this action.');
1536          }
1537  
1538          list($contacts, $courses, $noncontacts) = \core_message\api::search_users(
1539              $params['userid'],
1540              $params['search'],
1541              $params['limitnum']
1542          );
1543  
1544          $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1545  
1546          $renderer = $PAGE->get_renderer('core_message');
1547          return $search->export_for_template($renderer);
1548      }
1549  
1550      /**
1551       * Get messagearea search users returns.
1552       *
1553       * @deprecated since 3.6
1554       *
1555       * @return external_single_structure
1556       * @since 3.2
1557       */
1558      public static function data_for_messagearea_search_users_returns() {
1559          return new external_single_structure(
1560              array(
1561                  'contacts' => new external_multiple_structure(
1562                      self::get_messagearea_contact_structure()
1563                  ),
1564                  'courses' => new external_multiple_structure(
1565                      new external_single_structure(
1566                          array(
1567                              'id' => new external_value(PARAM_INT, 'The course id'),
1568                              'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1569                              'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1570                          )
1571                      )
1572                  ),
1573                  'noncontacts' => new external_multiple_structure(
1574                      self::get_messagearea_contact_structure()
1575                  )
1576              )
1577          );
1578      }
1579  
1580      /**
1581       * Marking the method as deprecated.
1582       *
1583       * @return bool
1584       */
1585      public static function data_for_messagearea_search_users_is_deprecated() {
1586          return true;
1587      }
1588  
1589      /**
1590       * Get messagearea message search users parameters.
1591       *
1592       * @return external_function_parameters
1593       * @since 3.6
1594       */
1595      public static function message_search_users_parameters() {
1596          return new external_function_parameters(
1597              array(
1598                  'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1599                  'search' => new external_value(PARAM_RAW, 'The string being searched'),
1600                  'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1601                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1602              )
1603          );
1604      }
1605  
1606      /**
1607       * Get search users results.
1608       *
1609       * @param int $userid The id of the user who is performing the search
1610       * @param string $search The string being searched
1611       * @param int $limitfrom
1612       * @param int $limitnum
1613       * @return array
1614       * @throws moodle_exception
1615       * @since 3.6
1616       */
1617      public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1618          global $USER;
1619  
1620          $systemcontext = context_system::instance();
1621  
1622          $params = array(
1623              'userid' => $userid,
1624              'search' => $search,
1625              'limitfrom' => $limitfrom,
1626              'limitnum' => $limitnum
1627          );
1628          $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1629          self::validate_context($systemcontext);
1630  
1631          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1632              throw new moodle_exception('You do not have permission to perform this action.');
1633          }
1634  
1635          list($contacts, $noncontacts) = \core_message\api::message_search_users(
1636              $params['userid'],
1637              $params['search'],
1638              $params['limitfrom'],
1639              $params['limitnum']);
1640  
1641          return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1642      }
1643  
1644      /**
1645       * Get messagearea message search users returns.
1646       *
1647       * @return external_single_structure
1648       * @since 3.2
1649       */
1650      public static function message_search_users_returns() {
1651          return new external_single_structure(
1652              array(
1653                  'contacts' => new external_multiple_structure(
1654                      self::get_conversation_member_structure()
1655                  ),
1656                  'noncontacts' => new external_multiple_structure(
1657                      self::get_conversation_member_structure()
1658                  )
1659              )
1660          );
1661      }
1662  
1663      /**
1664       * Get messagearea search messages parameters.
1665       *
1666       * @return external_function_parameters
1667       * @since 3.2
1668       */
1669      public static function data_for_messagearea_search_messages_parameters() {
1670          return new external_function_parameters(
1671              array(
1672                  'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1673                  'search' => new external_value(PARAM_RAW, 'The string being searched'),
1674                  'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1675                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1676              )
1677          );
1678      }
1679  
1680      /**
1681       * Get messagearea search messages results.
1682       *
1683       * @param int $userid The id of the user who is performing the search
1684       * @param string $search The string being searched
1685       * @param int $limitfrom
1686       * @param int $limitnum
1687       * @return stdClass
1688       * @throws moodle_exception
1689       * @since 3.2
1690       */
1691      public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1692          global $CFG, $USER;
1693  
1694          // Check if messaging is enabled.
1695          if (empty($CFG->messaging)) {
1696              throw new moodle_exception('disabled', 'message');
1697          }
1698  
1699          $systemcontext = context_system::instance();
1700  
1701          $params = array(
1702              'userid' => $userid,
1703              'search' => $search,
1704              'limitfrom' => $limitfrom,
1705              'limitnum' => $limitnum
1706  
1707          );
1708          $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1709          self::validate_context($systemcontext);
1710  
1711          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1712              throw new moodle_exception('You do not have permission to perform this action.');
1713          }
1714  
1715          $messages = \core_message\api::search_messages(
1716              $params['userid'],
1717              $params['search'],
1718              $params['limitfrom'],
1719              $params['limitnum']
1720          );
1721  
1722          $data = new \stdClass();
1723          $data->contacts = [];
1724          foreach ($messages as $message) {
1725              $contact = new \stdClass();
1726              $contact->userid = $message->userid;
1727              $contact->fullname = $message->fullname;
1728              $contact->profileimageurl = $message->profileimageurl;
1729              $contact->profileimageurlsmall = $message->profileimageurlsmall;
1730              $contact->messageid = $message->messageid;
1731              $contact->ismessaging = $message->ismessaging;
1732              $contact->sentfromcurrentuser = false;
1733              if ($message->lastmessage) {
1734                  if ($message->userid !== $message->useridfrom) {
1735                      $contact->sentfromcurrentuser = true;
1736                  }
1737                  $contact->lastmessage = shorten_text($message->lastmessage, 60);
1738              } else {
1739                  $contact->lastmessage = null;
1740              }
1741              $contact->lastmessagedate = $message->lastmessagedate;
1742              $contact->showonlinestatus = is_null($message->isonline) ? false : true;
1743              $contact->isonline = $message->isonline;
1744              $contact->isblocked = $message->isblocked;
1745              $contact->isread = $message->isread;
1746              $contact->unreadcount = $message->unreadcount;
1747              $contact->conversationid = $message->conversationid;
1748  
1749              $data->contacts[] = $contact;
1750          }
1751  
1752          return $data;
1753      }
1754  
1755      /**
1756       * Get messagearea search messages returns.
1757       *
1758       * @return external_single_structure
1759       * @since 3.2
1760       */
1761      public static function data_for_messagearea_search_messages_returns() {
1762          return new external_single_structure(
1763              array(
1764                  'contacts' => new external_multiple_structure(
1765                      self::get_messagearea_contact_structure()
1766                  )
1767              )
1768          );
1769      }
1770  
1771      /**
1772       * Get conversations parameters.
1773       *
1774       * @return external_function_parameters
1775       * @since 3.6
1776       */
1777      public static function get_conversations_parameters() {
1778          return new external_function_parameters(
1779              array(
1780                  'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1781                  'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1782                  'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1783                  'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1784                  'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1785                  conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1786                      VALUE_DEFAULT, null),
1787                  'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private
1788                      conversations (false) when private conversations are requested.',
1789                      VALUE_DEFAULT, false),
1790              )
1791          );
1792      }
1793  
1794      /**
1795       * Get the list of conversations for the user.
1796       *
1797       * @param int $userid The id of the user who is performing the search
1798       * @param int $limitfrom
1799       * @param int $limitnum
1800       * @param int|null $type
1801       * @param bool|null $favourites
1802       * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false)
1803       *             when private conversations are requested.
1804       * @return stdClass
1805       * @throws \moodle_exception if the messaging feature is disabled on the site.
1806       * @since 3.2
1807       */
1808      public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null,
1809              bool $mergeself = false) {
1810          global $CFG, $USER;
1811  
1812          // All the standard BL checks.
1813          if (empty($CFG->messaging)) {
1814              throw new moodle_exception('disabled', 'message');
1815          }
1816  
1817          $params = array(
1818              'userid' => $userid,
1819              'limitfrom' => $limitfrom,
1820              'limitnum' => $limitnum,
1821              'type' => $type,
1822              'favourites' => $favourites,
1823              'mergeself' => $mergeself
1824          );
1825          $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1826  
1827          $systemcontext = context_system::instance();
1828          self::validate_context($systemcontext);
1829  
1830          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1831              throw new moodle_exception('You do not have permission to perform this action.');
1832          }
1833  
1834          $conversations = \core_message\api::get_conversations(
1835              $params['userid'],
1836              $params['limitfrom'],
1837              $params['limitnum'],
1838              $params['type'],
1839              $params['favourites'],
1840              $params['mergeself']
1841          );
1842  
1843          return (object) ['conversations' => $conversations];
1844      }
1845  
1846      /**
1847       * Get conversations returns.
1848       *
1849       * @return external_single_structure
1850       * @since 3.6
1851       */
1852      public static function get_conversations_returns() {
1853          return new external_single_structure(
1854              [
1855                  'conversations' => new external_multiple_structure(
1856                      self::get_conversation_structure(true)
1857                  )
1858              ]
1859          );
1860      }
1861  
1862      /**
1863       * Get conversation parameters.
1864       *
1865       * @return external_function_parameters
1866       */
1867      public static function get_conversation_parameters() {
1868          return new external_function_parameters(
1869              array(
1870                  'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1871                  'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1872                  'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1873                  'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1874                  'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1875                  'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1876                  'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1877                  'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1878                  'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1879              )
1880          );
1881      }
1882  
1883      /**
1884       * Get a single conversation.
1885       *
1886       * @param int $userid The user id to get the conversation for
1887       * @param int $conversationid The id of the conversation to fetch
1888       * @param bool $includecontactrequests Should contact requests be included between members
1889       * @param bool $includeprivacyinfo Should privacy info be included between members
1890       * @param int $memberlimit Limit number of members to load
1891       * @param int $memberoffset Offset members by this amount
1892       * @param int $messagelimit Limit number of messages to load
1893       * @param int $messageoffset Offset the messages
1894       * @param bool $newestmessagesfirst Order messages by newest first
1895       * @return stdClass
1896       * @throws \moodle_exception if the messaging feature is disabled on the site.
1897       */
1898      public static function get_conversation(
1899          int $userid,
1900          int $conversationid,
1901          bool $includecontactrequests = false,
1902          bool $includeprivacyinfo = false,
1903          int $memberlimit = 0,
1904          int $memberoffset = 0,
1905          int $messagelimit = 0,
1906          int $messageoffset = 0,
1907          bool $newestmessagesfirst = true
1908      ) {
1909          global $CFG, $DB, $USER;
1910  
1911          // All the standard BL checks.
1912          if (empty($CFG->messaging)) {
1913              throw new moodle_exception('disabled', 'message');
1914          }
1915  
1916          $params = [
1917              'userid' => $userid,
1918              'conversationid' => $conversationid,
1919              'includecontactrequests' => $includecontactrequests,
1920              'includeprivacyinfo' => $includeprivacyinfo,
1921              'memberlimit' => $memberlimit,
1922              'memberoffset' => $memberoffset,
1923              'messagelimit' => $messagelimit,
1924              'messageoffset' => $messageoffset,
1925              'newestmessagesfirst' => $newestmessagesfirst
1926          ];
1927          self::validate_parameters(self::get_conversation_parameters(), $params);
1928  
1929          $systemcontext = context_system::instance();
1930          self::validate_context($systemcontext);
1931  
1932          $conversation = \core_message\api::get_conversation(
1933              $params['userid'],
1934              $params['conversationid'],
1935              $params['includecontactrequests'],
1936              $params['includeprivacyinfo'],
1937              $params['memberlimit'],
1938              $params['memberoffset'],
1939              $params['messagelimit'],
1940              $params['messageoffset'],
1941              $params['newestmessagesfirst']
1942          );
1943  
1944          if ($conversation) {
1945              return $conversation;
1946          } else {
1947              // We have to throw an exception here because the external functions annoyingly
1948              // don't accept null to be returned for a single structure.
1949              throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1950          }
1951      }
1952  
1953      /**
1954       * Get conversation returns.
1955       *
1956       * @return external_single_structure
1957       */
1958      public static function get_conversation_returns() {
1959          return self::get_conversation_structure();
1960      }
1961  
1962      /**
1963       * Get conversation parameters.
1964       *
1965       * @return external_function_parameters
1966       */
1967      public static function get_conversation_between_users_parameters() {
1968          return new external_function_parameters(
1969              array(
1970                  'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1971                  'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1972                  'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1973                  'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1974                  'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1975                  'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1976                  'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1977                  'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1978                  'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1979              )
1980          );
1981      }
1982  
1983      /**
1984       * Get a single conversation between users.
1985       *
1986       * @param int $userid The user id to get the conversation for
1987       * @param int $otheruserid The other user id
1988       * @param bool $includecontactrequests Should contact requests be included between members
1989       * @param bool $includeprivacyinfo Should privacy info be included between members
1990       * @param int $memberlimit Limit number of members to load
1991       * @param int $memberoffset Offset members by this amount
1992       * @param int $messagelimit Limit number of messages to load
1993       * @param int $messageoffset Offset the messages
1994       * @param bool $newestmessagesfirst Order messages by newest first
1995       * @return stdClass
1996       * @throws \moodle_exception if the messaging feature is disabled on the site.
1997       */
1998      public static function get_conversation_between_users(
1999          int $userid,
2000          int $otheruserid,
2001          bool $includecontactrequests = false,
2002          bool $includeprivacyinfo = false,
2003          int $memberlimit = 0,
2004          int $memberoffset = 0,
2005          int $messagelimit = 0,
2006          int $messageoffset = 0,
2007          bool $newestmessagesfirst = true
2008      ) {
2009          global $CFG, $DB, $USER;
2010  
2011          // All the standard BL checks.
2012          if (empty($CFG->messaging)) {
2013              throw new moodle_exception('disabled', 'message');
2014          }
2015  
2016          $params = [
2017              'userid' => $userid,
2018              'otheruserid' => $otheruserid,
2019              'includecontactrequests' => $includecontactrequests,
2020              'includeprivacyinfo' => $includeprivacyinfo,
2021              'memberlimit' => $memberlimit,
2022              'memberoffset' => $memberoffset,
2023              'messagelimit' => $messagelimit,
2024              'messageoffset' => $messageoffset,
2025              'newestmessagesfirst' => $newestmessagesfirst
2026          ];
2027          self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
2028  
2029          $systemcontext = context_system::instance();
2030          self::validate_context($systemcontext);
2031  
2032          $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
2033          $conversation = null;
2034  
2035          if ($conversationid) {
2036              $conversation = \core_message\api::get_conversation(
2037                  $params['userid'],
2038                  $conversationid,
2039                  $params['includecontactrequests'],
2040                  $params['includeprivacyinfo'],
2041                  $params['memberlimit'],
2042                  $params['memberoffset'],
2043                  $params['messagelimit'],
2044                  $params['messageoffset'],
2045                  $params['newestmessagesfirst']
2046              );
2047          }
2048  
2049          if ($conversation) {
2050              return $conversation;
2051          } else {
2052              // We have to throw an exception here because the external functions annoyingly
2053              // don't accept null to be returned for a single structure.
2054              throw new \moodle_exception('errorconversationdoesnotexist', 'message');
2055          }
2056      }
2057  
2058      /**
2059       * Get conversation returns.
2060       *
2061       * @return external_single_structure
2062       */
2063      public static function get_conversation_between_users_returns() {
2064          return self::get_conversation_structure(true);
2065      }
2066  
2067      /**
2068       * Get self-conversation parameters.
2069       *
2070       * @return external_function_parameters
2071       */
2072      public static function get_self_conversation_parameters() {
2073          return new external_function_parameters(
2074              array(
2075                  'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'),
2076                  'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
2077                  'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
2078                  'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
2079              )
2080          );
2081      }
2082  
2083      /**
2084       * Get a single self-conversation.
2085       *
2086       * @param int $userid The user id to get the self-conversation for
2087       * @param int $messagelimit Limit number of messages to load
2088       * @param int $messageoffset Offset the messages
2089       * @param bool $newestmessagesfirst Order messages by newest first
2090       * @return stdClass
2091       * @throws \moodle_exception if the messaging feature is disabled on the site.
2092       * @since Moodle 3.7
2093       */
2094      public static function get_self_conversation(
2095          int $userid,
2096          int $messagelimit = 0,
2097          int $messageoffset = 0,
2098          bool $newestmessagesfirst = true
2099      ) {
2100          global $CFG;
2101  
2102          // All the standard BL checks.
2103          if (empty($CFG->messaging)) {
2104              throw new moodle_exception('disabled', 'message');
2105          }
2106  
2107          $params = [
2108              'userid' => $userid,
2109              'messagelimit' => $messagelimit,
2110              'messageoffset' => $messageoffset,
2111              'newestmessagesfirst' => $newestmessagesfirst
2112          ];
2113          self::validate_parameters(self::get_self_conversation_parameters(), $params);
2114  
2115          $systemcontext = context_system::instance();
2116          self::validate_context($systemcontext);
2117  
2118          $conversation = \core_message\api::get_self_conversation($params['userid']);
2119  
2120          if ($conversation) {
2121              $conversation = \core_message\api::get_conversation(
2122                  $params['userid'],
2123                  $conversation->id,
2124                  false,
2125                  false,
2126                  0,
2127                  0,
2128                  $params['messagelimit'],
2129                  $params['messageoffset'],
2130                  $params['newestmessagesfirst']
2131              );
2132          }
2133  
2134          if ($conversation) {
2135              return $conversation;
2136          } else {
2137              // We have to throw an exception here because the external functions annoyingly
2138              // don't accept null to be returned for a single structure.
2139              throw new \moodle_exception('errorconversationdoesnotexist', 'message');
2140          }
2141      }
2142  
2143      /**
2144       * Get conversation returns.
2145       *
2146       * @return external_single_structure
2147       */
2148      public static function get_self_conversation_returns() {
2149          return self::get_conversation_structure();
2150      }
2151  
2152      /**
2153       * The messagearea conversations parameters.
2154       *
2155       * @deprecated since 3.6
2156       * @return external_function_parameters
2157       * @since 3.2
2158       */
2159      public static function data_for_messagearea_conversations_parameters() {
2160          return new external_function_parameters(
2161              array(
2162                  'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
2163                  'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2164                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
2165              )
2166          );
2167      }
2168  
2169      /**
2170       * Get messagearea conversations.
2171       *
2172       * NOTE FOR FINAL DEPRECATION:
2173       * When removing this method, please also consider removal of get_conversations_legacy_formatter()
2174       * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
2175       * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
2176       * removed.
2177       *
2178       * @deprecated since 3.6
2179       * @param int $userid The id of the user who we are viewing conversations for
2180       * @param int $limitfrom
2181       * @param int $limitnum
2182       * @return stdClass
2183       * @throws moodle_exception
2184       * @since 3.2
2185       */
2186      public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
2187          global $CFG, $PAGE, $USER;
2188  
2189          // Check if messaging is enabled.
2190          if (empty($CFG->messaging)) {
2191              throw new moodle_exception('disabled', 'message');
2192          }
2193  
2194          $systemcontext = context_system::instance();
2195  
2196          $params = array(
2197              'userid' => $userid,
2198              'limitfrom' => $limitfrom,
2199              'limitnum' => $limitnum
2200          );
2201          $params = self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
2202          self::validate_context($systemcontext);
2203  
2204          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2205              throw new moodle_exception('You do not have permission to perform this action.');
2206          }
2207  
2208          $conversations = \core_message\api::get_conversations($params['userid'], $params['limitfrom'], $params['limitnum']);
2209  
2210          // Format the conversations in the legacy style, as the get_conversations method has since been changed.
2211          $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
2212  
2213          $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
2214  
2215          $renderer = $PAGE->get_renderer('core_message');
2216          return $conversations->export_for_template($renderer);
2217      }
2218  
2219      /**
2220       * The messagearea conversations return structure.
2221       *
2222       * @deprecated since 3.6
2223       * @return external_single_structure
2224       * @since 3.2
2225       */
2226      public static function data_for_messagearea_conversations_returns() {
2227          return new external_single_structure(
2228              array(
2229                  'contacts' => new external_multiple_structure(
2230                      self::get_messagearea_contact_structure()
2231                  )
2232              )
2233          );
2234      }
2235  
2236      /**
2237       * Marking the method as deprecated.
2238       *
2239       * @return bool
2240       */
2241      public static function data_for_messagearea_conversations_is_deprecated() {
2242          return true;
2243      }
2244  
2245      /**
2246       * The messagearea contacts return parameters.
2247       *
2248       * @deprecated since 3.6
2249       * @return external_function_parameters
2250       * @since 3.2
2251       */
2252      public static function data_for_messagearea_contacts_parameters() {
2253          return self::data_for_messagearea_conversations_parameters();
2254      }
2255  
2256      /**
2257       * Get messagearea contacts parameters.
2258       *
2259       * @deprecated since 3.6
2260       * @param int $userid The id of the user who we are viewing conversations for
2261       * @param int $limitfrom
2262       * @param int $limitnum
2263       * @return stdClass
2264       * @throws moodle_exception
2265       * @since 3.2
2266       */
2267      public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
2268          global $CFG, $PAGE, $USER;
2269  
2270          // Check if messaging is enabled.
2271          if (empty($CFG->messaging)) {
2272              throw new moodle_exception('disabled', 'message');
2273          }
2274  
2275          $systemcontext = context_system::instance();
2276  
2277          $params = array(
2278              'userid' => $userid,
2279              'limitfrom' => $limitfrom,
2280              'limitnum' => $limitnum
2281          );
2282          $params = self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
2283          self::validate_context($systemcontext);
2284  
2285          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2286              throw new moodle_exception('You do not have permission to perform this action.');
2287          }
2288  
2289          $contacts = \core_message\api::get_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
2290          $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
2291  
2292          $renderer = $PAGE->get_renderer('core_message');
2293          return $contacts->export_for_template($renderer);
2294      }
2295  
2296      /**
2297       * The messagearea contacts return structure.
2298       *
2299       * @deprecated since 3.6
2300       * @return external_single_structure
2301       * @since 3.2
2302       */
2303      public static function data_for_messagearea_contacts_returns() {
2304          return self::data_for_messagearea_conversations_returns();
2305      }
2306  
2307      /**
2308       * Marking the method as deprecated.
2309       *
2310       * @return bool
2311       */
2312      public static function data_for_messagearea_contacts_is_deprecated() {
2313          return true;
2314      }
2315  
2316      /**
2317       * The messagearea messages parameters.
2318       *
2319       * @deprecated since 3.6
2320       * @return external_function_parameters
2321       * @since 3.2
2322       */
2323      public static function data_for_messagearea_messages_parameters() {
2324          return new external_function_parameters(
2325              array(
2326                  'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2327                  'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2328                  'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2329                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
2330                  'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
2331                  'timefrom' => new external_value(PARAM_INT,
2332                      'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
2333              )
2334          );
2335      }
2336  
2337      /**
2338       * Get messagearea messages.
2339       *
2340       * @deprecated since 3.6
2341       * @param int $currentuserid The current user's id
2342       * @param int $otheruserid The other user's id
2343       * @param int $limitfrom
2344       * @param int $limitnum
2345       * @param boolean $newest
2346       * @return stdClass
2347       * @throws moodle_exception
2348       * @since 3.2
2349       */
2350      public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
2351                                                           $newest = false, $timefrom = 0) {
2352          global $CFG, $PAGE, $USER;
2353  
2354          // Check if messaging is enabled.
2355          if (empty($CFG->messaging)) {
2356              throw new moodle_exception('disabled', 'message');
2357          }
2358  
2359          $systemcontext = context_system::instance();
2360  
2361          $params = array(
2362              'currentuserid' => $currentuserid,
2363              'otheruserid' => $otheruserid,
2364              'limitfrom' => $limitfrom,
2365              'limitnum' => $limitnum,
2366              'newest' => $newest,
2367              'timefrom' => $timefrom,
2368          );
2369          $params = self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
2370          self::validate_context($systemcontext);
2371  
2372          if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2373              throw new moodle_exception('You do not have permission to perform this action.');
2374          }
2375  
2376          if ($params['newest']) {
2377              $sort = 'timecreated DESC';
2378          } else {
2379              $sort = 'timecreated ASC';
2380          }
2381  
2382          // We need to enforce a one second delay on messages to avoid race conditions of current
2383          // messages still being sent.
2384          //
2385          // There is a chance that we could request messages before the current time's
2386          // second has elapsed and while other messages are being sent in that same second. In which
2387          // case those messages will be lost.
2388          //
2389          // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
2390          if (!empty($params['timefrom'])) {
2391              $timeto = time() - 1;
2392          } else {
2393              $timeto = 0;
2394          }
2395  
2396          // No requesting messages from the current time, as stated above.
2397          if ($params['timefrom'] == time()) {
2398              $messages = [];
2399          } else {
2400              $messages = \core_message\api::get_messages($params['currentuserid'], $params['otheruserid'], $params['limitfrom'],
2401                                                          $params['limitnum'], $sort, $params['timefrom'], $timeto);
2402          }
2403  
2404          $messages = new \core_message\output\messagearea\messages($params['currentuserid'], $params['otheruserid'], $messages);
2405  
2406          $renderer = $PAGE->get_renderer('core_message');
2407          return $messages->export_for_template($renderer);
2408      }
2409  
2410      /**
2411       * The messagearea messages return structure.
2412       *
2413       * @deprecated since 3.6
2414       * @return external_single_structure
2415       * @since 3.2
2416       */
2417      public static function data_for_messagearea_messages_returns() {
2418          return new external_single_structure(
2419              array(
2420                  'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
2421                      the messages on behalf of?'),
2422                  'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2423                  'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2424                  'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
2425                  'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2426                  'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2427                  'messages' => new external_multiple_structure(
2428                      self::get_messagearea_message_structure()
2429                  ),
2430                  'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
2431              )
2432          );
2433      }
2434  
2435      /**
2436       * Marking the method as deprecated.
2437       *
2438       * @return bool
2439       */
2440      public static function data_for_messagearea_messages_is_deprecated() {
2441          return true;
2442      }
2443  
2444      /**
2445       * The conversation messages parameters.
2446       *
2447       * @return external_function_parameters
2448       * @since 3.6
2449       */
2450      public static function get_conversation_messages_parameters() {
2451          return new external_function_parameters(
2452              array(
2453                  'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2454                  'convid' => new external_value(PARAM_INT, 'The conversation id'),
2455                  'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2456                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
2457                  'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
2458                  'timefrom' => new external_value(PARAM_INT,
2459                      'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
2460              )
2461          );
2462      }
2463  
2464      /**
2465       * Get conversation messages.
2466       *
2467       * @param  int $currentuserid The current user's id.
2468       * @param  int $convid The conversation id.
2469       * @param  int $limitfrom Return a subset of records, starting at this point (optional).
2470       * @param  int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
2471       * @param  bool $newest True for getting first newest messages, false otherwise.
2472       * @param  int  $timefrom The time from the conversation messages to get.
2473       * @return array The messages and members who have sent some of these messages.
2474       * @throws moodle_exception
2475       * @since 3.6
2476       */
2477      public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
2478                                                           bool $newest = false, int $timefrom = 0) {
2479          global $CFG, $USER;
2480  
2481          // Check if messaging is enabled.
2482          if (empty($CFG->messaging)) {
2483              throw new moodle_exception('disabled', 'message');
2484          }
2485  
2486          $systemcontext = context_system::instance();
2487  
2488          $params = array(
2489              'currentuserid' => $currentuserid,
2490              'convid' => $convid,
2491              'limitfrom' => $limitfrom,
2492              'limitnum' => $limitnum,
2493              'newest' => $newest,
2494              'timefrom' => $timefrom,
2495          );
2496          $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
2497          self::validate_context($systemcontext);
2498  
2499          if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2500              throw new moodle_exception('You do not have permission to perform this action.');
2501          }
2502  
2503          // Check that the user belongs to the conversation.
2504          if (!\core_message\api::is_user_in_conversation($params['currentuserid'], $params['convid'])) {
2505              throw new moodle_exception('User is not part of conversation.');
2506          }
2507  
2508          $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
2509  
2510          // We need to enforce a one second delay on messages to avoid race conditions of current
2511          // messages still being sent.
2512          //
2513          // There is a chance that we could request messages before the current time's
2514          // second has elapsed and while other messages are being sent in that same second. In which
2515          // case those messages will be lost.
2516          //
2517          // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
2518          $timeto = empty($params['timefrom']) ? 0 : time() - 1;
2519  
2520          // No requesting messages from the current time, as stated above.
2521          if ($params['timefrom'] == time()) {
2522              $messages = [];
2523          } else {
2524              $messages = \core_message\api::get_conversation_messages(
2525                  $params['currentuserid'],
2526                  $params['convid'],
2527                  $params['limitfrom'],
2528                  $params['limitnum'],
2529                  $sort,
2530                  $params['timefrom'],
2531                  $timeto);
2532          }
2533  
2534          return $messages;
2535      }
2536  
2537      /**
2538       * The messagearea messages return structure.
2539       *
2540       * @return external_single_structure
2541       * @since 3.6
2542       */
2543      public static function get_conversation_messages_returns() {
2544          return new external_single_structure(
2545              array(
2546                  'id' => new external_value(PARAM_INT, 'The conversation id'),
2547                  'members' => new external_multiple_structure(
2548                      self::get_conversation_member_structure()
2549                  ),
2550                  'messages' => new external_multiple_structure(
2551                      self::get_conversation_message_structure()
2552                  ),
2553              )
2554          );
2555      }
2556  
2557      /**
2558       * The user contacts return parameters.
2559       *
2560       * @return external_function_parameters
2561       */
2562      public static function get_user_contacts_parameters() {
2563          return new external_function_parameters(
2564              array(
2565                  'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
2566                  'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2567                  'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
2568              )
2569          );
2570      }
2571  
2572      /**
2573       * Get user contacts.
2574       *
2575       * @param int $userid The id of the user who we are viewing conversations for
2576       * @param int $limitfrom
2577       * @param int $limitnum
2578       * @return array
2579       * @throws moodle_exception
2580       */
2581      public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
2582          global $CFG, $USER;
2583  
2584          // Check if messaging is enabled.
2585          if (empty($CFG->messaging)) {
2586              throw new moodle_exception('disabled', 'message');
2587          }
2588  
2589          $systemcontext = context_system::instance();
2590  
2591          $params = array(
2592              'userid' => $userid,
2593              'limitfrom' => $limitfrom,
2594              'limitnum' => $limitnum
2595          );
2596          $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
2597          self::validate_context($systemcontext);
2598  
2599          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2600              throw new moodle_exception('You do not have permission to perform this action.');
2601          }
2602  
2603          return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
2604      }
2605  
2606      /**
2607       * The user contacts return structure.
2608       *
2609       * @return external_multiple_structure
2610       */
2611      public static function get_user_contacts_returns() {
2612          return new external_multiple_structure(
2613              self::get_conversation_member_structure()
2614          );
2615      }
2616  
2617      /**
2618       * The get most recent message return parameters.
2619       *
2620       * @deprecated since 3.6
2621       * @return external_function_parameters
2622       * @since 3.2
2623       */
2624      public static function data_for_messagearea_get_most_recent_message_parameters() {
2625          return new external_function_parameters(
2626              array(
2627                  'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2628                  'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2629              )
2630          );
2631      }
2632  
2633      /**
2634       * Get the most recent message in a conversation.
2635       *
2636       * @deprecated since 3.6
2637       * @param int $currentuserid The current user's id
2638       * @param int $otheruserid The other user's id
2639       * @return stdClass
2640       * @throws moodle_exception
2641       * @since 3.2
2642       */
2643      public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
2644          global $CFG, $PAGE, $USER;
2645  
2646          // Check if messaging is enabled.
2647          if (empty($CFG->messaging)) {
2648              throw new moodle_exception('disabled', 'message');
2649          }
2650  
2651          $systemcontext = context_system::instance();
2652  
2653          $params = array(
2654              'currentuserid' => $currentuserid,
2655              'otheruserid' => $otheruserid
2656          );
2657          $params = self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
2658          self::validate_context($systemcontext);
2659  
2660          if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2661              throw new moodle_exception('You do not have permission to perform this action.');
2662          }
2663  
2664          $message = \core_message\api::get_most_recent_message($params['currentuserid'], $params['otheruserid']);
2665          $message = new \core_message\output\messagearea\message($message);
2666  
2667          $renderer = $PAGE->get_renderer('core_message');
2668          return $message->export_for_template($renderer);
2669      }
2670  
2671      /**
2672       * The get most recent message return structure.
2673       *
2674       * @deprecated since 3.6
2675       * @return external_single_structure
2676       * @since 3.2
2677       */
2678      public static function data_for_messagearea_get_most_recent_message_returns() {
2679          return self::get_messagearea_message_structure();
2680      }
2681  
2682      /**
2683       * Marking the method as deprecated.
2684       *
2685       * @return bool
2686       */
2687      public static function data_for_messagearea_get_most_recent_message_is_deprecated() {
2688          return true;
2689      }
2690  
2691      /**
2692       * The get profile parameters.
2693       *
2694       * @deprecated since 3.6
2695       * @return external_function_parameters
2696       * @since 3.2
2697       */
2698      public static function data_for_messagearea_get_profile_parameters() {
2699          return new external_function_parameters(
2700              array(
2701                  'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2702                  'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
2703              )
2704          );
2705      }
2706  
2707      /**
2708       * Get the profile information for a contact.
2709       *
2710       * @deprecated since 3.6
2711       * @param int $currentuserid The current user's id
2712       * @param int $otheruserid The id of the user whose profile we are viewing
2713       * @return stdClass
2714       * @throws moodle_exception
2715       * @since 3.2
2716       */
2717      public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
2718          global $CFG, $PAGE, $USER;
2719  
2720          // Check if messaging is enabled.
2721          if (empty($CFG->messaging)) {
2722              throw new moodle_exception('disabled', 'message');
2723          }
2724  
2725          $systemcontext = context_system::instance();
2726  
2727          $params = array(
2728              'currentuserid' => $currentuserid,
2729              'otheruserid' => $otheruserid
2730          );
2731          $params = self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
2732          self::validate_context($systemcontext);
2733  
2734          if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2735              throw new moodle_exception('You do not have permission to perform this action.');
2736          }
2737  
2738          $profile = \core_message\api::get_profile($params['currentuserid'], $params['otheruserid']);
2739          $profile = new \core_message\output\messagearea\profile($profile);
2740  
2741          $renderer = $PAGE->get_renderer('core_message');
2742          return $profile->export_for_template($renderer);
2743      }
2744  
2745      /**
2746       * The get profile return structure.
2747       *
2748       * @deprecated since 3.6
2749       * @return external_single_structure
2750       * @since 3.2
2751       */
2752      public static function data_for_messagearea_get_profile_returns() {
2753          return new external_single_structure(
2754              array(
2755                  'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
2756                  'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
2757                  'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
2758                  'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
2759                  'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
2760                  'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
2761                  'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
2762                  'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2763                  'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2764                  'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
2765                  'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
2766              )
2767          );
2768      }
2769  
2770      /**
2771       * Marking the method as deprecated.
2772       *
2773       * @return bool
2774       */
2775      public static function data_for_messagearea_get_profile_is_deprecated() {
2776          return true;
2777      }
2778  
2779      /**
2780       * Get contacts parameters description.
2781       *
2782       * @deprecated since 3.6
2783       * @return external_function_parameters
2784       * @since Moodle 2.5
2785       */
2786      public static function get_contacts_parameters() {
2787          return new external_function_parameters(array());
2788      }
2789  
2790      /**
2791       * Get contacts.
2792       *
2793       * @deprecated since 3.6
2794       * @return external_description
2795       * @since Moodle 2.5
2796       */
2797      public static function get_contacts() {
2798          global $CFG, $PAGE, $USER;
2799  
2800          // Check if messaging is enabled.
2801          if (empty($CFG->messaging)) {
2802              throw new moodle_exception('disabled', 'message');
2803          }
2804  
2805          require_once($CFG->dirroot . '/user/lib.php');
2806  
2807          $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
2808          $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
2809          foreach ($contacts as $contact) {
2810              // Set the mode.
2811              $mode = 'offline';
2812              if (\core_message\helper::is_online($contact->lastaccess)) {
2813                  $mode = 'online';
2814              }
2815  
2816              $newcontact = array(
2817                  'id' => $contact->id,
2818                  'fullname' => fullname($contact),
2819                  'unread' => $contact->messagecount
2820              );
2821  
2822              $userpicture = new user_picture($contact);
2823              $userpicture->size = 1; // Size f1.
2824              $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2825              $userpicture->size = 0; // Size f2.
2826              $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2827  
2828              $allcontacts[$mode][$contact->id] = $newcontact;
2829          }
2830  
2831          $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
2832          foreach ($strangers as $contact) {
2833              $newcontact = array(
2834                  'id' => $contact->id,
2835                  'fullname' => fullname($contact),
2836                  'unread' => $contact->messagecount
2837              );
2838  
2839              $userpicture = new user_picture($contact);
2840              $userpicture->size = 1; // Size f1.
2841              $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2842              $userpicture->size = 0; // Size f2.
2843              $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2844  
2845              $allcontacts['strangers'][$contact->id] = $newcontact;
2846          }
2847  
2848          // Add noreply user and support user to the list, if they don't exist.
2849          $supportuser = core_user::get_support_user();
2850          if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
2851              $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
2852              if ($supportuser->messagecount > 0) {
2853                  $supportuser->fullname = fullname($supportuser);
2854                  $supportuser->unread = $supportuser->messagecount;
2855                  $allcontacts['strangers'][$supportuser->id] = $supportuser;
2856              }
2857          }
2858  
2859          $noreplyuser = core_user::get_noreply_user();
2860          if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
2861              $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
2862              if ($noreplyuser->messagecount > 0) {
2863                  $noreplyuser->fullname = fullname($noreplyuser);
2864                  $noreplyuser->unread = $noreplyuser->messagecount;
2865                  $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
2866              }
2867          }
2868  
2869          return $allcontacts;
2870      }
2871  
2872      /**
2873       * Get contacts return description.
2874       *
2875       * @deprecated since 3.6
2876       * @return external_description
2877       * @since Moodle 2.5
2878       */
2879      public static function get_contacts_returns() {
2880          return new external_single_structure(
2881              array(
2882                  'online' => new external_multiple_structure(
2883                      new external_single_structure(
2884                          array(
2885                              'id' => new external_value(PARAM_INT, 'User ID'),
2886                              'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2887                              'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2888                              'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2889                              'unread' => new external_value(PARAM_INT, 'Unread message count')
2890                          )
2891                      ),
2892                      'List of online contacts'
2893                  ),
2894                  'offline' => new external_multiple_structure(
2895                      new external_single_structure(
2896                          array(
2897                              'id' => new external_value(PARAM_INT, 'User ID'),
2898                              'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2899                              'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2900                              'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2901                              'unread' => new external_value(PARAM_INT, 'Unread message count')
2902                          )
2903                      ),
2904                      'List of offline contacts'
2905                  ),
2906                  'strangers' => new external_multiple_structure(
2907                      new external_single_structure(
2908                          array(
2909                              'id' => new external_value(PARAM_INT, 'User ID'),
2910                              'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2911                              'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2912                              'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2913                              'unread' => new external_value(PARAM_INT, 'Unread message count')
2914                          )
2915                      ),
2916                      'List of users that are not in the user\'s contact list but have sent a message'
2917                  )
2918              )
2919          );
2920      }
2921  
2922      /**
2923       * Marking the method as deprecated.
2924       *
2925       * @return bool
2926       */
2927      public static function get_contacts_is_deprecated() {
2928          return true;
2929      }
2930  
2931      /**
2932       * Search contacts parameters description.
2933       *
2934       * @return external_function_parameters
2935       * @since Moodle 2.5
2936       */
2937      public static function search_contacts_parameters() {
2938          return new external_function_parameters(
2939              array(
2940                  'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2941                  'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2942                      VALUE_DEFAULT, false)
2943              )
2944          );
2945      }
2946  
2947      /**
2948       * Search contacts.
2949       *
2950       * @param string $searchtext query string.
2951       * @param bool $onlymycourses limit the search to the user's courses only.
2952       * @return external_description
2953       * @since Moodle 2.5
2954       */
2955      public static function search_contacts($searchtext, $onlymycourses = false) {
2956          global $CFG, $USER, $PAGE;
2957          require_once($CFG->dirroot . '/user/lib.php');
2958  
2959          // Check if messaging is enabled.
2960          if (empty($CFG->messaging)) {
2961              throw new moodle_exception('disabled', 'message');
2962          }
2963  
2964          require_once($CFG->libdir . '/enrollib.php');
2965  
2966          $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2967          $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2968  
2969          // Extra validation, we do not allow empty queries.
2970          if ($params['searchtext'] === '') {
2971              throw new moodle_exception('querystringcannotbeempty');
2972          }
2973  
2974          $courseids = array();
2975          if ($params['onlymycourses']) {
2976              $mycourses = enrol_get_my_courses(array('id'));
2977              foreach ($mycourses as $mycourse) {
2978                  $courseids[] = $mycourse->id;
2979              }
2980          } else {
2981              $courseids[] = SITEID;
2982          }
2983  
2984          // Retrieving the users matching the query.
2985          $users = message_search_users($courseids, $params['searchtext']);
2986          $results = array();
2987          foreach ($users as $user) {
2988              $results[$user->id] = $user;
2989          }
2990  
2991          // Reorganising information.
2992          foreach ($results as &$user) {
2993              $newuser = array(
2994                  'id' => $user->id,
2995                  'fullname' => fullname($user)
2996              );
2997  
2998              // Avoid undefined property notice as phone not specified.
2999              $user->phone1 = null;
3000              $user->phone2 = null;
3001  
3002              $userpicture = new user_picture($user);
3003              $userpicture->size = 1; // Size f1.
3004              $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
3005              $userpicture->size = 0; // Size f2.
3006              $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
3007  
3008              $user = $newuser;
3009          }
3010  
3011          return $results;
3012      }
3013  
3014      /**
3015       * Search contacts return description.
3016       *
3017       * @return external_description
3018       * @since Moodle 2.5
3019       */
3020      public static function search_contacts_returns() {
3021          return new external_multiple_structure(
3022              new external_single_structure(
3023                  array(
3024                      'id' => new external_value(PARAM_INT, 'User ID'),
3025                      'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
3026                      'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
3027                      'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
3028                  )
3029              ),
3030              'List of contacts'
3031          );
3032      }
3033  
3034      /**
3035       * Get messages parameters description.
3036       *
3037       * @return external_function_parameters
3038       * @since 2.8
3039       */
3040      public static function get_messages_parameters() {
3041          return new external_function_parameters(
3042              array(
3043                  'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3044                  'useridfrom' => new external_value(
3045                      PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
3046                      VALUE_DEFAULT, 0),
3047                  'type' => new external_value(
3048                      PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
3049                      VALUE_DEFAULT, 'both'),
3050                  'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
3051                  'newestfirst' => new external_value(
3052                      PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
3053                      VALUE_DEFAULT, true),
3054                  'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
3055                  'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
3056              )
3057          );
3058      }
3059  
3060      /**
3061       * Get messages function implementation.
3062       *
3063       * @since  2.8
3064       * @throws invalid_parameter_exception
3065       * @throws moodle_exception
3066       * @param  int      $useridto       the user id who received the message
3067       * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
3068       * @param  string   $type           type of message to return, expected values: notifications, conversations and both
3069       * @param  bool     $read           true for retreiving read messages, false for unread
3070       * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
3071       * @param  int      $limitfrom      limit from
3072       * @param  int      $limitnum       limit num
3073       * @return external_description
3074       */
3075      public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
3076                                          $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
3077          global $CFG, $USER;
3078  
3079          $warnings = array();
3080  
3081          $params = array(
3082              'useridto' => $useridto,
3083              'useridfrom' => $useridfrom,
3084              'type' => $type,
3085              'read' => $read,
3086              'newestfirst' => $newestfirst,
3087              'limitfrom' => $limitfrom,
3088              'limitnum' => $limitnum
3089          );
3090  
3091          $params = self::validate_parameters(self::get_messages_parameters(), $params);
3092  
3093          $context = context_system::instance();
3094          self::validate_context($context);
3095  
3096          $useridto = $params['useridto'];
3097          $useridfrom = $params['useridfrom'];
3098          $type = $params['type'];
3099          $read = $params['read'];
3100          $newestfirst = $params['newestfirst'];
3101          $limitfrom = $params['limitfrom'];
3102          $limitnum = $params['limitnum'];
3103  
3104          $allowedvalues = array('notifications', 'conversations', 'both');
3105          if (!in_array($type, $allowedvalues)) {
3106              throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
3107                  'allowed values are: ' . implode(',', $allowedvalues));
3108          }
3109  
3110          // Check if private messaging between users is allowed.
3111          if (empty($CFG->messaging)) {
3112              // If we are retreiving only conversations, and messaging is disabled, throw an exception.
3113              if ($type == "conversations") {
3114                  throw new moodle_exception('disabled', 'message');
3115              }
3116              if ($type == "both") {
3117                  $warning = array();
3118                  $warning['item'] = 'message';
3119                  $warning['itemid'] = $USER->id;
3120                  $warning['warningcode'] = '1';
3121                  $warning['message'] = 'Private messages (conversations) are not enabled in this site.
3122                      Only notifications will be returned';
3123                  $warnings[] = $warning;
3124              }
3125          }
3126  
3127          if (!empty($useridto)) {
3128              if (core_user::is_real_user($useridto)) {
3129                  $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3130              } else {
3131                  throw new moodle_exception('invaliduser');
3132              }
3133          }
3134  
3135          if (!empty($useridfrom)) {
3136              // We use get_user here because the from user can be the noreply or support user.
3137              $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3138          }
3139  
3140          // Check if the current user is the sender/receiver or just a privileged user.
3141          if ($useridto != $USER->id and $useridfrom != $USER->id and
3142               !has_capability('moodle/site:readallmessages', $context)) {
3143              throw new moodle_exception('accessdenied', 'admin');
3144          }
3145  
3146          // Which type of messages to retrieve.
3147          $notifications = -1;
3148          if ($type != 'both') {
3149              $notifications = ($type == 'notifications') ? 1 : 0;
3150          }
3151  
3152          $orderdirection = $newestfirst ? 'DESC' : 'ASC';
3153          $sort = "mr.timecreated $orderdirection";
3154  
3155          if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
3156              $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
3157  
3158              // In some cases, we don't need to get the to/from user objects from the sql query.
3159              $userfromfullname = '';
3160              $usertofullname = '';
3161  
3162              // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
3163              if (!empty($useridto)) {
3164                  $usertofullname = fullname($userto, $canviewfullname);
3165                  // The user from may or may not be filled.
3166                  if (!empty($useridfrom)) {
3167                      $userfromfullname = fullname($userfrom, $canviewfullname);
3168                  }
3169              } else {
3170                  // If the useridto field is empty, the useridfrom must be filled.
3171                  $userfromfullname = fullname($userfrom, $canviewfullname);
3172              }
3173              foreach ($messages as $mid => $message) {
3174  
3175                  // Do not return deleted messages.
3176                  if (!$message->notification) {
3177                      if (($useridto == $USER->id and $message->timeusertodeleted) or
3178                          ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
3179                          unset($messages[$mid]);
3180                          continue;
3181                      }
3182                  }
3183  
3184                  // We need to get the user from the query.
3185                  if (empty($userfromfullname)) {
3186                      // Check for non-reply and support users.
3187                      if (core_user::is_real_user($message->useridfrom)) {
3188                          $user = new stdClass();
3189                          $user = username_load_fields_from_object($user, $message, 'userfrom');
3190                          $message->userfromfullname = fullname($user, $canviewfullname);
3191                      } else {
3192                          $user = core_user::get_user($message->useridfrom);
3193                          $message->userfromfullname = fullname($user, $canviewfullname);
3194                      }
3195                  } else {
3196                      $message->userfromfullname = $userfromfullname;
3197                  }
3198  
3199                  // We need to get the user from the query.
3200                  if (empty($usertofullname)) {
3201                      $user = new stdClass();
3202                      $user = username_load_fields_from_object($user, $message, 'userto');
3203                      $message->usertofullname = fullname($user, $canviewfullname);
3204                  } else {
3205                      $message->usertofullname = $usertofullname;
3206                  }
3207  
3208                  $message->text = message_format_message_text($message);
3209                  $messages[$mid] = (array) $message;
3210              }
3211          }
3212  
3213          $results = array(
3214              'messages' => $messages,
3215              'warnings' => $warnings
3216          );
3217  
3218          return $results;
3219      }
3220  
3221      /**
3222       * Get messages return description.
3223       *
3224       * @return external_single_structure
3225       * @since 2.8
3226       */
3227      public static function get_messages_returns() {
3228          return new external_single_structure(
3229              array(
3230                  'messages' => new external_multiple_structure(
3231                      new external_single_structure(
3232                          array(
3233                              'id' => new external_value(PARAM_INT, 'Message id'),
3234                              'useridfrom' => new external_value(PARAM_INT, 'User from id'),
3235                              'useridto' => new external_value(PARAM_INT, 'User to id'),
3236                              'subject' => new external_value(PARAM_TEXT, 'The message subject'),
3237                              'text' => new external_value(PARAM_RAW, 'The message text formated'),
3238                              'fullmessage' => new external_value(PARAM_RAW, 'The message'),
3239                              'fullmessageformat' => new external_format_value('fullmessage'),
3240                              'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
3241                              'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
3242                              'notification' => new external_value(PARAM_INT, 'Is a notification?'),
3243                              'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
3244                              'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
3245                              'timecreated' => new external_value(PARAM_INT, 'Time created'),
3246                              'timeread' => new external_value(PARAM_INT, 'Time read'),
3247                              'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
3248                              'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
3249                              'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
3250                                  VALUE_OPTIONAL),
3251                              'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
3252                              'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
3253                                  The data here is serialised using json_encode().', VALUE_OPTIONAL),
3254                          ), 'message'
3255                      )
3256                  ),
3257                  'warnings' => new external_warnings()
3258              )
3259          );
3260      }
3261  
3262      /**
3263       * Mark all notifications as read parameters description.
3264       *
3265       * @return external_function_parameters
3266       * @since 3.2
3267       */
3268      public static function mark_all_notifications_as_read_parameters() {
3269          return new external_function_parameters(
3270              array(
3271                  'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3272                  'useridfrom' => new external_value(
3273                      PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
3274                      VALUE_DEFAULT, 0),
3275                  'timecreatedto' => new external_value(
3276                      PARAM_INT, 'mark messages created before this time as read, 0 for all messages',
3277                      VALUE_DEFAULT, 0),
3278              )
3279          );
3280      }
3281  
3282      /**
3283       * Mark all notifications as read function.
3284       *
3285       * @since  3.2
3286       * @throws invalid_parameter_exception
3287       * @throws moodle_exception
3288       * @param  int      $useridto       the user id who received the message
3289       * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
3290       * @param  int      $timecreatedto  mark message created before this time as read, 0 for all messages
3291       * @return external_description
3292       */
3293      public static function mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto = 0) {
3294          global $USER;
3295  
3296          $params = self::validate_parameters(
3297              self::mark_all_notifications_as_read_parameters(),
3298              array(
3299                  'useridto' => $useridto,
3300                  'useridfrom' => $useridfrom,
3301                  'timecreatedto' => $timecreatedto,
3302              )
3303          );
3304  
3305          $context = context_system::instance();
3306          self::validate_context($context);
3307  
3308          $useridto = $params['useridto'];
3309          $useridfrom = $params['useridfrom'];
3310          $timecreatedto = $params['timecreatedto'];
3311  
3312          if (!empty($useridto)) {
3313              if (core_user::is_real_user($useridto)) {
3314                  $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3315              } else {
3316                  throw new moodle_exception('invaliduser');
3317              }
3318          }
3319  
3320          if (!empty($useridfrom)) {
3321              // We use get_user here because the from user can be the noreply or support user.
3322              $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3323          }
3324  
3325          // Check if the current user is the sender/receiver or just a privileged user.
3326          if ($useridto != $USER->id and $useridfrom != $USER->id and
3327              // The deleteanymessage cap seems more reasonable here than readallmessages.
3328               !has_capability('moodle/site:deleteanymessage', $context)) {
3329              throw new moodle_exception('accessdenied', 'admin');
3330          }
3331  
3332          \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto);
3333  
3334          return true;
3335      }
3336  
3337      /**
3338       * Mark all notifications as read return description.
3339       *
3340       * @return external_single_structure
3341       * @since 3.2
3342       */
3343      public static function mark_all_notifications_as_read_returns() {
3344          return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
3345      }
3346  
3347      /**
3348       * Get unread conversations count parameters description.
3349       *
3350       * @return external_function_parameters
3351       * @since 3.2
3352       */
3353      public static function get_unread_conversations_count_parameters() {
3354          return new external_function_parameters(
3355              array(
3356                  'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3357              )
3358          );
3359      }
3360  
3361      /**
3362       * Get unread messages count function.
3363       *
3364       * @since  3.2
3365       * @throws invalid_parameter_exception
3366       * @throws moodle_exception
3367       * @param  int      $useridto       the user id who received the message
3368       * @return external_description
3369       */
3370      public static function get_unread_conversations_count($useridto) {
3371          global $USER, $CFG;
3372  
3373          // Check if messaging is enabled.
3374          if (empty($CFG->messaging)) {
3375              throw new moodle_exception('disabled', 'message');
3376          }
3377  
3378          $params = self::validate_parameters(
3379              self::get_unread_conversations_count_parameters(),
3380              array('useridto' => $useridto)
3381          );
3382  
3383          $context = context_system::instance();
3384          self::validate_context($context);
3385  
3386          $useridto = $params['useridto'];
3387  
3388          if (!empty($useridto)) {
3389              if (core_user::is_real_user($useridto)) {
3390                  $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3391              } else {
3392                  throw new moodle_exception('invaliduser');
3393              }
3394          } else {
3395              $useridto = $USER->id;
3396          }
3397  
3398          // Check if the current user is the receiver or just a privileged user.
3399          if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
3400              throw new moodle_exception('accessdenied', 'admin');
3401          }
3402  
3403          return \core_message\api::count_unread_conversations($userto);
3404      }
3405  
3406      /**
3407       * Get unread conversations count return description.
3408       *
3409       * @return external_single_structure
3410       * @since 3.2
3411       */
3412      public static function get_unread_conversations_count_returns() {
3413          return new external_value(PARAM_INT, 'The count of unread messages for the user');
3414      }
3415  
3416      /**
3417       * Get blocked users parameters description.
3418       *
3419       * @return external_function_parameters
3420       * @since 2.9
3421       */
3422      public static function get_blocked_users_parameters() {
3423          return new external_function_parameters(
3424              array(
3425                  'userid' => new external_value(PARAM_INT,
3426                                  'the user whose blocked users we want to retrieve',
3427                                  VALUE_REQUIRED),
3428              )
3429          );
3430      }
3431  
3432      /**
3433       * Retrieve a list of users blocked
3434       *
3435       * @param  int $userid the user whose blocked users we want to retrieve
3436       * @return external_description
3437       * @since 2.9
3438       */
3439      public static function get_blocked_users($userid) {
3440          global $CFG, $USER, $PAGE;
3441  
3442          // Warnings array, it can be empty at the end but is mandatory.
3443          $warnings = array();
3444  
3445          // Validate params.
3446          $params = array(
3447              'userid' => $userid
3448          );
3449          $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
3450          $userid = $params['userid'];
3451  
3452          // Validate context.
3453          $context = context_system::instance();
3454          self::validate_context($context);
3455  
3456          // Check if private messaging between users is allowed.
3457          if (empty($CFG->messaging)) {
3458              throw new moodle_exception('disabled', 'message');
3459          }
3460  
3461          $user = core_user::get_user($userid, '*', MUST_EXIST);
3462          core_user::require_active_user($user);
3463  
3464          // Check if we have permissions for retrieve the information.
3465          $capability = 'moodle/site:manageallmessaging';
3466          if (($USER->id != $userid) && !has_capability($capability, $context)) {
3467              throw new required_capability_exception($context, $capability, 'nopermissions', '');
3468          }
3469  
3470          // Now, we can get safely all the blocked users.
3471          $users = \core_message\api::get_blocked_users($user->id);
3472  
3473          $blockedusers = array();
3474          foreach ($users as $user) {
3475              $newuser = array(
3476                  'id' => $user->id,
3477                  'fullname' => fullname($user),
3478              );
3479  
3480              $userpicture = new user_picture($user);
3481              $userpicture->size = 1; // Size f1.
3482              $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
3483  
3484              $blockedusers[] = $newuser;
3485          }
3486  
3487          $results = array(
3488              'users' => $blockedusers,
3489              'warnings' => $warnings
3490          );
3491          return $results;
3492      }
3493  
3494      /**
3495       * Get blocked users return description.
3496       *
3497       * @return external_single_structure
3498       * @since 2.9
3499       */
3500      public static function get_blocked_users_returns() {
3501          return new external_single_structure(
3502              array(
3503                  'users' => new external_multiple_structure(
3504                      new external_single_structure(
3505                          array(
3506                              'id' => new external_value(PARAM_INT, 'User ID'),
3507                              'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
3508                              'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
3509                          )
3510                      ),
3511                      'List of blocked users'
3512                  ),
3513                  'warnings' => new external_warnings()
3514              )
3515          );
3516      }
3517  
3518      /**
3519       * Returns description of method parameters
3520       *
3521       * @return external_function_parameters
3522       * @since 2.9
3523       */
3524      public static function mark_message_read_parameters() {
3525          return new external_function_parameters(
3526              array(
3527                  'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
3528                  'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
3529                      VALUE_DEFAULT, 0)
3530              )
3531          );
3532      }
3533  
3534      /**
3535       * Mark a single message as read, trigger message_viewed event
3536       *
3537       * @param  int $messageid id of the message (in the message table)
3538       * @param  int $timeread timestamp for when the message should be marked read
3539       * @return external_description
3540       * @throws invalid_parameter_exception
3541       * @throws moodle_exception
3542       * @since 2.9
3543       */
3544      public static function mark_message_read($messageid, $timeread) {
3545          global $CFG, $DB, $USER;
3546  
3547          // Check if private messaging between users is allowed.
3548          if (empty($CFG->messaging)) {
3549              throw new moodle_exception('disabled', 'message');
3550          }
3551  
3552          // Warnings array, it can be empty at the end but is mandatory.
3553          $warnings = array();
3554  
3555          // Validate params.
3556          $params = array(
3557              'messageid' => $messageid,
3558              'timeread' => $timeread
3559          );
3560          $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
3561  
3562          if (empty($params['timeread'])) {
3563              $timeread = time();
3564          } else {
3565              $timeread = $params['timeread'];
3566          }
3567  
3568          // Validate context.
3569          $context = context_system::instance();
3570          self::validate_context($context);
3571  
3572          $sql = "SELECT m.*, mcm.userid as useridto
3573                    FROM {messages} m
3574              INNER JOIN {message_conversations} mc
3575                      ON m.conversationid = mc.id
3576              INNER JOIN {message_conversation_members} mcm
3577                      ON mcm.conversationid = mc.id
3578               LEFT JOIN {message_user_actions} mua
3579                      ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
3580                   WHERE mua.id is NULL
3581                     AND mcm.userid != m.useridfrom
3582                     AND m.id = ?";
3583          $messageparams = [];
3584          $messageparams[] = $USER->id;
3585          $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
3586          $messageparams[] = $params['messageid'];
3587          $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
3588  
3589          if ($message->useridto != $USER->id) {
3590              throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
3591          }
3592  
3593          \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
3594  
3595          $results = array(
3596              'messageid' => $message->id,
3597              'warnings' => $warnings
3598          );
3599          return $results;
3600      }
3601  
3602      /**
3603       * Returns description of method result value
3604       *
3605       * @return external_description
3606       * @since 2.9
3607       */
3608      public static function mark_message_read_returns() {
3609          return new external_single_structure(
3610              array(
3611                  'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
3612                  'warnings' => new external_warnings()
3613              )
3614          );
3615      }
3616  
3617      /**
3618       * Returns description of method parameters
3619       *
3620       * @return external_function_parameters
3621       */
3622      public static function mark_notification_read_parameters() {
3623          return new external_function_parameters(
3624              array(
3625                  'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
3626                  'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
3627                      VALUE_DEFAULT, 0)
3628              )
3629          );
3630      }
3631  
3632      /**
3633       * Mark a single notification as read.
3634       *
3635       * This will trigger a 'notification_viewed' event.
3636       *
3637       * @param int $notificationid id of the notification
3638       * @param int $timeread timestamp for when the notification should be marked read
3639       * @return external_description
3640       * @throws invalid_parameter_exception
3641       * @throws moodle_exception
3642       */
3643      public static function mark_notification_read($notificationid, $timeread) {
3644          global $CFG, $DB, $USER;
3645  
3646          // Warnings array, it can be empty at the end but is mandatory.
3647          $warnings = array();
3648  
3649          // Validate params.
3650          $params = array(
3651              'notificationid' => $notificationid,
3652              'timeread' => $timeread
3653          );
3654          $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
3655  
3656          if (empty($params['timeread'])) {
3657              $timeread = time();
3658          } else {
3659              $timeread = $params['timeread'];
3660          }
3661  
3662          // Validate context.
3663          $context = context_system::instance();
3664          self::validate_context($context);
3665  
3666          $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
3667  
3668          if ($notification->useridto != $USER->id) {
3669              throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
3670                  'notification as read');
3671          }
3672  
3673          \core_message\api::mark_notification_as_read($notification, $timeread);
3674  
3675          $results = array(
3676              'notificationid' => $notification->id,
3677              'warnings' => $warnings
3678          );
3679  
3680          return $results;
3681      }
3682  
3683      /**
3684       * Returns description of method result value
3685       *
3686       * @return external_description
3687       */
3688      public static function mark_notification_read_returns() {
3689          return new external_single_structure(
3690              array(
3691                  'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
3692                  'warnings' => new external_warnings()
3693              )
3694          );
3695      }
3696  
3697      /**
3698       * Mark all messages as read parameters description.
3699       *
3700       * @deprecated since 3.6
3701       * @return external_function_parameters
3702       * @since 3.2
3703       */
3704      public static function mark_all_messages_as_read_parameters() {
3705          return new external_function_parameters(
3706              array(
3707                  'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3708                  'useridfrom' => new external_value(
3709                      PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
3710                      VALUE_DEFAULT, 0),
3711              )
3712          );
3713      }
3714  
3715      /**
3716       * Mark all messages as read function.
3717       *
3718       * @deprecated since 3.6
3719       * @throws invalid_parameter_exception
3720       * @throws moodle_exception
3721       * @param  int      $useridto       the user id who received the message
3722       * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
3723       * @return external_description
3724       * @since  3.2
3725       */
3726      public static function mark_all_messages_as_read($useridto, $useridfrom) {
3727          global $USER, $CFG;
3728  
3729          // Check if messaging is enabled.
3730          if (empty($CFG->messaging)) {
3731              throw new moodle_exception('disabled', 'message');
3732          }
3733  
3734          $params = self::validate_parameters(
3735              self::mark_all_messages_as_read_parameters(),
3736              array(
3737                  'useridto' => $useridto,
3738                  'useridfrom' => $useridfrom,
3739              )
3740          );
3741  
3742          $context = context_system::instance();
3743          self::validate_context($context);
3744  
3745          $useridto = $params['useridto'];
3746          $useridfrom = $params['useridfrom'];
3747  
3748          if (!empty($useridto)) {
3749              if (core_user::is_real_user($useridto)) {
3750                  $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3751              } else {
3752                  throw new moodle_exception('invaliduser');
3753              }
3754          }
3755  
3756          if (!empty($useridfrom)) {
3757              // We use get_user here because the from user can be the noreply or support user.
3758              $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3759          }
3760  
3761          // Check if the current user is the sender/receiver or just a privileged user.
3762          if ($useridto != $USER->id and $useridfrom != $USER->id and
3763              // The deleteanymessage cap seems more reasonable here than readallmessages.
3764               !has_capability('moodle/site:deleteanymessage', $context)) {
3765              throw new moodle_exception('accessdenied', 'admin');
3766          }
3767  
3768          if ($useridfrom) {
3769              if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
3770                  \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
3771              }
3772          } else {
3773              \core_message\api::mark_all_messages_as_read($useridto);
3774          }
3775  
3776          return true;
3777      }
3778  
3779      /**
3780       * Mark all messages as read return description.
3781       *
3782       * @deprecated since 3.6
3783       * @return external_single_structure
3784       * @since 3.2
3785       */
3786      public static function mark_all_messages_as_read_returns() {
3787          return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
3788      }
3789  
3790      /**
3791       * Marking the method as deprecated.
3792       *
3793       * @return bool
3794       */
3795      public static function mark_all_messages_as_read_is_deprecated() {
3796          return true;
3797      }
3798  
3799      /**
3800       * Mark all conversation messages as read parameters description.
3801       *
3802       * @return external_function_parameters
3803       * @since 3.6
3804       */
3805      public static function mark_all_conversation_messages_as_read_parameters() {
3806          return new external_function_parameters(
3807              array(
3808                  'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
3809                  'conversationid' =>
3810                      new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
3811              )
3812          );
3813      }
3814  
3815      /**
3816       * Mark all conversation messages as read function.
3817       *
3818       * @param int $userid The user id of who we want to delete the conversation for
3819       * @param int $conversationid The id of the conversations
3820       * @since 3.6
3821       */
3822      public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
3823          global $CFG;
3824  
3825          // Check if messaging is enabled.
3826          if (empty($CFG->messaging)) {
3827              throw new moodle_exception('disabled', 'message');
3828          }
3829  
3830          $params = array(
3831              'userid' => $userid,
3832              'conversationid' => $conversationid,
3833          );
3834          $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
3835  
3836          $context = context_system::instance();
3837          self::validate_context($context);
3838  
3839          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3840          core_user::require_active_user($user);
3841  
3842          if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
3843              \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
3844          } else {
3845              throw new moodle_exception('accessdenied', 'admin');
3846          }
3847      }
3848  
3849      /**
3850       * Mark all conversation messages as read return description.
3851       *
3852       * @return external_warnings
3853       * @since 3.6
3854       */
3855      public static function mark_all_conversation_messages_as_read_returns() {
3856          return null;
3857      }
3858  
3859      /**
3860       * Returns description of method parameters.
3861       *
3862       * @deprecated since 3.6
3863       * @return external_function_parameters
3864       * @since 3.2
3865       */
3866      public static function delete_conversation_parameters() {
3867          return new external_function_parameters(
3868              array(
3869                  'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3870                  'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
3871              )
3872          );
3873      }
3874  
3875      /**
3876       * Deletes a conversation.
3877       *
3878       * @deprecated since 3.6
3879       * @param int $userid The user id of who we want to delete the conversation for
3880       * @param int $otheruserid The user id of the other user in the conversation
3881       * @return array
3882       * @throws moodle_exception
3883       * @since 3.2
3884       */
3885      public static function delete_conversation($userid, $otheruserid) {
3886          global $CFG;
3887  
3888          // Check if private messaging between users is allowed.
3889          if (empty($CFG->messaging)) {
3890              throw new moodle_exception('disabled', 'message');
3891          }
3892  
3893          // Warnings array, it can be empty at the end but is mandatory.
3894          $warnings = array();
3895  
3896          // Validate params.
3897          $params = array(
3898              'userid' => $userid,
3899              'otheruserid' => $otheruserid,
3900          );
3901          $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
3902  
3903          // Validate context.
3904          $context = context_system::instance();
3905          self::validate_context($context);
3906  
3907          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3908          core_user::require_active_user($user);
3909  
3910          if (!$conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']])) {
3911              return [];
3912          }
3913  
3914          if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3915              \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3916              $status = true;
3917          } else {
3918              throw new moodle_exception('You do not have permission to delete messages');
3919          }
3920  
3921          $results = array(
3922              'status' => $status,
3923              'warnings' => $warnings
3924          );
3925  
3926          return $results;
3927      }
3928  
3929      /**
3930       * Returns description of method result value.
3931       *
3932       * @deprecated since 3.6
3933       * @return external_description
3934       * @since 3.2
3935       */
3936      public static function delete_conversation_returns() {
3937          return new external_single_structure(
3938              array(
3939                  'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
3940                  'warnings' => new external_warnings()
3941              )
3942          );
3943      }
3944  
3945      /**
3946       * Marking the method as deprecated.
3947       *
3948       * @return bool
3949       */
3950      public static function delete_conversation_is_deprecated() {
3951          return true;
3952      }
3953  
3954      /**
3955       * Returns description of method parameters.
3956       *
3957       * @return external_function_parameters
3958       * @since 3.6
3959       */
3960      public static function delete_conversations_by_id_parameters() {
3961          return new external_function_parameters(
3962              array(
3963                  'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3964                  'conversationids' => new external_multiple_structure(
3965                      new external_value(PARAM_INT, 'The id of the conversation'),
3966                      'List of conversation IDs'
3967                  ),
3968              )
3969          );
3970      }
3971  
3972      /**
3973       * Deletes a conversation.
3974       *
3975       * @param int $userid The user id of who we want to delete the conversation for
3976       * @param int[] $conversationids The ids of the conversations
3977       * @return array
3978       * @throws moodle_exception
3979       * @since 3.6
3980       */
3981      public static function delete_conversations_by_id($userid, array $conversationids) {
3982          global $CFG;
3983  
3984          // Check if private messaging between users is allowed.
3985          if (empty($CFG->messaging)) {
3986              throw new moodle_exception('disabled', 'message');
3987          }
3988  
3989          // Validate params.
3990          $params = [
3991              'userid' => $userid,
3992              'conversationids' => $conversationids,
3993          ];
3994          $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
3995  
3996          // Validate context.
3997          $context = context_system::instance();
3998          self::validate_context($context);
3999  
4000          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
4001          core_user::require_active_user($user);
4002  
4003          foreach ($params['conversationids'] as $conversationid) {
4004              if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
4005                  \core_message\api::delete_conversation_by_id($user->id, $conversationid);
4006              } else {
4007                  throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
4008              }
4009          }
4010  
4011          return [];
4012      }
4013  
4014      /**
4015       * Returns description of method result value.
4016       *
4017       * @return external_description
4018       * @since 3.6
4019       */
4020      public static function delete_conversations_by_id_returns() {
4021          return new external_warnings();
4022      }
4023  
4024      /**
4025       * Returns description of method parameters
4026       *
4027       * @return external_function_parameters
4028       * @since 3.1
4029       */
4030      public static function delete_message_parameters() {
4031          return new external_function_parameters(
4032              array(
4033                  'messageid' => new external_value(PARAM_INT, 'The message id'),
4034                  'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
4035                  'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
4036              )
4037          );
4038      }
4039  
4040      /**
4041       * Deletes a message
4042       *
4043       * @param  int $messageid the message id
4044       * @param  int $userid the user id of who we want to delete the message for
4045       * @param  bool $read if is a message read (default to true)
4046       * @return external_description
4047       * @throws moodle_exception
4048       * @since 3.1
4049       */
4050      public static function delete_message($messageid, $userid, $read = true) {
4051          global $CFG;
4052  
4053          // Check if private messaging between users is allowed.
4054          if (empty($CFG->messaging)) {
4055              throw new moodle_exception('disabled', 'message');
4056          }
4057  
4058          // Warnings array, it can be empty at the end but is mandatory.
4059          $warnings = array();
4060  
4061          // Validate params.
4062          $params = array(
4063              'messageid' => $messageid,
4064              'userid' => $userid,
4065              'read' => $read
4066          );
4067          $params = self::validate_parameters(self::delete_message_parameters(), $params);
4068  
4069          // Validate context.
4070          $context = context_system::instance();
4071          self::validate_context($context);
4072  
4073          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
4074          core_user::require_active_user($user);
4075  
4076          if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
4077              $status = \core_message\api::delete_message($user->id, $params['messageid']);
4078          } else {
4079              throw new moodle_exception('You do not have permission to delete this message');
4080          }
4081  
4082          $results = array(
4083              'status' => $status,
4084              'warnings' => $warnings
4085          );
4086          return $results;
4087      }
4088  
4089      /**
4090       * Returns description of method result value
4091       *
4092       * @return external_description
4093       * @since 3.1
4094       */
4095      public static function delete_message_returns() {
4096          return new external_single_structure(
4097              array(
4098                  'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
4099                  'warnings' => new external_warnings()
4100              )
4101          );
4102      }
4103  
4104      /**
4105       * Returns description of method parameters
4106       *
4107       * @return external_function_parameters
4108       * @since 3.2
4109       */
4110      public static function message_processor_config_form_parameters() {
4111          return new external_function_parameters(
4112              array(
4113                  'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
4114                  'name' => new external_value(PARAM_SAFEDIR, 'The name of the message processor'),
4115                  'formvalues' => new external_multiple_structure(
4116                      new external_single_structure(
4117                          array(
4118                              'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
4119                              'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
4120                          )
4121                      ),
4122                      'Config form values',
4123                      VALUE_REQUIRED
4124                  ),
4125              )
4126          );
4127      }
4128  
4129      /**
4130       * Processes a message processor config form.
4131       *
4132       * @param  int $userid the user id
4133       * @param  string $name the name of the processor
4134       * @param  array $formvalues the form values
4135       * @return external_description
4136       * @throws moodle_exception
4137       * @since 3.2
4138       */
4139      public static function message_processor_config_form($userid, $name, $formvalues) {
4140          global $USER, $CFG;
4141  
4142          $params = self::validate_parameters(
4143              self::message_processor_config_form_parameters(),
4144              array(
4145                  'userid' => $userid,
4146                  'name' => $name,
4147                  'formvalues' => $formvalues,
4148              )
4149          );
4150  
4151          $user = self::validate_preferences_permissions($params['userid']);
4152  
4153          $processor = get_message_processor($params['name']);
4154          $preferences = [];
4155          $form = new stdClass();
4156  
4157          foreach ($params['formvalues'] as $formvalue) {
4158              // Curly braces to ensure interpretation is consistent between
4159              // php 5 and php 7.
4160              $form->{$formvalue['name']} = $formvalue['value'];
4161          }
4162  
4163          $processor->process_form($form, $preferences);
4164  
4165          if (!empty($preferences)) {
4166              set_user_preferences($preferences, $params['userid']);
4167          }
4168      }
4169  
4170      /**
4171       * Returns description of method result value
4172       *
4173       * @return external_description
4174       * @since 3.2
4175       */
4176      public static function message_processor_config_form_returns() {
4177          return null;
4178      }
4179  
4180      /**
4181       * Returns description of method parameters
4182       *
4183       * @return external_function_parameters
4184       * @since 3.2
4185       */
4186      public static function get_message_processor_parameters() {
4187          return new external_function_parameters(
4188              array(
4189                  'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
4190                  'name' => new external_value(PARAM_SAFEDIR, 'The name of the message processor', VALUE_REQUIRED),
4191              )
4192          );
4193      }
4194  
4195      /**
4196       * Get a message processor.
4197       *
4198       * @param int $userid
4199       * @param string $name the name of the processor
4200       * @return external_description
4201       * @throws moodle_exception
4202       * @since 3.2
4203       */
4204      public static function get_message_processor($userid = 0, $name) {
4205          global $USER, $PAGE, $CFG;
4206  
4207          // Check if messaging is enabled.
4208          if (empty($CFG->messaging)) {
4209              throw new moodle_exception('disabled', 'message');
4210          }
4211  
4212          $params = self::validate_parameters(
4213              self::get_message_processor_parameters(),
4214              array(
4215                  'userid' => $userid,
4216                  'name' => $name,
4217              )
4218          );
4219  
4220          if (empty($params['userid'])) {
4221              $params['userid'] = $USER->id;
4222          }
4223  
4224          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
4225          core_user::require_active_user($user);
4226          self::validate_context(context_user::instance($params['userid']));
4227  
4228          $processor = get_message_processor($params['name']);
4229  
4230          $processoroutput = new \core_message\output\processor($processor, $user);
4231          $renderer = $PAGE->get_renderer('core_message');
4232  
4233          return $processoroutput->export_for_template($renderer);
4234      }
4235  
4236      /**
4237       * Returns description of method result value
4238       *
4239       * @return external_description
4240       * @since 3.2
4241       */
4242      public static function get_message_processor_returns() {
4243          return new external_function_parameters(
4244              array(
4245                  'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
4246                  'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
4247              )
4248          );
4249      }
4250  
4251      /**
4252       * Check that the user has enough permission to retrieve message or notifications preferences.
4253       *
4254       * @param  int $userid the user id requesting the preferences
4255       * @return stdClass full user object
4256       * @throws moodle_exception
4257       * @since  Moodle 3.2
4258       */
4259      protected static function validate_preferences_permissions($userid) {
4260          global $USER;
4261  
4262          if (empty($userid)) {
4263              $user = $USER;
4264          } else {
4265              $user = core_user::get_user($userid, '*', MUST_EXIST);
4266              core_user::require_active_user($user);
4267          }
4268  
4269          $systemcontext = context_system::instance();
4270          self::validate_context($systemcontext);
4271  
4272          // Check access control.
4273          if ($user->id == $USER->id) {
4274              // Editing own message profile.
4275              require_capability('moodle/user:editownmessageprofile', $systemcontext);
4276          } else {
4277              // Teachers, parents, etc.
4278              $personalcontext = context_user::instance($user->id);
4279              require_capability('moodle/user:editmessageprofile', $personalcontext);
4280          }
4281          return $user;
4282      }
4283  
4284      /**
4285       * Returns a notification or message preference structure.
4286       *
4287       * @return external_single_structure the structure
4288       * @since  Moodle 3.2
4289       */
4290      protected static function get_preferences_structure() {
4291          return new external_single_structure(
4292              array(
4293                  'userid' => new external_value(PARAM_INT, 'User id'),
4294                  'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
4295                  'processors' => new external_multiple_structure(
4296                      new external_single_structure(
4297                          array(
4298                              'displayname' => new external_value(PARAM_TEXT, 'Display name'),
4299                              'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
4300                              'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
4301                              'contextid' => new external_value(PARAM_INT, 'Context id'),
4302                              'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
4303                          )
4304                      ),
4305                      'Config form values'
4306                  ),
4307                  'components' => new external_multiple_structure(
4308                      new external_single_structure(
4309                          array(
4310                              'displayname' => new external_value(PARAM_TEXT, 'Display name'),
4311                              'notifications' => new external_multiple_structure(
4312                                  new external_single_structure(
4313                                      array(
4314                                          'displayname' => new external_value(PARAM_TEXT, 'Display name'),
4315                                          'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
4316                                          'processors' => new external_multiple_structure(
4317                                              new external_single_structure(
4318                                                  array(
4319                                                      'displayname' => new external_value(PARAM_TEXT, 'Display name'),
4320                                                      'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
4321                                                      'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
4322                                                      'lockedmessage' => new external_value(PARAM_TEXT,
4323                                                          'Text to display if locked', VALUE_OPTIONAL),
4324                                                      'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
4325                                                      'loggedin' => new external_single_structure(
4326                                                          array(
4327                                                              'name' => new external_value(PARAM_NOTAGS, 'Name'),
4328                                                              'displayname' => new external_value(PARAM_TEXT, 'Display name'),
4329                                                              'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
4330                                                          )
4331                                                      ),
4332                                                      'loggedoff' => new external_single_structure(
4333                                                          array(
4334                                                              'name' => new external_value(PARAM_NOTAGS, 'Name'),
4335                                                              'displayname' => new external_value(PARAM_TEXT, 'Display name'),
4336                                                              'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
4337                                                          )
4338                                                      ),
4339                                                  )
4340                                              ),
4341                                              'Processors values for this notification'
4342                                          ),
4343                                      )
4344                                  ),
4345                                  'List of notificaitons for the component'
4346                              ),
4347                          )
4348                      ),
4349                      'Available components'
4350                  ),
4351              )
4352          );
4353      }
4354  
4355      /**
4356       * Returns description of method parameters
4357       *
4358       * @return external_function_parameters
4359       * @since 3.2
4360       */
4361      public static function get_user_notification_preferences_parameters() {
4362          return new external_function_parameters(
4363              array(
4364                  'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
4365              )
4366          );
4367      }
4368  
4369      /**
4370       * Get the notification preferences for a given user.
4371       *
4372       * @param int $userid id of the user, 0 for current user
4373       * @return external_description
4374       * @throws moodle_exception
4375       * @since 3.2
4376       */
4377      public static function get_user_notification_preferences($userid = 0) {
4378          global $PAGE;
4379  
4380          $params = self::validate_parameters(
4381              self::get_user_notification_preferences_parameters(),
4382              array(
4383                  'userid' => $userid,
4384              )
4385          );
4386          $user = self::validate_preferences_permissions($params['userid']);
4387  
4388          $processors = get_message_processors();
4389          $providers = message_get_providers_for_user($user->id);
4390          $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
4391          $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
4392  
4393          $renderer = $PAGE->get_renderer('core_message');
4394  
4395          $result = array(
4396              'warnings' => array(),
4397              'preferences' => $notificationlist->export_for_template($renderer)
4398          );
4399          return $result;
4400      }
4401  
4402      /**
4403       * Returns description of method result value
4404       *
4405       * @return external_description
4406       * @since 3.2
4407       */
4408      public static function get_user_notification_preferences_returns() {
4409          return new external_function_parameters(
4410              array(
4411                  'preferences' => self::get_preferences_structure(),
4412                  'warnings' => new external_warnings(),
4413              )
4414          );
4415      }
4416  
4417      /**
4418       * Returns description of method parameters
4419       *
4420       * @return external_function_parameters
4421       * @since 3.2
4422       */
4423      public static function get_user_message_preferences_parameters() {
4424          return new external_function_parameters(
4425              array(
4426                  'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
4427              )
4428          );
4429      }
4430  
4431      /**
4432       * Get the notification preferences for a given user.
4433       *
4434       * @param int $userid id of the user, 0 for current user
4435       * @return external_description
4436       * @throws moodle_exception
4437       * @since 3.2
4438       */
4439      public static function get_user_message_preferences($userid = 0) {
4440          global $CFG, $PAGE;
4441  
4442          $params = self::validate_parameters(
4443              self::get_user_message_preferences_parameters(),
4444              array(
4445                  'userid' => $userid,
4446              )
4447          );
4448  
4449          $user = self::validate_preferences_permissions($params['userid']);
4450  
4451          // Filter out enabled, available system_configured and user_configured processors only.
4452          $readyprocessors = array_filter(get_message_processors(), function($processor) {
4453              return $processor->enabled &&
4454                  $processor->configured &&
4455                  $processor->object->is_user_configured() &&
4456                  // Filter out processors that don't have and message preferences to configure.
4457                  $processor->object->has_message_preferences();
4458          });
4459  
4460          $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
4461              return $provider->component === 'moodle';
4462          });
4463          $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
4464          $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
4465              $providers, $preferences, $user);
4466  
4467          $renderer = $PAGE->get_renderer('core_message');
4468  
4469          $entertosend = get_user_preferences('message_entertosend', $CFG->messagingdefaultpressenter, $user);
4470  
4471          $result = array(
4472              'warnings' => array(),
4473              'preferences' => $notificationlistoutput->export_for_template($renderer),
4474              'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id),
4475              'entertosend' => $entertosend
4476          );
4477          return $result;
4478      }
4479  
4480      /**
4481       * Returns description of method result value
4482       *
4483       * @return external_description
4484       * @since 3.2
4485       */
4486      public static function get_user_message_preferences_returns() {
4487          return new external_function_parameters(
4488              array(
4489                  'preferences' => self::get_preferences_structure(),
4490                  'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'),
4491                  'entertosend' => new external_value(PARAM_BOOL, 'User preference for using enter to send messages'),
4492                  'warnings' => new external_warnings(),
4493              )
4494          );
4495      }
4496  
4497      /**
4498       * Returns description of method parameters for the favourite_conversations() method.
4499       *
4500       * @return external_function_parameters
4501       */
4502      public static function set_favourite_conversations_parameters() {
4503          return new external_function_parameters(
4504              array(
4505                  'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
4506                  'conversations' => new external_multiple_structure(
4507                      new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
4508                  )
4509              )
4510          );
4511      }
4512  
4513      /**
4514       * Favourite a conversation, or list of conversations for a user.
4515       *
4516       * @param int $userid the id of the user, or 0 for the current user.
4517       * @param array $conversationids the list of conversations ids to favourite.
4518       * @return array
4519       * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
4520       */
4521      public static function set_favourite_conversations(int $userid, array $conversationids) {
4522          global $CFG, $USER;
4523  
4524          // All the business logic checks that really shouldn't be in here.
4525          if (empty($CFG->messaging)) {
4526              throw new moodle_exception('disabled', 'message');
4527          }
4528          $params = [
4529              'userid' => $userid,
4530              'conversations' => $conversationids
4531          ];
4532          $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params);
4533          $systemcontext = context_system::instance();
4534          self::validate_context($systemcontext);
4535  
4536          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
4537              throw new moodle_exception('You do not have permission to perform this action.');
4538          }
4539  
4540          foreach ($params['conversations'] as $conversationid) {
4541              \core_message\api::set_favourite_conversation($conversationid, $params['userid']);
4542          }
4543  
4544          return [];
4545      }
4546  
4547      /**
4548       * Return a description of the returns for the create_user_favourite_conversations() method.
4549       *
4550       * @return external_description
4551       */
4552      public static function set_favourite_conversations_returns() {
4553          return new external_warnings();
4554      }
4555  
4556      /**
4557       * Returns description of method parameters for unfavourite_conversations() method.
4558       *
4559       * @return external_function_parameters
4560       */
4561      public static function unset_favourite_conversations_parameters() {
4562          return new external_function_parameters(
4563              array(
4564                  'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
4565                  'conversations' => new external_multiple_structure(
4566                      new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
4567                  )
4568              )
4569          );
4570      }
4571  
4572      /**
4573       * Unfavourite a conversation, or list of conversations for a user.
4574       *
4575       * @param int $userid the id of the user, or 0 for the current user.
4576       * @param array $conversationids the list of conversations ids unset as favourites.
4577       * @return array
4578       * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
4579       */
4580      public static function unset_favourite_conversations(int $userid, array $conversationids) {
4581          global $CFG, $USER;
4582  
4583          // All the business logic checks that really shouldn't be in here.
4584          if (empty($CFG->messaging)) {
4585              throw new moodle_exception('disabled', 'message');
4586          }
4587          $params = [
4588              'userid' => $userid,
4589              'conversations' => $conversationids
4590          ];
4591          $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params);
4592          $systemcontext = context_system::instance();
4593          self::validate_context($systemcontext);
4594  
4595          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
4596              throw new moodle_exception('You do not have permission to perform this action.');
4597          }
4598  
4599          foreach ($params['conversations'] as $conversationid) {
4600              \core_message\api::unset_favourite_conversation($conversationid, $params['userid']);
4601          }
4602  
4603          return [];
4604      }
4605  
4606      /**
4607       * Unset favourite conversations return description.
4608       *
4609       * @return external_description
4610       */
4611      public static function unset_favourite_conversations_returns() {
4612          return new external_warnings();
4613      }
4614  
4615      /**
4616       * Returns description of method parameters for get_member_info() method.
4617       *
4618       * @return external_function_parameters
4619       */
4620      public static function get_member_info_parameters() {
4621          return new external_function_parameters(
4622              array(
4623                  'referenceuserid' => new external_value(PARAM_INT, 'id of the user'),
4624                  'userids' => new external_multiple_structure(
4625                      new external_value(PARAM_INT, 'id of members to get')
4626                  ),
4627                  'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false),
4628                  'includeprivacyinfo' => new external_value(PARAM_BOOL, 'include privacy info in response', VALUE_DEFAULT, false)
4629              )
4630          );
4631      }
4632  
4633      /**
4634       * Returns conversation member info for the supplied users, relative to the supplied referenceuserid.
4635       *
4636       * This is the basic structure used when returning members, and includes information about the relationship between each member
4637       * and the referenceuser, such as a whether the referenceuser has marked the member as a contact, or has blocked them.
4638       *
4639       * @param int $referenceuserid the id of the user which check contact and blocked status.
4640       * @param array $userids
4641       * @return array the array of objects containing member info.
4642       * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
4643       */
4644      public static function get_member_info(
4645          int $referenceuserid,
4646          array $userids,
4647          bool $includecontactrequests = false,
4648          bool $includeprivacyinfo = false
4649      ) {
4650          global $CFG, $USER;
4651  
4652          // All the business logic checks that really shouldn't be in here.
4653          if (empty($CFG->messaging)) {
4654              throw new moodle_exception('disabled', 'message');
4655          }
4656          $params = [
4657              'referenceuserid' => $referenceuserid,
4658              'userids' => $userids,
4659              'includecontactrequests' => $includecontactrequests,
4660              'includeprivacyinfo' => $includeprivacyinfo
4661          ];
4662          $params = self::validate_parameters(self::get_member_info_parameters(), $params);
4663          $systemcontext = context_system::instance();
4664          self::validate_context($systemcontext);
4665  
4666          if (($USER->id != $referenceuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
4667              throw new moodle_exception('You do not have permission to perform this action.');
4668          }
4669  
4670          return \core_message\helper::get_member_info(
4671              $params['referenceuserid'],
4672              $params['userids'],
4673              $params['includecontactrequests'],
4674              $params['includeprivacyinfo']
4675          );
4676      }
4677  
4678      /**
4679       * Get member info return description.
4680       *
4681       * @return external_description
4682       */
4683      public static function get_member_info_returns() {
4684          return new external_multiple_structure(
4685              self::get_conversation_member_structure()
4686          );
4687      }
4688  
4689      /**
4690       * Returns description of method parameters for get_conversation_counts() method.
4691       *
4692       * @return external_function_parameters
4693       */
4694      public static function get_conversation_counts_parameters() {
4695          return new external_function_parameters(
4696              [
4697                  'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
4698              ]
4699          );
4700      }
4701  
4702      /**
4703       * Returns an array of conversation counts for the various types of conversations, including favourites.
4704       *
4705       * Return format:
4706       * [
4707       *     'favourites' => 0,
4708       *     'types' => [
4709       *          \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
4710       *          \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
4711       *      ]
4712       * ]
4713       *
4714       * @param int $userid the id of the user whose counts we are fetching.
4715       * @return array the array of conversation counts, indexed by type.
4716       * @throws moodle_exception if the current user cannot perform this action.
4717       */
4718      public static function get_conversation_counts(int $userid) {
4719          global $CFG, $USER;
4720  
4721          // All the business logic checks that really shouldn't be in here.
4722          if (empty($CFG->messaging)) {
4723              throw new moodle_exception('disabled', 'message');
4724          }
4725  
4726          if (empty($userid)) {
4727              $userid = $USER->id;
4728          }
4729  
4730          $params = ['userid' => $userid];
4731          $params = self::validate_parameters(self::get_conversation_counts_parameters(), $params);
4732  
4733          $systemcontext = context_system::instance();
4734          self::validate_context($systemcontext);
4735  
4736          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
4737              throw new moodle_exception('You do not have permission to perform this action.');
4738          }
4739  
4740          return \core_message\api::get_conversation_counts($params['userid']);
4741      }
4742  
4743      /**
4744       * Get conversation counts return description.
4745       *
4746       * @return external_description
4747       */
4748      public static function get_conversation_counts_returns() {
4749          return new external_single_structure(
4750              [
4751                  'favourites' => new external_value(PARAM_INT, 'Total number of favourite conversations'),
4752                  'types' => new external_single_structure(
4753                      [
4754                          \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
4755                              'Total number of individual conversations'),
4756                          \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
4757                              'Total number of group conversations'),
4758                          \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
4759                              'Total number of self conversations'),
4760                      ]
4761                  ),
4762              ]
4763          );
4764      }
4765  
4766      /**
4767       * Returns description of method parameters for get_unread_conversation_counts() method.
4768       *
4769       * @return external_function_parameters
4770       */
4771      public static function get_unread_conversation_counts_parameters() {
4772          return new external_function_parameters(
4773              [
4774                  'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
4775              ]
4776          );
4777      }
4778  
4779      /**
4780       * Returns an array of unread conversation counts for the various types of conversations, including favourites.
4781       *
4782       * Return format:
4783       * [
4784       *     'favourites' => 0,
4785       *     'types' => [
4786       *          \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
4787       *          \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
4788       *      ]
4789       * ]
4790       *
4791       * @param int $userid the id of the user whose counts we are fetching.
4792       * @return array the array of unread conversation counts, indexed by type.
4793       * @throws moodle_exception if the current user cannot perform this action.
4794       */
4795      public static function get_unread_conversation_counts(int $userid) {
4796          global $CFG, $USER;
4797  
4798          // All the business logic checks that really shouldn't be in here.
4799          if (empty($CFG->messaging)) {
4800              throw new moodle_exception('disabled', 'message');
4801          }
4802  
4803          if (empty($userid)) {
4804              $userid = $USER->id;
4805          }
4806  
4807          $params = ['userid' => $userid];
4808          $params = self::validate_parameters(self::get_unread_conversation_counts_parameters(), $params);
4809  
4810          $systemcontext = context_system::instance();
4811          self::validate_context($systemcontext);
4812  
4813          if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
4814              throw new moodle_exception('You do not have permission to perform this action.');
4815          }
4816  
4817          return \core_message\api::get_unread_conversation_counts($params['userid']);
4818      }
4819  
4820      /**
4821       * Get unread conversation counts return description.
4822       *
4823       * @return external_description
4824       */
4825      public static function get_unread_conversation_counts_returns() {
4826          return new external_single_structure(
4827              [
4828                  'favourites' => new external_value(PARAM_INT, 'Total number of unread favourite conversations'),
4829                  'types' => new external_single_structure(
4830                      [
4831                          \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
4832                              'Total number of unread individual conversations'),
4833                          \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
4834                              'Total number of unread group conversations'),
4835                          \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
4836                              'Total number of unread self conversations'),
4837                      ]
4838                  ),
4839              ]
4840          );
4841      }
4842  
4843      /**
4844       * Returns description of method parameters
4845       *
4846       * @return external_function_parameters
4847       * @since 3.7
4848       */
4849      public static function delete_message_for_all_users_parameters() {
4850          return new external_function_parameters(
4851              array(
4852                  'messageid' => new external_value(PARAM_INT, 'The message id'),
4853                  'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users')
4854              )
4855          );
4856      }
4857      /**
4858       * Deletes a message for all users
4859       *
4860       * @param  int $messageid the message id
4861       * @param  int $userid the user id of who we want to delete the message for all users, is no longer used.
4862       * @return external_description
4863       * @throws moodle_exception
4864       * @since 3.7
4865       */
4866      public static function delete_message_for_all_users(int $messageid, int $userid) {
4867          global $CFG, $USER;
4868  
4869          // Check if private messaging between users is allowed.
4870          if (empty($CFG->messaging)) {
4871              throw new moodle_exception('disabled', 'message');
4872          }
4873  
4874          // Validate params.
4875          $params = array(
4876              'messageid' => $messageid,
4877              'userid' => $userid
4878          );
4879          $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params);
4880  
4881          // Validate context.
4882          $context = context_system::instance();
4883          self::validate_context($context);
4884  
4885          core_user::require_active_user($USER);
4886  
4887          // Checks if a user can delete a message for all users.
4888          if (core_message\api::can_delete_message_for_all_users($USER->id, $params['messageid'])) {
4889              \core_message\api::delete_message_for_all_users($params['messageid']);
4890          } else {
4891              throw new moodle_exception('You do not have permission to delete this message for everyone.');
4892          }
4893  
4894          return [];
4895      }
4896      /**
4897       * Returns description of method result value
4898       *
4899       * @return external_description
4900       * @since 3.7
4901       */
4902      public static function delete_message_for_all_users_returns() {
4903          return new external_warnings();
4904      }
4905  }