See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 18 /** 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 $resultmsg['msgid'] = -1; 231 if (!isset($errormessage)) { // Nobody has set a message error or thrown an exception, let's set it. 232 $errormessage = get_string('messageundeliveredbynotificationsettings', 'error'); 233 } 234 $resultmsg['errormessage'] = $errormessage; 235 } 236 237 $resultmessages[] = $resultmsg; 238 } 239 240 if (!empty($messageids)) { 241 $messagerecords = $DB->get_records_list( 242 'messages', 243 'id', 244 $messageids, 245 '', 246 'id, conversationid, smallmessage, fullmessageformat, fullmessagetrust'); 247 $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) { 248 $id = $resultmessage['msgid']; 249 $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null; 250 $resultmessage['useridfrom'] = $USER->id; 251 $resultmessage['text'] = message_format_message_text((object) [ 252 'smallmessage' => $messagerecords[$id]->smallmessage, 253 'fullmessageformat' => external_validate_format($messagerecords[$id]->fullmessageformat), 254 'fullmessagetrust' => $messagerecords[$id]->fullmessagetrust 255 ]); 256 return $resultmessage; 257 }, $resultmessages); 258 } 259 260 return $resultmessages; 261 } 262 263 /** 264 * Returns description of method result value 265 * 266 * @return external_description 267 * @since Moodle 2.2 268 */ 269 public static function send_instant_messages_returns() { 270 return new external_multiple_structure( 271 new external_single_structure( 272 array( 273 'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds: id of the created message if it succeeded, -1 when failed'), 274 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL), 275 'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL), 276 'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL), 277 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL), 278 'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL), 279 'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL), 280 'candeletemessagesforallusers' => new external_value(PARAM_BOOL, 281 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false), 282 ) 283 ) 284 ); 285 } 286 287 /** 288 * Delete contacts parameters description. 289 * 290 * @return external_function_parameters 291 * @since Moodle 2.5 292 */ 293 public static function delete_contacts_parameters() { 294 return new external_function_parameters( 295 array( 296 'userids' => new external_multiple_structure( 297 new external_value(PARAM_INT, 'User ID'), 298 'List of user IDs' 299 ), 300 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the 301 current user', VALUE_DEFAULT, 0) 302 ) 303 ); 304 } 305 306 /** 307 * Delete contacts. 308 * 309 * @param array $userids array of user IDs. 310 * @param int $userid The id of the user we are deleting the contacts for 311 * @return null 312 * @since Moodle 2.5 313 */ 314 public static function delete_contacts($userids, $userid = 0) { 315 global $CFG, $USER; 316 317 // Check if messaging is enabled. 318 if (empty($CFG->messaging)) { 319 throw new moodle_exception('disabled', 'message'); 320 } 321 322 if (empty($userid)) { 323 $userid = $USER->id; 324 } 325 326 // Validate context. 327 $context = context_system::instance(); 328 self::validate_context($context); 329 330 $params = array('userids' => $userids, 'userid' => $userid); 331 $params = self::validate_parameters(self::delete_contacts_parameters(), $params); 332 333 $capability = 'moodle/site:manageallmessaging'; 334 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) { 335 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 336 } 337 338 foreach ($params['userids'] as $id) { 339 \core_message\api::remove_contact($params['userid'], $id); 340 } 341 342 return null; 343 } 344 345 /** 346 * Delete contacts return description. 347 * 348 * @return external_description 349 * @since Moodle 2.5 350 */ 351 public static function delete_contacts_returns() { 352 return null; 353 } 354 355 /** 356 * Mute conversations parameters description. 357 * 358 * @return external_function_parameters 359 */ 360 public static function mute_conversations_parameters() { 361 return new external_function_parameters( 362 [ 363 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'), 364 'conversationids' => new external_multiple_structure( 365 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED) 366 ), 367 ] 368 ); 369 } 370 371 /** 372 * Mutes conversations. 373 * 374 * @param int $userid The id of the user who is blocking 375 * @param array $conversationids The list of conversations being muted 376 * @return external_description 377 */ 378 public static function mute_conversations(int $userid, array $conversationids) { 379 global $CFG, $USER; 380 381 // Check if messaging is enabled. 382 if (empty($CFG->messaging)) { 383 throw new moodle_exception('disabled', 'message'); 384 } 385 386 // Validate context. 387 $context = context_system::instance(); 388 self::validate_context($context); 389 390 $params = ['userid' => $userid, 'conversationids' => $conversationids]; 391 $params = self::validate_parameters(self::mute_conversations_parameters(), $params); 392 393 $capability = 'moodle/site:manageallmessaging'; 394 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) { 395 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 396 } 397 398 foreach ($params['conversationids'] as $conversationid) { 399 if (!\core_message\api::is_conversation_muted($params['userid'], $conversationid)) { 400 \core_message\api::mute_conversation($params['userid'], $conversationid); 401 } 402 } 403 404 return []; 405 } 406 407 /** 408 * Mute conversations return description. 409 * 410 * @return external_description 411 */ 412 public static function mute_conversations_returns() { 413 return new external_warnings(); 414 } 415 416 /** 417 * Unmute conversations parameters description. 418 * 419 * @return external_function_parameters 420 */ 421 public static function unmute_conversations_parameters() { 422 return new external_function_parameters( 423 [ 424 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'), 425 'conversationids' => new external_multiple_structure( 426 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED) 427 ), 428 ] 429 ); 430 } 431 432 /** 433 * Unmute conversations. 434 * 435 * @param int $userid The id of the user who is unblocking 436 * @param array $conversationids The list of conversations being muted 437 */ 438 public static function unmute_conversations(int $userid, array $conversationids) { 439 global $CFG, $USER; 440 441 // Check if messaging is enabled. 442 if (empty($CFG->messaging)) { 443 throw new moodle_exception('disabled', 'message'); 444 } 445 446 // Validate context. 447 $context = context_system::instance(); 448 self::validate_context($context); 449 450 $params = ['userid' => $userid, 'conversationids' => $conversationids]; 451 $params = self::validate_parameters(self::unmute_conversations_parameters(), $params); 452 453 $capability = 'moodle/site:manageallmessaging'; 454 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) { 455 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 456 } 457 458 foreach ($params['conversationids'] as $conversationid) { 459 \core_message\api::unmute_conversation($params['userid'], $conversationid); 460 } 461 462 return []; 463 } 464 465 /** 466 * Unmute conversations return description. 467 * 468 * @return external_description 469 */ 470 public static function unmute_conversations_returns() { 471 return new external_warnings(); 472 } 473 474 /** 475 * Block user parameters description. 476 * 477 * @return external_function_parameters 478 */ 479 public static function block_user_parameters() { 480 return new external_function_parameters( 481 [ 482 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'), 483 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'), 484 ] 485 ); 486 } 487 488 /** 489 * Blocks a user. 490 * 491 * @param int $userid The id of the user who is blocking 492 * @param int $blockeduserid The id of the user being blocked 493 * @return external_description 494 */ 495 public static function block_user(int $userid, int $blockeduserid) { 496 global $CFG, $USER; 497 498 // Check if messaging is enabled. 499 if (empty($CFG->messaging)) { 500 throw new moodle_exception('disabled', 'message'); 501 } 502 503 // Validate context. 504 $context = context_system::instance(); 505 self::validate_context($context); 506 507 $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid]; 508 $params = self::validate_parameters(self::block_user_parameters(), $params); 509 510 $capability = 'moodle/site:manageallmessaging'; 511 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) { 512 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 513 } 514 515 // If the blocking is going to be useless then don't do it. 516 if (\core_message\api::can_send_message($userid, $blockeduserid, true)) { 517 return []; 518 } 519 520 if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) { 521 \core_message\api::block_user($params['userid'], $params['blockeduserid']); 522 } 523 524 return []; 525 } 526 527 /** 528 * Block user return description. 529 * 530 * @return external_description 531 */ 532 public static function block_user_returns() { 533 return new external_warnings(); 534 } 535 536 /** 537 * Unblock user parameters description. 538 * 539 * @return external_function_parameters 540 */ 541 public static function unblock_user_parameters() { 542 return new external_function_parameters( 543 [ 544 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'), 545 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'), 546 ] 547 ); 548 } 549 550 /** 551 * Unblock user. 552 * 553 * @param int $userid The id of the user who is unblocking 554 * @param int $unblockeduserid The id of the user being unblocked 555 */ 556 public static function unblock_user(int $userid, int $unblockeduserid) { 557 global $CFG, $USER; 558 559 // Check if messaging is enabled. 560 if (empty($CFG->messaging)) { 561 throw new moodle_exception('disabled', 'message'); 562 } 563 564 // Validate context. 565 $context = context_system::instance(); 566 self::validate_context($context); 567 568 $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid]; 569 $params = self::validate_parameters(self::unblock_user_parameters(), $params); 570 571 $capability = 'moodle/site:manageallmessaging'; 572 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) { 573 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 574 } 575 576 \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']); 577 578 return []; 579 } 580 581 /** 582 * Unblock user return description. 583 * 584 * @return external_description 585 */ 586 public static function unblock_user_returns() { 587 return new external_warnings(); 588 } 589 590 /** 591 * Returns contact requests parameters description. 592 * 593 * @return external_function_parameters 594 */ 595 public static function get_contact_requests_parameters() { 596 return new external_function_parameters( 597 [ 598 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'), 599 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0), 600 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0) 601 ] 602 ); 603 } 604 605 /** 606 * Handles returning the contact requests for a user. 607 * 608 * This also includes the user data necessary to display information 609 * about the user. 610 * 611 * It will not include blocked users. 612 * 613 * @param int $userid The id of the user we want to get the contact requests for 614 * @param int $limitfrom 615 * @param int $limitnum 616 */ 617 public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) { 618 global $CFG, $USER; 619 620 // Check if messaging is enabled. 621 if (empty($CFG->messaging)) { 622 throw new moodle_exception('disabled', 'message'); 623 } 624 625 // Validate context. 626 $context = context_system::instance(); 627 self::validate_context($context); 628 629 $params = [ 630 'userid' => $userid, 631 'limitfrom' => $limitfrom, 632 'limitnum' => $limitnum 633 ]; 634 $params = self::validate_parameters(self::get_contact_requests_parameters(), $params); 635 636 $capability = 'moodle/site:manageallmessaging'; 637 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) { 638 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 639 } 640 641 return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']); 642 } 643 644 /** 645 * Returns the contact requests return description. 646 * 647 * @return external_description 648 */ 649 public static function get_contact_requests_returns() { 650 return new external_multiple_structure( 651 self::get_conversation_member_structure() 652 ); 653 } 654 655 /** 656 * Returns the number of contact requests the user has received parameters description. 657 * 658 * @return external_function_parameters 659 */ 660 public static function get_received_contact_requests_count_parameters() { 661 return new external_function_parameters( 662 array( 663 'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' . 664 'received contact requests for', VALUE_REQUIRED), 665 ) 666 ); 667 } 668 669 /** 670 * Returns the number of contact requests the user has received. 671 * 672 * @param int $userid The ID of the user we want to return the number of received contact requests for 673 * @return external_value 674 */ 675 public static function get_received_contact_requests_count(int $userid) { 676 global $CFG, $USER; 677 678 // Check if messaging is enabled. 679 if (empty($CFG->messaging)) { 680 throw new moodle_exception('disabled', 'message'); 681 } 682 683 // Validate context. 684 $context = context_system::instance(); 685 self::validate_context($context); 686 687 $params = [ 688 'userid' => $userid, 689 ]; 690 $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params); 691 692 $capability = 'moodle/site:manageallmessaging'; 693 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) { 694 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 695 } 696 697 return \core_message\api::get_received_contact_requests_count($params['userid']); 698 } 699 700 /** 701 * Returns the number of contact requests the user has received return description. 702 * 703 * @return external_value 704 */ 705 public static function get_received_contact_requests_count_returns() { 706 return new external_value(PARAM_INT, 'The number of received contact requests'); 707 } 708 709 /** 710 * Returns get conversation members parameters description. 711 * 712 * @return external_function_parameters 713 */ 714 public static function get_conversation_members_parameters() { 715 return new external_function_parameters( 716 [ 717 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'), 718 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'), 719 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?', 720 VALUE_DEFAULT, false), 721 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?', 722 VALUE_DEFAULT, false), 723 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0), 724 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0) 725 ] 726 ); 727 } 728 729 /** 730 * Returns a list of conversation members. 731 * 732 * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info. 733 * @param int $conversationid The id of the conversation 734 * @param bool $includecontactrequests Do we want to include contact requests with this data? 735 * @param bool $includeprivacyinfo Do we want to include privacy info? 736 * @param int $limitfrom 737 * @param int $limitnum 738 * @return array 739 */ 740 public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false, 741 bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) { 742 global $CFG, $USER; 743 744 // Check if messaging is enabled. 745 if (empty($CFG->messaging)) { 746 throw new moodle_exception('disabled', 'message'); 747 } 748 749 // Validate context. 750 $context = context_system::instance(); 751 self::validate_context($context); 752 753 $params = [ 754 'userid' => $userid, 755 'conversationid' => $conversationid, 756 'includecontactrequests' => $includecontactrequests, 757 'includeprivacyinfo' => $includeprivacyinfo, 758 'limitfrom' => $limitfrom, 759 'limitnum' => $limitnum 760 ]; 761 $params = self::validate_parameters(self::get_conversation_members_parameters(), $params); 762 763 $capability = 'moodle/site:manageallmessaging'; 764 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) { 765 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 766 } 767 768 // The user needs to be a part of the conversation before querying who the members are. 769 if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) { 770 throw new moodle_exception('You are not a member of this conversation.'); 771 } 772 773 return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'], 774 $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']); 775 } 776 777 /** 778 * Returns the get conversation members return description. 779 * 780 * @return external_description 781 */ 782 public static function get_conversation_members_returns() { 783 return new external_multiple_structure( 784 self::get_conversation_member_structure() 785 ); 786 } 787 788 /** 789 * Creates a contact request parameters description. 790 * 791 * @return external_function_parameters 792 */ 793 public static function create_contact_request_parameters() { 794 return new external_function_parameters( 795 [ 796 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'), 797 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested') 798 ] 799 ); 800 } 801 802 /** 803 * Creates a contact request. 804 * 805 * @param int $userid The id of the user who is creating the contact request 806 * @param int $requesteduserid The id of the user being requested 807 */ 808 public static function create_contact_request(int $userid, int $requesteduserid) { 809 global $CFG, $USER; 810 811 // Check if messaging is enabled. 812 if (empty($CFG->messaging)) { 813 throw new moodle_exception('disabled', 'message'); 814 } 815 816 // Validate context. 817 $context = context_system::instance(); 818 self::validate_context($context); 819 820 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid]; 821 $params = self::validate_parameters(self::create_contact_request_parameters(), $params); 822 823 $capability = 'moodle/site:manageallmessaging'; 824 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) { 825 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 826 } 827 828 $result = [ 829 'warnings' => [] 830 ]; 831 832 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) { 833 $result['warnings'][] = [ 834 'item' => 'user', 835 'itemid' => $params['requesteduserid'], 836 'warningcode' => 'cannotcreatecontactrequest', 837 'message' => 'You are unable to create a contact request for this user' 838 ]; 839 } else { 840 if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) { 841 // There should only ever be one but just in case there are multiple then we can return the first. 842 $result['request'] = array_shift($requests); 843 } else { 844 $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']); 845 } 846 } 847 848 return $result; 849 } 850 851 /** 852 * Creates a contact request return description. 853 * 854 * @return external_description 855 */ 856 public static function create_contact_request_returns() { 857 return new external_single_structure( 858 array( 859 'request' => new external_single_structure( 860 array( 861 'id' => new external_value(PARAM_INT, 'Message id'), 862 'userid' => new external_value(PARAM_INT, 'User from id'), 863 'requesteduserid' => new external_value(PARAM_INT, 'User to id'), 864 'timecreated' => new external_value(PARAM_INT, 'Time created'), 865 ), 866 'request record', 867 VALUE_OPTIONAL 868 ), 869 'warnings' => new external_warnings() 870 ) 871 ); 872 } 873 874 /** 875 * Confirm a contact request parameters description. 876 * 877 * @return external_function_parameters 878 */ 879 public static function confirm_contact_request_parameters() { 880 return new external_function_parameters( 881 [ 882 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'), 883 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested') 884 ] 885 ); 886 } 887 888 /** 889 * Confirm a contact request. 890 * 891 * @param int $userid The id of the user who is creating the contact request 892 * @param int $requesteduserid The id of the user being requested 893 */ 894 public static function confirm_contact_request(int $userid, int $requesteduserid) { 895 global $CFG, $USER; 896 897 // Check if messaging is enabled. 898 if (empty($CFG->messaging)) { 899 throw new moodle_exception('disabled', 'message'); 900 } 901 902 // Validate context. 903 $context = context_system::instance(); 904 self::validate_context($context); 905 906 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid]; 907 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params); 908 909 $capability = 'moodle/site:manageallmessaging'; 910 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) { 911 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 912 } 913 914 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']); 915 916 return []; 917 } 918 919 /** 920 * Confirm a contact request return description. 921 * 922 * @return external_description 923 */ 924 public static function confirm_contact_request_returns() { 925 return new external_warnings(); 926 } 927 928 /** 929 * Declines a contact request parameters description. 930 * 931 * @return external_function_parameters 932 */ 933 public static function decline_contact_request_parameters() { 934 return new external_function_parameters( 935 [ 936 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'), 937 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested') 938 ] 939 ); 940 } 941 942 /** 943 * Declines a contact request. 944 * 945 * @param int $userid The id of the user who is creating the contact request 946 * @param int $requesteduserid The id of the user being requested 947 */ 948 public static function decline_contact_request(int $userid, int $requesteduserid) { 949 global $CFG, $USER; 950 951 // Check if messaging is enabled. 952 if (empty($CFG->messaging)) { 953 throw new moodle_exception('disabled', 'message'); 954 } 955 956 // Validate context. 957 $context = context_system::instance(); 958 self::validate_context($context); 959 960 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid]; 961 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params); 962 963 $capability = 'moodle/site:manageallmessaging'; 964 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) { 965 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 966 } 967 968 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']); 969 970 return []; 971 } 972 973 /** 974 * Declines a contact request return description. 975 * 976 * @return external_description 977 */ 978 public static function decline_contact_request_returns() { 979 return new external_warnings(); 980 } 981 982 /** 983 * Return the structure of a message area contact. 984 * 985 * @return external_single_structure 986 * @since Moodle 3.2 987 */ 988 private static function get_messagearea_contact_structure() { 989 return new external_single_structure( 990 array( 991 'userid' => new external_value(PARAM_INT, 'The user\'s id'), 992 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'), 993 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'), 994 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'), 995 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'), 996 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'), 997 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'), 998 'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null), 999 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null), 1000 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'), 1001 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'), 1002 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'), 1003 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'), 1004 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation', 1005 VALUE_DEFAULT, null), 1006 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null), 1007 ) 1008 ); 1009 } 1010 1011 /** 1012 * Return the structure of a conversation. 1013 * 1014 * @return external_single_structure 1015 * @since Moodle 3.6 1016 */ 1017 private static function get_conversation_structure() { 1018 return new external_single_structure( 1019 array( 1020 'id' => new external_value(PARAM_INT, 'The conversation id'), 1021 'name' => new external_value(PARAM_RAW, 'The conversation name, if set', VALUE_DEFAULT, null), 1022 'subname' => new external_value(PARAM_RAW, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null), 1023 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null), 1024 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group,3=self)'), 1025 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'), 1026 'ismuted' => new external_value(PARAM_BOOL, 'If the user muted this conversation'), 1027 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this conversation as a favourite'), 1028 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'), 1029 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation', 1030 VALUE_DEFAULT, null), 1031 'members' => new external_multiple_structure( 1032 self::get_conversation_member_structure() 1033 ), 1034 'messages' => new external_multiple_structure( 1035 self::get_conversation_message_structure() 1036 ), 1037 'candeletemessagesforallusers' => new external_value(PARAM_BOOL, 1038 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false), 1039 ) 1040 ); 1041 } 1042 1043 /** 1044 * Return the structure of a conversation member. 1045 * 1046 * @return external_single_structure 1047 * @since Moodle 3.6 1048 */ 1049 private static function get_conversation_member_structure() { 1050 $result = [ 1051 'id' => new external_value(PARAM_INT, 'The user id'), 1052 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'), 1053 'profileurl' => new external_value(PARAM_URL, 'The link to the user\'s profile page'), 1054 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'), 1055 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'), 1056 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'), 1057 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'), 1058 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'), 1059 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'), 1060 'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'), 1061 'canmessageevenifblocked' => new external_value(PARAM_BOOL, 1062 'If the user can still message even if they get blocked'), 1063 'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'), 1064 'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'), 1065 ]; 1066 1067 $result['contactrequests'] = new external_multiple_structure( 1068 new external_single_structure( 1069 [ 1070 'id' => new external_value(PARAM_INT, 'The id of the contact request'), 1071 'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'), 1072 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'), 1073 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'), 1074 ] 1075 ), 'The contact requests', VALUE_OPTIONAL 1076 ); 1077 1078 $result['conversations'] = new external_multiple_structure(new external_single_structure( 1079 array( 1080 'id' => new external_value(PARAM_INT, 'Conversations id'), 1081 'type' => new external_value(PARAM_INT, 'Conversation type: private or public'), 1082 'name' => new external_value(PARAM_RAW, 'Multilang compatible conversation name'. VALUE_OPTIONAL), 1083 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'), 1084 ), 'information about conversation', VALUE_OPTIONAL), 1085 'Conversations between users', VALUE_OPTIONAL 1086 ); 1087 1088 return new external_single_structure( 1089 $result 1090 ); 1091 } 1092 1093 /** 1094 * Return the structure of a message area message. 1095 * 1096 * @return external_single_structure 1097 * @since Moodle 3.6 1098 */ 1099 private static function get_conversation_message_structure() { 1100 return new external_single_structure( 1101 array( 1102 'id' => new external_value(PARAM_INT, 'The id of the message'), 1103 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'), 1104 'text' => new external_value(PARAM_RAW, 'The text of the message'), 1105 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'), 1106 ) 1107 ); 1108 } 1109 1110 /** 1111 * Get messagearea message search users parameters. 1112 * 1113 * @return external_function_parameters 1114 * @since 3.6 1115 */ 1116 public static function message_search_users_parameters() { 1117 return new external_function_parameters( 1118 array( 1119 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'), 1120 'search' => new external_value(PARAM_RAW, 'The string being searched'), 1121 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0), 1122 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0), 1123 ) 1124 ); 1125 } 1126 1127 /** 1128 * Get search users results. 1129 * 1130 * @param int $userid The id of the user who is performing the search 1131 * @param string $search The string being searched 1132 * @param int $limitfrom 1133 * @param int $limitnum 1134 * @return array 1135 * @throws moodle_exception 1136 * @since 3.6 1137 */ 1138 public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) { 1139 global $USER; 1140 1141 $systemcontext = context_system::instance(); 1142 1143 $params = array( 1144 'userid' => $userid, 1145 'search' => $search, 1146 'limitfrom' => $limitfrom, 1147 'limitnum' => $limitnum 1148 ); 1149 $params = self::validate_parameters(self::message_search_users_parameters(), $params); 1150 self::validate_context($systemcontext); 1151 1152 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 1153 throw new moodle_exception('You do not have permission to perform this action.'); 1154 } 1155 1156 list($contacts, $noncontacts) = \core_message\api::message_search_users( 1157 $params['userid'], 1158 $params['search'], 1159 $params['limitfrom'], 1160 $params['limitnum']); 1161 1162 return array('contacts' => $contacts, 'noncontacts' => $noncontacts); 1163 } 1164 1165 /** 1166 * Get messagearea message search users returns. 1167 * 1168 * @return external_single_structure 1169 * @since 3.2 1170 */ 1171 public static function message_search_users_returns() { 1172 return new external_single_structure( 1173 array( 1174 'contacts' => new external_multiple_structure( 1175 self::get_conversation_member_structure() 1176 ), 1177 'noncontacts' => new external_multiple_structure( 1178 self::get_conversation_member_structure() 1179 ) 1180 ) 1181 ); 1182 } 1183 1184 /** 1185 * Get messagearea search messages parameters. 1186 * 1187 * @return external_function_parameters 1188 * @since 3.2 1189 */ 1190 public static function data_for_messagearea_search_messages_parameters() { 1191 return new external_function_parameters( 1192 array( 1193 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'), 1194 'search' => new external_value(PARAM_RAW, 'The string being searched'), 1195 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0), 1196 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0) 1197 ) 1198 ); 1199 } 1200 1201 /** 1202 * Get messagearea search messages results. 1203 * 1204 * @param int $userid The id of the user who is performing the search 1205 * @param string $search The string being searched 1206 * @param int $limitfrom 1207 * @param int $limitnum 1208 * @return stdClass 1209 * @throws moodle_exception 1210 * @since 3.2 1211 */ 1212 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) { 1213 global $CFG, $USER; 1214 1215 // Check if messaging is enabled. 1216 if (empty($CFG->messaging)) { 1217 throw new moodle_exception('disabled', 'message'); 1218 } 1219 1220 $systemcontext = context_system::instance(); 1221 1222 $params = array( 1223 'userid' => $userid, 1224 'search' => $search, 1225 'limitfrom' => $limitfrom, 1226 'limitnum' => $limitnum 1227 1228 ); 1229 $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params); 1230 self::validate_context($systemcontext); 1231 1232 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 1233 throw new moodle_exception('You do not have permission to perform this action.'); 1234 } 1235 1236 $messages = \core_message\api::search_messages( 1237 $params['userid'], 1238 $params['search'], 1239 $params['limitfrom'], 1240 $params['limitnum'] 1241 ); 1242 1243 $data = new \stdClass(); 1244 $data->contacts = []; 1245 foreach ($messages as $message) { 1246 $contact = new \stdClass(); 1247 $contact->userid = $message->userid; 1248 $contact->fullname = $message->fullname; 1249 $contact->profileimageurl = $message->profileimageurl; 1250 $contact->profileimageurlsmall = $message->profileimageurlsmall; 1251 $contact->messageid = $message->messageid; 1252 $contact->ismessaging = $message->ismessaging; 1253 $contact->sentfromcurrentuser = false; 1254 if ($message->lastmessage) { 1255 if ($message->userid !== $message->useridfrom) { 1256 $contact->sentfromcurrentuser = true; 1257 } 1258 $contact->lastmessage = shorten_text($message->lastmessage, 60); 1259 } else { 1260 $contact->lastmessage = null; 1261 } 1262 $contact->lastmessagedate = $message->lastmessagedate; 1263 $contact->showonlinestatus = is_null($message->isonline) ? false : true; 1264 $contact->isonline = $message->isonline; 1265 $contact->isblocked = $message->isblocked; 1266 $contact->isread = $message->isread; 1267 $contact->unreadcount = $message->unreadcount; 1268 $contact->conversationid = $message->conversationid; 1269 1270 $data->contacts[] = $contact; 1271 } 1272 1273 return $data; 1274 } 1275 1276 /** 1277 * Get messagearea search messages returns. 1278 * 1279 * @return external_single_structure 1280 * @since 3.2 1281 */ 1282 public static function data_for_messagearea_search_messages_returns() { 1283 return new external_single_structure( 1284 array( 1285 'contacts' => new external_multiple_structure( 1286 self::get_messagearea_contact_structure() 1287 ) 1288 ) 1289 ); 1290 } 1291 1292 /** 1293 * Get conversations parameters. 1294 * 1295 * @return external_function_parameters 1296 * @since 3.6 1297 */ 1298 public static function get_conversations_parameters() { 1299 return new external_function_parameters( 1300 array( 1301 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'), 1302 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0), 1303 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0), 1304 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null), 1305 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite 1306 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)', 1307 VALUE_DEFAULT, null), 1308 'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private 1309 conversations (false) when private conversations are requested.', 1310 VALUE_DEFAULT, false), 1311 ) 1312 ); 1313 } 1314 1315 /** 1316 * Get the list of conversations for the user. 1317 * 1318 * @param int $userid The id of the user who is performing the search 1319 * @param int $limitfrom 1320 * @param int $limitnum 1321 * @param int|null $type 1322 * @param bool|null $favourites 1323 * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false) 1324 * when private conversations are requested. 1325 * @return stdClass 1326 * @throws \moodle_exception if the messaging feature is disabled on the site. 1327 * @since 3.2 1328 */ 1329 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null, 1330 bool $mergeself = false) { 1331 global $CFG, $USER; 1332 1333 // All the standard BL checks. 1334 if (empty($CFG->messaging)) { 1335 throw new moodle_exception('disabled', 'message'); 1336 } 1337 1338 $params = array( 1339 'userid' => $userid, 1340 'limitfrom' => $limitfrom, 1341 'limitnum' => $limitnum, 1342 'type' => $type, 1343 'favourites' => $favourites, 1344 'mergeself' => $mergeself 1345 ); 1346 $params = self::validate_parameters(self::get_conversations_parameters(), $params); 1347 1348 $systemcontext = context_system::instance(); 1349 self::validate_context($systemcontext); 1350 1351 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 1352 throw new moodle_exception('You do not have permission to perform this action.'); 1353 } 1354 1355 $conversations = \core_message\api::get_conversations( 1356 $params['userid'], 1357 $params['limitfrom'], 1358 $params['limitnum'], 1359 $params['type'], 1360 $params['favourites'], 1361 $params['mergeself'] 1362 ); 1363 1364 return (object) ['conversations' => $conversations]; 1365 } 1366 1367 /** 1368 * Get conversations returns. 1369 * 1370 * @return external_single_structure 1371 * @since 3.6 1372 */ 1373 public static function get_conversations_returns() { 1374 return new external_single_structure( 1375 [ 1376 'conversations' => new external_multiple_structure( 1377 self::get_conversation_structure(true) 1378 ) 1379 ] 1380 ); 1381 } 1382 1383 /** 1384 * Get conversation parameters. 1385 * 1386 * @return external_function_parameters 1387 */ 1388 public static function get_conversation_parameters() { 1389 return new external_function_parameters( 1390 array( 1391 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'), 1392 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'), 1393 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'), 1394 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'), 1395 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0), 1396 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0), 1397 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100), 1398 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0), 1399 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true) 1400 ) 1401 ); 1402 } 1403 1404 /** 1405 * Get a single conversation. 1406 * 1407 * @param int $userid The user id to get the conversation for 1408 * @param int $conversationid The id of the conversation to fetch 1409 * @param bool $includecontactrequests Should contact requests be included between members 1410 * @param bool $includeprivacyinfo Should privacy info be included between members 1411 * @param int $memberlimit Limit number of members to load 1412 * @param int $memberoffset Offset members by this amount 1413 * @param int $messagelimit Limit number of messages to load 1414 * @param int $messageoffset Offset the messages 1415 * @param bool $newestmessagesfirst Order messages by newest first 1416 * @return stdClass 1417 * @throws \moodle_exception if the messaging feature is disabled on the site. 1418 */ 1419 public static function get_conversation( 1420 int $userid, 1421 int $conversationid, 1422 bool $includecontactrequests = false, 1423 bool $includeprivacyinfo = false, 1424 int $memberlimit = 0, 1425 int $memberoffset = 0, 1426 int $messagelimit = 0, 1427 int $messageoffset = 0, 1428 bool $newestmessagesfirst = true 1429 ) { 1430 global $CFG, $DB, $USER; 1431 1432 // All the standard BL checks. 1433 if (empty($CFG->messaging)) { 1434 throw new moodle_exception('disabled', 'message'); 1435 } 1436 1437 $params = [ 1438 'userid' => $userid, 1439 'conversationid' => $conversationid, 1440 'includecontactrequests' => $includecontactrequests, 1441 'includeprivacyinfo' => $includeprivacyinfo, 1442 'memberlimit' => $memberlimit, 1443 'memberoffset' => $memberoffset, 1444 'messagelimit' => $messagelimit, 1445 'messageoffset' => $messageoffset, 1446 'newestmessagesfirst' => $newestmessagesfirst 1447 ]; 1448 self::validate_parameters(self::get_conversation_parameters(), $params); 1449 1450 $systemcontext = context_system::instance(); 1451 self::validate_context($systemcontext); 1452 1453 $conversation = \core_message\api::get_conversation( 1454 $params['userid'], 1455 $params['conversationid'], 1456 $params['includecontactrequests'], 1457 $params['includeprivacyinfo'], 1458 $params['memberlimit'], 1459 $params['memberoffset'], 1460 $params['messagelimit'], 1461 $params['messageoffset'], 1462 $params['newestmessagesfirst'] 1463 ); 1464 1465 if ($conversation) { 1466 return $conversation; 1467 } else { 1468 // We have to throw an exception here because the external functions annoyingly 1469 // don't accept null to be returned for a single structure. 1470 throw new \moodle_exception('errorconversationdoesnotexist', 'message'); 1471 } 1472 } 1473 1474 /** 1475 * Get conversation returns. 1476 * 1477 * @return external_single_structure 1478 */ 1479 public static function get_conversation_returns() { 1480 return self::get_conversation_structure(); 1481 } 1482 1483 /** 1484 * Get conversation parameters. 1485 * 1486 * @return external_function_parameters 1487 */ 1488 public static function get_conversation_between_users_parameters() { 1489 return new external_function_parameters( 1490 array( 1491 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'), 1492 'otheruserid' => new external_value(PARAM_INT, 'The other user id'), 1493 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'), 1494 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'), 1495 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0), 1496 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0), 1497 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100), 1498 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0), 1499 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true) 1500 ) 1501 ); 1502 } 1503 1504 /** 1505 * Get a single conversation between users. 1506 * 1507 * @param int $userid The user id to get the conversation for 1508 * @param int $otheruserid The other user id 1509 * @param bool $includecontactrequests Should contact requests be included between members 1510 * @param bool $includeprivacyinfo Should privacy info be included between members 1511 * @param int $memberlimit Limit number of members to load 1512 * @param int $memberoffset Offset members by this amount 1513 * @param int $messagelimit Limit number of messages to load 1514 * @param int $messageoffset Offset the messages 1515 * @param bool $newestmessagesfirst Order messages by newest first 1516 * @return stdClass 1517 * @throws \moodle_exception if the messaging feature is disabled on the site. 1518 */ 1519 public static function get_conversation_between_users( 1520 int $userid, 1521 int $otheruserid, 1522 bool $includecontactrequests = false, 1523 bool $includeprivacyinfo = false, 1524 int $memberlimit = 0, 1525 int $memberoffset = 0, 1526 int $messagelimit = 0, 1527 int $messageoffset = 0, 1528 bool $newestmessagesfirst = true 1529 ) { 1530 global $CFG, $DB, $USER; 1531 1532 // All the standard BL checks. 1533 if (empty($CFG->messaging)) { 1534 throw new moodle_exception('disabled', 'message'); 1535 } 1536 1537 $params = [ 1538 'userid' => $userid, 1539 'otheruserid' => $otheruserid, 1540 'includecontactrequests' => $includecontactrequests, 1541 'includeprivacyinfo' => $includeprivacyinfo, 1542 'memberlimit' => $memberlimit, 1543 'memberoffset' => $memberoffset, 1544 'messagelimit' => $messagelimit, 1545 'messageoffset' => $messageoffset, 1546 'newestmessagesfirst' => $newestmessagesfirst 1547 ]; 1548 self::validate_parameters(self::get_conversation_between_users_parameters(), $params); 1549 1550 $systemcontext = context_system::instance(); 1551 self::validate_context($systemcontext); 1552 1553 $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]); 1554 $conversation = null; 1555 1556 if ($conversationid) { 1557 $conversation = \core_message\api::get_conversation( 1558 $params['userid'], 1559 $conversationid, 1560 $params['includecontactrequests'], 1561 $params['includeprivacyinfo'], 1562 $params['memberlimit'], 1563 $params['memberoffset'], 1564 $params['messagelimit'], 1565 $params['messageoffset'], 1566 $params['newestmessagesfirst'] 1567 ); 1568 } 1569 1570 if ($conversation) { 1571 return $conversation; 1572 } else { 1573 // We have to throw an exception here because the external functions annoyingly 1574 // don't accept null to be returned for a single structure. 1575 throw new \moodle_exception('errorconversationdoesnotexist', 'message'); 1576 } 1577 } 1578 1579 /** 1580 * Get conversation returns. 1581 * 1582 * @return external_single_structure 1583 */ 1584 public static function get_conversation_between_users_returns() { 1585 return self::get_conversation_structure(true); 1586 } 1587 1588 /** 1589 * Get self-conversation parameters. 1590 * 1591 * @return external_function_parameters 1592 */ 1593 public static function get_self_conversation_parameters() { 1594 return new external_function_parameters( 1595 array( 1596 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'), 1597 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100), 1598 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0), 1599 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true) 1600 ) 1601 ); 1602 } 1603 1604 /** 1605 * Get a single self-conversation. 1606 * 1607 * @param int $userid The user id to get the self-conversation for 1608 * @param int $messagelimit Limit number of messages to load 1609 * @param int $messageoffset Offset the messages 1610 * @param bool $newestmessagesfirst Order messages by newest first 1611 * @return stdClass 1612 * @throws \moodle_exception if the messaging feature is disabled on the site. 1613 * @since Moodle 3.7 1614 */ 1615 public static function get_self_conversation( 1616 int $userid, 1617 int $messagelimit = 0, 1618 int $messageoffset = 0, 1619 bool $newestmessagesfirst = true 1620 ) { 1621 global $CFG; 1622 1623 // All the standard BL checks. 1624 if (empty($CFG->messaging)) { 1625 throw new moodle_exception('disabled', 'message'); 1626 } 1627 1628 $params = [ 1629 'userid' => $userid, 1630 'messagelimit' => $messagelimit, 1631 'messageoffset' => $messageoffset, 1632 'newestmessagesfirst' => $newestmessagesfirst 1633 ]; 1634 self::validate_parameters(self::get_self_conversation_parameters(), $params); 1635 1636 $systemcontext = context_system::instance(); 1637 self::validate_context($systemcontext); 1638 1639 $conversation = \core_message\api::get_self_conversation($params['userid']); 1640 1641 if ($conversation) { 1642 $conversation = \core_message\api::get_conversation( 1643 $params['userid'], 1644 $conversation->id, 1645 false, 1646 false, 1647 0, 1648 0, 1649 $params['messagelimit'], 1650 $params['messageoffset'], 1651 $params['newestmessagesfirst'] 1652 ); 1653 } 1654 1655 if ($conversation) { 1656 return $conversation; 1657 } else { 1658 // We have to throw an exception here because the external functions annoyingly 1659 // don't accept null to be returned for a single structure. 1660 throw new \moodle_exception('errorconversationdoesnotexist', 'message'); 1661 } 1662 } 1663 1664 /** 1665 * Get conversation returns. 1666 * 1667 * @return external_single_structure 1668 */ 1669 public static function get_self_conversation_returns() { 1670 return self::get_conversation_structure(); 1671 } 1672 1673 /** 1674 * The conversation messages parameters. 1675 * 1676 * @return external_function_parameters 1677 * @since 3.6 1678 */ 1679 public static function get_conversation_messages_parameters() { 1680 return new external_function_parameters( 1681 array( 1682 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'), 1683 'convid' => new external_value(PARAM_INT, 'The conversation id'), 1684 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0), 1685 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0), 1686 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false), 1687 'timefrom' => new external_value(PARAM_INT, 1688 'The timestamp from which the messages were created', VALUE_DEFAULT, 0), 1689 ) 1690 ); 1691 } 1692 1693 /** 1694 * Get conversation messages. 1695 * 1696 * @param int $currentuserid The current user's id. 1697 * @param int $convid The conversation id. 1698 * @param int $limitfrom Return a subset of records, starting at this point (optional). 1699 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set). 1700 * @param bool $newest True for getting first newest messages, false otherwise. 1701 * @param int $timefrom The time from the conversation messages to get. 1702 * @return array The messages and members who have sent some of these messages. 1703 * @throws moodle_exception 1704 * @since 3.6 1705 */ 1706 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0, 1707 bool $newest = false, int $timefrom = 0) { 1708 global $CFG, $USER; 1709 1710 // Check if messaging is enabled. 1711 if (empty($CFG->messaging)) { 1712 throw new moodle_exception('disabled', 'message'); 1713 } 1714 1715 $systemcontext = context_system::instance(); 1716 1717 $params = array( 1718 'currentuserid' => $currentuserid, 1719 'convid' => $convid, 1720 'limitfrom' => $limitfrom, 1721 'limitnum' => $limitnum, 1722 'newest' => $newest, 1723 'timefrom' => $timefrom, 1724 ); 1725 $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params); 1726 self::validate_context($systemcontext); 1727 1728 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 1729 throw new moodle_exception('You do not have permission to perform this action.'); 1730 } 1731 1732 // Check that the user belongs to the conversation. 1733 if (!\core_message\api::is_user_in_conversation($params['currentuserid'], $params['convid'])) { 1734 throw new moodle_exception('User is not part of conversation.'); 1735 } 1736 1737 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC'; 1738 1739 // We need to enforce a one second delay on messages to avoid race conditions of current 1740 // messages still being sent. 1741 // 1742 // There is a chance that we could request messages before the current time's 1743 // second has elapsed and while other messages are being sent in that same second. In which 1744 // case those messages will be lost. 1745 // 1746 // Instead we ignore the current time in the result set to ensure that second is allowed to finish. 1747 $timeto = empty($params['timefrom']) ? 0 : time() - 1; 1748 1749 // No requesting messages from the current time, as stated above. 1750 if ($params['timefrom'] == time()) { 1751 $messages = []; 1752 } else { 1753 $messages = \core_message\api::get_conversation_messages( 1754 $params['currentuserid'], 1755 $params['convid'], 1756 $params['limitfrom'], 1757 $params['limitnum'], 1758 $sort, 1759 $params['timefrom'], 1760 $timeto); 1761 } 1762 1763 return $messages; 1764 } 1765 1766 /** 1767 * The messagearea messages return structure. 1768 * 1769 * @return external_single_structure 1770 * @since 3.6 1771 */ 1772 public static function get_conversation_messages_returns() { 1773 return new external_single_structure( 1774 array( 1775 'id' => new external_value(PARAM_INT, 'The conversation id'), 1776 'members' => new external_multiple_structure( 1777 self::get_conversation_member_structure() 1778 ), 1779 'messages' => new external_multiple_structure( 1780 self::get_conversation_message_structure() 1781 ), 1782 ) 1783 ); 1784 } 1785 1786 /** 1787 * The user contacts return parameters. 1788 * 1789 * @return external_function_parameters 1790 */ 1791 public static function get_user_contacts_parameters() { 1792 return new external_function_parameters( 1793 array( 1794 'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'), 1795 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0), 1796 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0) 1797 ) 1798 ); 1799 } 1800 1801 /** 1802 * Get user contacts. 1803 * 1804 * @param int $userid The id of the user who we are viewing conversations for 1805 * @param int $limitfrom 1806 * @param int $limitnum 1807 * @return array 1808 * @throws moodle_exception 1809 */ 1810 public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) { 1811 global $CFG, $USER; 1812 1813 // Check if messaging is enabled. 1814 if (empty($CFG->messaging)) { 1815 throw new moodle_exception('disabled', 'message'); 1816 } 1817 1818 $systemcontext = context_system::instance(); 1819 1820 $params = array( 1821 'userid' => $userid, 1822 'limitfrom' => $limitfrom, 1823 'limitnum' => $limitnum 1824 ); 1825 $params = self::validate_parameters(self::get_user_contacts_parameters(), $params); 1826 self::validate_context($systemcontext); 1827 1828 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 1829 throw new moodle_exception('You do not have permission to perform this action.'); 1830 } 1831 1832 return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']); 1833 } 1834 1835 /** 1836 * The user contacts return structure. 1837 * 1838 * @return external_multiple_structure 1839 */ 1840 public static function get_user_contacts_returns() { 1841 return new external_multiple_structure( 1842 self::get_conversation_member_structure() 1843 ); 1844 } 1845 1846 /** 1847 * Search contacts parameters description. 1848 * 1849 * @return external_function_parameters 1850 * @since Moodle 2.5 1851 */ 1852 public static function search_contacts_parameters() { 1853 return new external_function_parameters( 1854 array( 1855 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'), 1856 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses', 1857 VALUE_DEFAULT, false) 1858 ) 1859 ); 1860 } 1861 1862 /** 1863 * Search contacts. 1864 * 1865 * @param string $searchtext query string. 1866 * @param bool $onlymycourses limit the search to the user's courses only. 1867 * @return external_description 1868 * @since Moodle 2.5 1869 */ 1870 public static function search_contacts($searchtext, $onlymycourses = false) { 1871 global $CFG, $USER, $PAGE; 1872 require_once($CFG->dirroot . '/user/lib.php'); 1873 1874 // Check if messaging is enabled. 1875 if (empty($CFG->messaging)) { 1876 throw new moodle_exception('disabled', 'message'); 1877 } 1878 1879 require_once($CFG->libdir . '/enrollib.php'); 1880 1881 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses); 1882 $params = self::validate_parameters(self::search_contacts_parameters(), $params); 1883 1884 // Extra validation, we do not allow empty queries. 1885 if ($params['searchtext'] === '') { 1886 throw new moodle_exception('querystringcannotbeempty'); 1887 } 1888 1889 $courseids = array(); 1890 if ($params['onlymycourses']) { 1891 $mycourses = enrol_get_my_courses(array('id')); 1892 foreach ($mycourses as $mycourse) { 1893 $courseids[] = $mycourse->id; 1894 } 1895 } else { 1896 $courseids[] = SITEID; 1897 } 1898 1899 // Retrieving the users matching the query. 1900 $users = message_search_users($courseids, $params['searchtext']); 1901 $results = array(); 1902 foreach ($users as $user) { 1903 $results[$user->id] = $user; 1904 } 1905 1906 // Reorganising information. 1907 foreach ($results as &$user) { 1908 $newuser = array( 1909 'id' => $user->id, 1910 'fullname' => fullname($user) 1911 ); 1912 1913 // Avoid undefined property notice as phone not specified. 1914 $user->phone1 = null; 1915 $user->phone2 = null; 1916 1917 $userpicture = new user_picture($user); 1918 $userpicture->size = 1; // Size f1. 1919 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false); 1920 $userpicture->size = 0; // Size f2. 1921 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false); 1922 1923 $user = $newuser; 1924 } 1925 1926 return $results; 1927 } 1928 1929 /** 1930 * Search contacts return description. 1931 * 1932 * @return external_description 1933 * @since Moodle 2.5 1934 */ 1935 public static function search_contacts_returns() { 1936 return new external_multiple_structure( 1937 new external_single_structure( 1938 array( 1939 'id' => new external_value(PARAM_INT, 'User ID'), 1940 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'), 1941 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL), 1942 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL) 1943 ) 1944 ), 1945 'List of contacts' 1946 ); 1947 } 1948 1949 /** 1950 * Get messages parameters description. 1951 * 1952 * @return external_function_parameters 1953 * @since 2.8 1954 */ 1955 public static function get_messages_parameters() { 1956 return new external_function_parameters( 1957 array( 1958 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED), 1959 'useridfrom' => new external_value( 1960 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user', 1961 VALUE_DEFAULT, 0), 1962 'type' => new external_value( 1963 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both', 1964 VALUE_DEFAULT, 'both'), 1965 'read' => new external_value(PARAM_INT, '1 for getting read messages, 0 for unread, 2 for both', 1966 VALUE_DEFAULT, 1), 1967 'newestfirst' => new external_value( 1968 PARAM_BOOL, 'true for ordering by newest first, false for oldest first', 1969 VALUE_DEFAULT, true), 1970 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0), 1971 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0) 1972 ) 1973 ); 1974 } 1975 1976 /** 1977 * Get messages function implementation. 1978 * 1979 * @since 2.8 1980 * @throws invalid_parameter_exception 1981 * @throws moodle_exception 1982 * @param int $useridto the user id who received the message 1983 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user 1984 * @param string $type type of message to return, expected values: notifications, conversations and both 1985 * @param int $read 1 for getting read messages, 0 for unread, 2 for both 1986 * @param bool $newestfirst true for ordering by newest first, false for oldest first 1987 * @param int $limitfrom limit from 1988 * @param int $limitnum limit num 1989 * @return external_description 1990 */ 1991 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = MESSAGE_GET_READ, 1992 $newestfirst = true, $limitfrom = 0, $limitnum = 0) { 1993 global $CFG, $USER, $PAGE; 1994 1995 $warnings = array(); 1996 1997 $params = array( 1998 'useridto' => $useridto, 1999 'useridfrom' => $useridfrom, 2000 'type' => $type, 2001 'read' => $read, 2002 'newestfirst' => $newestfirst, 2003 'limitfrom' => $limitfrom, 2004 'limitnum' => $limitnum 2005 ); 2006 2007 $params = self::validate_parameters(self::get_messages_parameters(), $params); 2008 2009 $context = context_system::instance(); 2010 self::validate_context($context); 2011 2012 $useridto = $params['useridto']; 2013 $useridfrom = $params['useridfrom']; 2014 $type = $params['type']; 2015 $read = $params['read']; 2016 $newestfirst = $params['newestfirst']; 2017 $limitfrom = $params['limitfrom']; 2018 $limitnum = $params['limitnum']; 2019 2020 $allowedvalues = array('notifications', 'conversations', 'both'); 2021 if (!in_array($type, $allowedvalues)) { 2022 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' . 2023 'allowed values are: ' . implode(',', $allowedvalues)); 2024 } 2025 2026 // Check if private messaging between users is allowed. 2027 if (empty($CFG->messaging)) { 2028 // If we are retreiving only conversations, and messaging is disabled, throw an exception. 2029 if ($type == "conversations") { 2030 throw new moodle_exception('disabled', 'message'); 2031 } 2032 if ($type == "both") { 2033 $warning = array(); 2034 $warning['item'] = 'message'; 2035 $warning['itemid'] = $USER->id; 2036 $warning['warningcode'] = '1'; 2037 $warning['message'] = 'Private messages (conversations) are not enabled in this site. 2038 Only notifications will be returned'; 2039 $warnings[] = $warning; 2040 } 2041 } 2042 2043 if (!empty($useridto)) { 2044 if (core_user::is_real_user($useridto)) { 2045 $userto = core_user::get_user($useridto, '*', MUST_EXIST); 2046 } else { 2047 throw new moodle_exception('invaliduser'); 2048 } 2049 } 2050 2051 if (!empty($useridfrom)) { 2052 // We use get_user here because the from user can be the noreply or support user. 2053 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST); 2054 } 2055 2056 // Check if the current user is the sender/receiver or just a privileged user. 2057 if ($useridto != $USER->id and $useridfrom != $USER->id and 2058 !has_capability('moodle/site:readallmessages', $context)) { 2059 throw new moodle_exception('accessdenied', 'admin'); 2060 } 2061 2062 // Which type of messages to retrieve. 2063 $notifications = -1; 2064 if ($type != 'both') { 2065 $notifications = ($type == 'notifications') ? 1 : 0; 2066 } 2067 2068 $orderdirection = $newestfirst ? 'DESC' : 'ASC'; 2069 $sort = "mr.timecreated $orderdirection"; 2070 2071 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) { 2072 $canviewfullname = has_capability('moodle/site:viewfullnames', $context); 2073 2074 // In some cases, we don't need to get the to/from user objects from the sql query. 2075 $userfromfullname = ''; 2076 $usertofullname = ''; 2077 2078 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there. 2079 if (!empty($useridto)) { 2080 $usertofullname = fullname($userto, $canviewfullname); 2081 // The user from may or may not be filled. 2082 if (!empty($useridfrom)) { 2083 $userfromfullname = fullname($userfrom, $canviewfullname); 2084 } 2085 } else { 2086 // If the useridto field is empty, the useridfrom must be filled. 2087 $userfromfullname = fullname($userfrom, $canviewfullname); 2088 } 2089 foreach ($messages as $mid => $message) { 2090 2091 if (!$message->notification) { 2092 // Do not return deleted messages. 2093 if (($useridto == $USER->id and $message->timeusertodeleted) or 2094 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) { 2095 unset($messages[$mid]); 2096 continue; 2097 } 2098 } else { 2099 // Return iconurl for notifications. 2100 if (!isset($output)) { 2101 $output = $PAGE->get_renderer('core'); 2102 } 2103 2104 if (!empty($message->component) && substr($message->component, 0, 4) == 'mod_') { 2105 $iconurl = $output->image_url('monologo', $message->component); 2106 } else { 2107 $iconurl = $output->image_url('i/marker', 'core'); 2108 } 2109 2110 $message->iconurl = clean_param($iconurl->out(), PARAM_URL); 2111 } 2112 2113 // We need to get the user from the query. 2114 if (empty($userfromfullname)) { 2115 // Check for non-reply and support users. 2116 if (core_user::is_real_user($message->useridfrom)) { 2117 $user = new stdClass(); 2118 $user = username_load_fields_from_object($user, $message, 'userfrom'); 2119 $message->userfromfullname = fullname($user, $canviewfullname); 2120 } else { 2121 $user = core_user::get_user($message->useridfrom); 2122 $message->userfromfullname = fullname($user, $canviewfullname); 2123 } 2124 } else { 2125 $message->userfromfullname = $userfromfullname; 2126 } 2127 2128 // We need to get the user from the query. 2129 if (empty($usertofullname)) { 2130 $user = new stdClass(); 2131 $user = username_load_fields_from_object($user, $message, 'userto'); 2132 $message->usertofullname = fullname($user, $canviewfullname); 2133 } else { 2134 $message->usertofullname = $usertofullname; 2135 } 2136 2137 // Clean subject of html. 2138 $message->subject = clean_param($message->subject, PARAM_TEXT); 2139 $message->text = message_format_message_text($message); 2140 $messages[$mid] = (array) $message; 2141 } 2142 } 2143 2144 $results = array( 2145 'messages' => $messages, 2146 'warnings' => $warnings 2147 ); 2148 2149 return $results; 2150 } 2151 2152 /** 2153 * Get messages return description. 2154 * 2155 * @return external_single_structure 2156 * @since 2.8 2157 */ 2158 public static function get_messages_returns() { 2159 return new external_single_structure( 2160 array( 2161 'messages' => new external_multiple_structure( 2162 new external_single_structure( 2163 array( 2164 'id' => new external_value(PARAM_INT, 'Message id'), 2165 'useridfrom' => new external_value(PARAM_INT, 'User from id'), 2166 'useridto' => new external_value(PARAM_INT, 'User to id'), 2167 'subject' => new external_value(PARAM_TEXT, 'The message subject'), 2168 'text' => new external_value(PARAM_RAW, 'The message text formated'), 2169 'fullmessage' => new external_value(PARAM_RAW, 'The message'), 2170 'fullmessageformat' => new external_format_value('fullmessage'), 2171 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'), 2172 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'), 2173 'notification' => new external_value(PARAM_INT, 'Is a notification?'), 2174 'contexturl' => new external_value(PARAM_RAW, 'Context URL'), 2175 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'), 2176 'timecreated' => new external_value(PARAM_INT, 'Time created'), 2177 'timeread' => new external_value(PARAM_INT, 'Time read'), 2178 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'), 2179 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'), 2180 'component' => new external_value(PARAM_TEXT, 'The component that generated the notification', 2181 VALUE_OPTIONAL), 2182 'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL), 2183 'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor. 2184 The data here is serialised using json_encode().', VALUE_OPTIONAL), 2185 'iconurl' => new external_value(PARAM_URL, 'URL for icon, only for notifications.', VALUE_OPTIONAL), 2186 ), 'message' 2187 ) 2188 ), 2189 'warnings' => new external_warnings() 2190 ) 2191 ); 2192 } 2193 2194 /** 2195 * Mark all notifications as read parameters description. 2196 * 2197 * @return external_function_parameters 2198 * @since 3.2 2199 */ 2200 public static function mark_all_notifications_as_read_parameters() { 2201 return new external_function_parameters( 2202 array( 2203 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED), 2204 'useridfrom' => new external_value( 2205 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user', 2206 VALUE_DEFAULT, 0), 2207 'timecreatedto' => new external_value( 2208 PARAM_INT, 'mark messages created before this time as read, 0 for all messages', 2209 VALUE_DEFAULT, 0), 2210 ) 2211 ); 2212 } 2213 2214 /** 2215 * Mark all notifications as read function. 2216 * 2217 * @since 3.2 2218 * @throws invalid_parameter_exception 2219 * @throws moodle_exception 2220 * @param int $useridto the user id who received the message 2221 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user 2222 * @param int $timecreatedto mark message created before this time as read, 0 for all messages 2223 * @return external_description 2224 */ 2225 public static function mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto = 0) { 2226 global $USER; 2227 2228 $params = self::validate_parameters( 2229 self::mark_all_notifications_as_read_parameters(), 2230 array( 2231 'useridto' => $useridto, 2232 'useridfrom' => $useridfrom, 2233 'timecreatedto' => $timecreatedto, 2234 ) 2235 ); 2236 2237 $context = context_system::instance(); 2238 self::validate_context($context); 2239 2240 $useridto = $params['useridto']; 2241 $useridfrom = $params['useridfrom']; 2242 $timecreatedto = $params['timecreatedto']; 2243 2244 if (!empty($useridto)) { 2245 if (core_user::is_real_user($useridto)) { 2246 $userto = core_user::get_user($useridto, '*', MUST_EXIST); 2247 } else { 2248 throw new moodle_exception('invaliduser'); 2249 } 2250 } 2251 2252 if (!empty($useridfrom)) { 2253 // We use get_user here because the from user can be the noreply or support user. 2254 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST); 2255 } 2256 2257 // Check if the current user is the sender/receiver or just a privileged user. 2258 if ($useridto != $USER->id and $useridfrom != $USER->id and 2259 // The deleteanymessage cap seems more reasonable here than readallmessages. 2260 !has_capability('moodle/site:deleteanymessage', $context)) { 2261 throw new moodle_exception('accessdenied', 'admin'); 2262 } 2263 2264 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto); 2265 2266 return true; 2267 } 2268 2269 /** 2270 * Mark all notifications as read return description. 2271 * 2272 * @return external_single_structure 2273 * @since 3.2 2274 */ 2275 public static function mark_all_notifications_as_read_returns() { 2276 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise'); 2277 } 2278 2279 /** 2280 * Get unread conversations count parameters description. 2281 * 2282 * @return external_function_parameters 2283 * @since 3.2 2284 */ 2285 public static function get_unread_conversations_count_parameters() { 2286 return new external_function_parameters( 2287 array( 2288 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED), 2289 ) 2290 ); 2291 } 2292 2293 /** 2294 * Get unread messages count function. 2295 * 2296 * @since 3.2 2297 * @throws invalid_parameter_exception 2298 * @throws moodle_exception 2299 * @param int $useridto the user id who received the message 2300 * @return external_description 2301 */ 2302 public static function get_unread_conversations_count($useridto) { 2303 global $USER, $CFG; 2304 2305 // Check if messaging is enabled. 2306 if (empty($CFG->messaging)) { 2307 throw new moodle_exception('disabled', 'message'); 2308 } 2309 2310 $params = self::validate_parameters( 2311 self::get_unread_conversations_count_parameters(), 2312 array('useridto' => $useridto) 2313 ); 2314 2315 $context = context_system::instance(); 2316 self::validate_context($context); 2317 2318 $useridto = $params['useridto']; 2319 2320 if (!empty($useridto)) { 2321 if (core_user::is_real_user($useridto)) { 2322 $userto = core_user::get_user($useridto, '*', MUST_EXIST); 2323 } else { 2324 throw new moodle_exception('invaliduser'); 2325 } 2326 } else { 2327 $useridto = $USER->id; 2328 } 2329 2330 // Check if the current user is the receiver or just a privileged user. 2331 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) { 2332 throw new moodle_exception('accessdenied', 'admin'); 2333 } 2334 2335 return \core_message\api::count_unread_conversations($userto); 2336 } 2337 2338 /** 2339 * Get unread conversations count return description. 2340 * 2341 * @return external_single_structure 2342 * @since 3.2 2343 */ 2344 public static function get_unread_conversations_count_returns() { 2345 return new external_value(PARAM_INT, 'The count of unread messages for the user'); 2346 } 2347 2348 /** 2349 * Get blocked users parameters description. 2350 * 2351 * @return external_function_parameters 2352 * @since 2.9 2353 */ 2354 public static function get_blocked_users_parameters() { 2355 return new external_function_parameters( 2356 array( 2357 'userid' => new external_value(PARAM_INT, 2358 'the user whose blocked users we want to retrieve', 2359 VALUE_REQUIRED), 2360 ) 2361 ); 2362 } 2363 2364 /** 2365 * Retrieve a list of users blocked 2366 * 2367 * @param int $userid the user whose blocked users we want to retrieve 2368 * @return external_description 2369 * @since 2.9 2370 */ 2371 public static function get_blocked_users($userid) { 2372 global $CFG, $USER, $PAGE; 2373 2374 // Warnings array, it can be empty at the end but is mandatory. 2375 $warnings = array(); 2376 2377 // Validate params. 2378 $params = array( 2379 'userid' => $userid 2380 ); 2381 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params); 2382 $userid = $params['userid']; 2383 2384 // Validate context. 2385 $context = context_system::instance(); 2386 self::validate_context($context); 2387 2388 // Check if private messaging between users is allowed. 2389 if (empty($CFG->messaging)) { 2390 throw new moodle_exception('disabled', 'message'); 2391 } 2392 2393 $user = core_user::get_user($userid, '*', MUST_EXIST); 2394 core_user::require_active_user($user); 2395 2396 // Check if we have permissions for retrieve the information. 2397 $capability = 'moodle/site:manageallmessaging'; 2398 if (($USER->id != $userid) && !has_capability($capability, $context)) { 2399 throw new required_capability_exception($context, $capability, 'nopermissions', ''); 2400 } 2401 2402 // Now, we can get safely all the blocked users. 2403 $users = \core_message\api::get_blocked_users($user->id); 2404 2405 $blockedusers = array(); 2406 foreach ($users as $user) { 2407 $newuser = array( 2408 'id' => $user->id, 2409 'fullname' => fullname($user), 2410 ); 2411 2412 $userpicture = new user_picture($user); 2413 $userpicture->size = 1; // Size f1. 2414 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false); 2415 2416 $blockedusers[] = $newuser; 2417 } 2418 2419 $results = array( 2420 'users' => $blockedusers, 2421 'warnings' => $warnings 2422 ); 2423 return $results; 2424 } 2425 2426 /** 2427 * Get blocked users return description. 2428 * 2429 * @return external_single_structure 2430 * @since 2.9 2431 */ 2432 public static function get_blocked_users_returns() { 2433 return new external_single_structure( 2434 array( 2435 'users' => new external_multiple_structure( 2436 new external_single_structure( 2437 array( 2438 'id' => new external_value(PARAM_INT, 'User ID'), 2439 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'), 2440 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL) 2441 ) 2442 ), 2443 'List of blocked users' 2444 ), 2445 'warnings' => new external_warnings() 2446 ) 2447 ); 2448 } 2449 2450 /** 2451 * Returns description of method parameters 2452 * 2453 * @return external_function_parameters 2454 * @since 2.9 2455 */ 2456 public static function mark_message_read_parameters() { 2457 return new external_function_parameters( 2458 array( 2459 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'), 2460 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read', 2461 VALUE_DEFAULT, 0) 2462 ) 2463 ); 2464 } 2465 2466 /** 2467 * Mark a single message as read, trigger message_viewed event 2468 * 2469 * @param int $messageid id of the message (in the message table) 2470 * @param int $timeread timestamp for when the message should be marked read 2471 * @return external_description 2472 * @throws invalid_parameter_exception 2473 * @throws moodle_exception 2474 * @since 2.9 2475 */ 2476 public static function mark_message_read($messageid, $timeread) { 2477 global $CFG, $DB, $USER; 2478 2479 // Check if private messaging between users is allowed. 2480 if (empty($CFG->messaging)) { 2481 throw new moodle_exception('disabled', 'message'); 2482 } 2483 2484 // Warnings array, it can be empty at the end but is mandatory. 2485 $warnings = array(); 2486 2487 // Validate params. 2488 $params = array( 2489 'messageid' => $messageid, 2490 'timeread' => $timeread 2491 ); 2492 $params = self::validate_parameters(self::mark_message_read_parameters(), $params); 2493 2494 if (empty($params['timeread'])) { 2495 $timeread = time(); 2496 } else { 2497 $timeread = $params['timeread']; 2498 } 2499 2500 // Validate context. 2501 $context = context_system::instance(); 2502 self::validate_context($context); 2503 2504 $sql = "SELECT m.*, mcm.userid as useridto 2505 FROM {messages} m 2506 INNER JOIN {message_conversations} mc 2507 ON m.conversationid = mc.id 2508 INNER JOIN {message_conversation_members} mcm 2509 ON mcm.conversationid = mc.id 2510 LEFT JOIN {message_user_actions} mua 2511 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?) 2512 WHERE mua.id is NULL 2513 AND mcm.userid != m.useridfrom 2514 AND m.id = ?"; 2515 $messageparams = []; 2516 $messageparams[] = $USER->id; 2517 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ; 2518 $messageparams[] = $params['messageid']; 2519 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST); 2520 2521 if ($message->useridto != $USER->id) { 2522 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read'); 2523 } 2524 2525 \core_message\api::mark_message_as_read($USER->id, $message, $timeread); 2526 2527 $results = array( 2528 'messageid' => $message->id, 2529 'warnings' => $warnings 2530 ); 2531 return $results; 2532 } 2533 2534 /** 2535 * Returns description of method result value 2536 * 2537 * @return external_description 2538 * @since 2.9 2539 */ 2540 public static function mark_message_read_returns() { 2541 return new external_single_structure( 2542 array( 2543 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'), 2544 'warnings' => new external_warnings() 2545 ) 2546 ); 2547 } 2548 2549 /** 2550 * Returns description of method parameters 2551 * 2552 * @return external_function_parameters 2553 */ 2554 public static function mark_notification_read_parameters() { 2555 return new external_function_parameters( 2556 array( 2557 'notificationid' => new external_value(PARAM_INT, 'id of the notification'), 2558 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read', 2559 VALUE_DEFAULT, 0) 2560 ) 2561 ); 2562 } 2563 2564 /** 2565 * Mark a single notification as read. 2566 * 2567 * This will trigger a 'notification_viewed' event. 2568 * 2569 * @param int $notificationid id of the notification 2570 * @param int $timeread timestamp for when the notification should be marked read 2571 * @return external_description 2572 * @throws invalid_parameter_exception 2573 * @throws moodle_exception 2574 */ 2575 public static function mark_notification_read($notificationid, $timeread) { 2576 global $CFG, $DB, $USER; 2577 2578 // Warnings array, it can be empty at the end but is mandatory. 2579 $warnings = array(); 2580 2581 // Validate params. 2582 $params = array( 2583 'notificationid' => $notificationid, 2584 'timeread' => $timeread 2585 ); 2586 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params); 2587 2588 if (empty($params['timeread'])) { 2589 $timeread = time(); 2590 } else { 2591 $timeread = $params['timeread']; 2592 } 2593 2594 // Validate context. 2595 $context = context_system::instance(); 2596 self::validate_context($context); 2597 2598 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST); 2599 2600 if ($notification->useridto != $USER->id) { 2601 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' . 2602 'notification as read'); 2603 } 2604 2605 \core_message\api::mark_notification_as_read($notification, $timeread); 2606 2607 $results = array( 2608 'notificationid' => $notification->id, 2609 'warnings' => $warnings 2610 ); 2611 2612 return $results; 2613 } 2614 2615 /** 2616 * Returns description of method result value 2617 * 2618 * @return external_description 2619 */ 2620 public static function mark_notification_read_returns() { 2621 return new external_single_structure( 2622 array( 2623 'notificationid' => new external_value(PARAM_INT, 'id of the notification'), 2624 'warnings' => new external_warnings() 2625 ) 2626 ); 2627 } 2628 2629 /** 2630 * Mark all conversation messages as read parameters description. 2631 * 2632 * @return external_function_parameters 2633 * @since 3.6 2634 */ 2635 public static function mark_all_conversation_messages_as_read_parameters() { 2636 return new external_function_parameters( 2637 array( 2638 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'), 2639 'conversationid' => 2640 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for') 2641 ) 2642 ); 2643 } 2644 2645 /** 2646 * Mark all conversation messages as read function. 2647 * 2648 * @param int $userid The user id of who we want to delete the conversation for 2649 * @param int $conversationid The id of the conversations 2650 * @since 3.6 2651 */ 2652 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) { 2653 global $CFG; 2654 2655 // Check if messaging is enabled. 2656 if (empty($CFG->messaging)) { 2657 throw new moodle_exception('disabled', 'message'); 2658 } 2659 2660 $params = array( 2661 'userid' => $userid, 2662 'conversationid' => $conversationid, 2663 ); 2664 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params); 2665 2666 $context = context_system::instance(); 2667 self::validate_context($context); 2668 2669 $user = core_user::get_user($params['userid'], '*', MUST_EXIST); 2670 core_user::require_active_user($user); 2671 2672 if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) { 2673 \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']); 2674 } else { 2675 throw new moodle_exception('accessdenied', 'admin'); 2676 } 2677 } 2678 2679 /** 2680 * Mark all conversation messages as read return description. 2681 * 2682 * @return external_warnings 2683 * @since 3.6 2684 */ 2685 public static function mark_all_conversation_messages_as_read_returns() { 2686 return null; 2687 } 2688 2689 /** 2690 * Returns description of method parameters. 2691 * 2692 * @return external_function_parameters 2693 * @since 3.6 2694 */ 2695 public static function delete_conversations_by_id_parameters() { 2696 return new external_function_parameters( 2697 array( 2698 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'), 2699 'conversationids' => new external_multiple_structure( 2700 new external_value(PARAM_INT, 'The id of the conversation'), 2701 'List of conversation IDs' 2702 ), 2703 ) 2704 ); 2705 } 2706 2707 /** 2708 * Deletes a conversation. 2709 * 2710 * @param int $userid The user id of who we want to delete the conversation for 2711 * @param int[] $conversationids The ids of the conversations 2712 * @return array 2713 * @throws moodle_exception 2714 * @since 3.6 2715 */ 2716 public static function delete_conversations_by_id($userid, array $conversationids) { 2717 global $CFG; 2718 2719 // Check if private messaging between users is allowed. 2720 if (empty($CFG->messaging)) { 2721 throw new moodle_exception('disabled', 'message'); 2722 } 2723 2724 // Validate params. 2725 $params = [ 2726 'userid' => $userid, 2727 'conversationids' => $conversationids, 2728 ]; 2729 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params); 2730 2731 // Validate context. 2732 $context = context_system::instance(); 2733 self::validate_context($context); 2734 2735 $user = core_user::get_user($params['userid'], '*', MUST_EXIST); 2736 core_user::require_active_user($user); 2737 2738 foreach ($params['conversationids'] as $conversationid) { 2739 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) { 2740 \core_message\api::delete_conversation_by_id($user->id, $conversationid); 2741 } else { 2742 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'"); 2743 } 2744 } 2745 2746 return []; 2747 } 2748 2749 /** 2750 * Returns description of method result value. 2751 * 2752 * @return external_description 2753 * @since 3.6 2754 */ 2755 public static function delete_conversations_by_id_returns() { 2756 return new external_warnings(); 2757 } 2758 2759 /** 2760 * Returns description of method parameters 2761 * 2762 * @return external_function_parameters 2763 * @since 3.1 2764 */ 2765 public static function delete_message_parameters() { 2766 return new external_function_parameters( 2767 array( 2768 'messageid' => new external_value(PARAM_INT, 'The message id'), 2769 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'), 2770 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true) 2771 ) 2772 ); 2773 } 2774 2775 /** 2776 * Deletes a message 2777 * 2778 * @param int $messageid the message id 2779 * @param int $userid the user id of who we want to delete the message for 2780 * @param bool $read if is a message read (default to true) 2781 * @return external_description 2782 * @throws moodle_exception 2783 * @since 3.1 2784 */ 2785 public static function delete_message($messageid, $userid, $read = true) { 2786 global $CFG; 2787 2788 // Check if private messaging between users is allowed. 2789 if (empty($CFG->messaging)) { 2790 throw new moodle_exception('disabled', 'message'); 2791 } 2792 2793 // Warnings array, it can be empty at the end but is mandatory. 2794 $warnings = array(); 2795 2796 // Validate params. 2797 $params = array( 2798 'messageid' => $messageid, 2799 'userid' => $userid, 2800 'read' => $read 2801 ); 2802 $params = self::validate_parameters(self::delete_message_parameters(), $params); 2803 2804 // Validate context. 2805 $context = context_system::instance(); 2806 self::validate_context($context); 2807 2808 $user = core_user::get_user($params['userid'], '*', MUST_EXIST); 2809 core_user::require_active_user($user); 2810 2811 if (\core_message\api::can_delete_message($user->id, $params['messageid'])) { 2812 $status = \core_message\api::delete_message($user->id, $params['messageid']); 2813 } else { 2814 throw new moodle_exception('You do not have permission to delete this message'); 2815 } 2816 2817 $results = array( 2818 'status' => $status, 2819 'warnings' => $warnings 2820 ); 2821 return $results; 2822 } 2823 2824 /** 2825 * Returns description of method result value 2826 * 2827 * @return external_description 2828 * @since 3.1 2829 */ 2830 public static function delete_message_returns() { 2831 return new external_single_structure( 2832 array( 2833 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'), 2834 'warnings' => new external_warnings() 2835 ) 2836 ); 2837 } 2838 2839 /** 2840 * Returns description of method parameters 2841 * 2842 * @return external_function_parameters 2843 * @since 3.2 2844 */ 2845 public static function message_processor_config_form_parameters() { 2846 return new external_function_parameters( 2847 array( 2848 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED), 2849 'name' => new external_value(PARAM_SAFEDIR, 'The name of the message processor'), 2850 'formvalues' => new external_multiple_structure( 2851 new external_single_structure( 2852 array( 2853 'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED), 2854 'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED), 2855 ) 2856 ), 2857 'Config form values', 2858 VALUE_REQUIRED 2859 ), 2860 ) 2861 ); 2862 } 2863 2864 /** 2865 * Processes a message processor config form. 2866 * 2867 * @param int $userid the user id 2868 * @param string $name the name of the processor 2869 * @param array $formvalues the form values 2870 * @return external_description 2871 * @throws moodle_exception 2872 * @since 3.2 2873 */ 2874 public static function message_processor_config_form($userid, $name, $formvalues) { 2875 global $USER, $CFG; 2876 2877 $params = self::validate_parameters( 2878 self::message_processor_config_form_parameters(), 2879 array( 2880 'userid' => $userid, 2881 'name' => $name, 2882 'formvalues' => $formvalues, 2883 ) 2884 ); 2885 2886 $user = self::validate_preferences_permissions($params['userid']); 2887 2888 $processor = get_message_processor($params['name']); 2889 $preferences = []; 2890 $form = new stdClass(); 2891 2892 foreach ($params['formvalues'] as $formvalue) { 2893 // Curly braces to ensure interpretation is consistent between 2894 // php 5 and php 7. 2895 $form->{$formvalue['name']} = $formvalue['value']; 2896 } 2897 2898 $processor->process_form($form, $preferences); 2899 2900 if (!empty($preferences)) { 2901 set_user_preferences($preferences, $params['userid']); 2902 } 2903 } 2904 2905 /** 2906 * Returns description of method result value 2907 * 2908 * @return external_description 2909 * @since 3.2 2910 */ 2911 public static function message_processor_config_form_returns() { 2912 return null; 2913 } 2914 2915 /** 2916 * Returns description of method parameters 2917 * 2918 * @return external_function_parameters 2919 * @since 3.2 2920 */ 2921 public static function get_message_processor_parameters() { 2922 return new external_function_parameters( 2923 array( 2924 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'), 2925 'name' => new external_value(PARAM_SAFEDIR, 'The name of the message processor', VALUE_REQUIRED), 2926 ) 2927 ); 2928 } 2929 2930 /** 2931 * Get a message processor. 2932 * 2933 * @param int $userid 2934 * @param string $name the name of the processor 2935 * @return external_description 2936 * @throws moodle_exception 2937 * @since 3.2 2938 */ 2939 public static function get_message_processor($userid, $name) { 2940 global $USER, $PAGE, $CFG; 2941 2942 // Check if messaging is enabled. 2943 if (empty($CFG->messaging)) { 2944 throw new moodle_exception('disabled', 'message'); 2945 } 2946 2947 $params = self::validate_parameters( 2948 self::get_message_processor_parameters(), 2949 array( 2950 'userid' => $userid, 2951 'name' => $name, 2952 ) 2953 ); 2954 2955 if (empty($params['userid'])) { 2956 $params['userid'] = $USER->id; 2957 } 2958 2959 $user = core_user::get_user($params['userid'], '*', MUST_EXIST); 2960 core_user::require_active_user($user); 2961 self::validate_context(context_user::instance($params['userid'])); 2962 2963 $processor = get_message_processor($params['name']); 2964 2965 $processoroutput = new \core_message\output\processor($processor, $user); 2966 $renderer = $PAGE->get_renderer('core_message'); 2967 2968 return $processoroutput->export_for_template($renderer); 2969 } 2970 2971 /** 2972 * Returns description of method result value 2973 * 2974 * @return external_description 2975 * @since 3.2 2976 */ 2977 public static function get_message_processor_returns() { 2978 return new external_function_parameters( 2979 array( 2980 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'), 2981 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'), 2982 ) 2983 ); 2984 } 2985 2986 /** 2987 * Check that the user has enough permission to retrieve message or notifications preferences. 2988 * 2989 * @param int $userid the user id requesting the preferences 2990 * @return stdClass full user object 2991 * @throws moodle_exception 2992 * @since Moodle 3.2 2993 */ 2994 protected static function validate_preferences_permissions($userid) { 2995 global $USER; 2996 2997 if (empty($userid)) { 2998 $user = $USER; 2999 } else { 3000 $user = core_user::get_user($userid, '*', MUST_EXIST); 3001 core_user::require_active_user($user); 3002 } 3003 3004 $systemcontext = context_system::instance(); 3005 self::validate_context($systemcontext); 3006 3007 // Check access control. 3008 if ($user->id == $USER->id) { 3009 // Editing own message profile. 3010 require_capability('moodle/user:editownmessageprofile', $systemcontext); 3011 } else { 3012 // Teachers, parents, etc. 3013 $personalcontext = context_user::instance($user->id); 3014 require_capability('moodle/user:editmessageprofile', $personalcontext); 3015 } 3016 return $user; 3017 } 3018 3019 /** 3020 * Returns a notification or message preference structure. 3021 * 3022 * @return external_single_structure the structure 3023 * @since Moodle 3.2 3024 * @todo Remove loggedin and loggedoff from processors structure on MDL-73284. 3025 */ 3026 protected static function get_preferences_structure() { 3027 return new external_single_structure( 3028 array( 3029 'userid' => new external_value(PARAM_INT, 'User id'), 3030 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'), 3031 'processors' => new external_multiple_structure( 3032 new external_single_structure( 3033 array( 3034 'displayname' => new external_value(PARAM_TEXT, 'Display name'), 3035 'name' => new external_value(PARAM_PLUGIN, 'Processor name'), 3036 'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'), 3037 'contextid' => new external_value(PARAM_INT, 'Context id'), 3038 'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'), 3039 ) 3040 ), 3041 'Config form values' 3042 ), 3043 'components' => new external_multiple_structure( 3044 new external_single_structure( 3045 array( 3046 'displayname' => new external_value(PARAM_TEXT, 'Display name'), 3047 'notifications' => new external_multiple_structure( 3048 new external_single_structure( 3049 array( 3050 'displayname' => new external_value(PARAM_TEXT, 'Display name'), 3051 'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'), 3052 'processors' => new external_multiple_structure( 3053 new external_single_structure( 3054 array( 3055 'displayname' => new external_value(PARAM_TEXT, 'Display name'), 3056 'name' => new external_value(PARAM_PLUGIN, 'Processor name'), 3057 'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'), 3058 'lockedmessage' => new external_value(PARAM_TEXT, 3059 'Text to display if locked', VALUE_OPTIONAL), 3060 'userconfigured' => new external_value(PARAM_INT, 'Is configured?'), 3061 'loggedin' => new external_single_structure( 3062 array( 3063 'name' => new external_value(PARAM_NOTAGS, 'Name'), 3064 'displayname' => new external_value(PARAM_TEXT, 'Display name'), 3065 'checked' => new external_value(PARAM_BOOL, 'Is checked?'), 3066 ), 3067 'DEPRECATED ATTRIBUTE - 3068 Kept for backward compatibility, use enabled instead.', 3069 ), 3070 'loggedoff' => new external_single_structure( 3071 array( 3072 'name' => new external_value(PARAM_NOTAGS, 'Name'), 3073 'displayname' => new external_value(PARAM_TEXT, 'Display name'), 3074 'checked' => new external_value(PARAM_BOOL, 'Is checked?'), 3075 ), 3076 'DEPRECATED ATTRIBUTE - 3077 Kept for backward compatibility, use enabled instead.', 3078 ), 3079 'enabled' => new external_value(PARAM_BOOL, 'Is enabled?'), 3080 ) 3081 ), 3082 'Processors values for this notification' 3083 ), 3084 ) 3085 ), 3086 'List of notificaitons for the component' 3087 ), 3088 ) 3089 ), 3090 'Available components' 3091 ), 3092 ) 3093 ); 3094 } 3095 3096 /** 3097 * Returns description of method parameters 3098 * 3099 * @return external_function_parameters 3100 * @since 3.2 3101 */ 3102 public static function get_user_notification_preferences_parameters() { 3103 return new external_function_parameters( 3104 array( 3105 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0) 3106 ) 3107 ); 3108 } 3109 3110 /** 3111 * Get the notification preferences for a given user. 3112 * 3113 * @param int $userid id of the user, 0 for current user 3114 * @return external_description 3115 * @throws moodle_exception 3116 * @since 3.2 3117 */ 3118 public static function get_user_notification_preferences($userid = 0) { 3119 global $PAGE; 3120 3121 $params = self::validate_parameters( 3122 self::get_user_notification_preferences_parameters(), 3123 array( 3124 'userid' => $userid, 3125 ) 3126 ); 3127 $user = self::validate_preferences_permissions($params['userid']); 3128 3129 $processors = get_message_processors(); 3130 $providers = message_get_providers_for_user($user->id); 3131 $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user); 3132 $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user); 3133 3134 $renderer = $PAGE->get_renderer('core_message'); 3135 3136 $result = array( 3137 'warnings' => array(), 3138 'preferences' => $notificationlist->export_for_template($renderer) 3139 ); 3140 return $result; 3141 } 3142 3143 /** 3144 * Returns description of method result value 3145 * 3146 * @return external_description 3147 * @since 3.2 3148 */ 3149 public static function get_user_notification_preferences_returns() { 3150 return new external_function_parameters( 3151 array( 3152 'preferences' => self::get_preferences_structure(), 3153 'warnings' => new external_warnings(), 3154 ) 3155 ); 3156 } 3157 3158 /** 3159 * Returns description of method parameters 3160 * 3161 * @return external_function_parameters 3162 * @since 3.2 3163 */ 3164 public static function get_user_message_preferences_parameters() { 3165 return new external_function_parameters( 3166 array( 3167 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0) 3168 ) 3169 ); 3170 } 3171 3172 /** 3173 * Get the notification preferences for a given user. 3174 * 3175 * @param int $userid id of the user, 0 for current user 3176 * @return external_description 3177 * @throws moodle_exception 3178 * @since 3.2 3179 */ 3180 public static function get_user_message_preferences($userid = 0) { 3181 global $CFG, $PAGE; 3182 3183 $params = self::validate_parameters( 3184 self::get_user_message_preferences_parameters(), 3185 array( 3186 'userid' => $userid, 3187 ) 3188 ); 3189 3190 $user = self::validate_preferences_permissions($params['userid']); 3191 3192 // Filter out enabled, available system_configured and user_configured processors only. 3193 $readyprocessors = array_filter(get_message_processors(), function($processor) { 3194 return $processor->enabled && 3195 $processor->configured && 3196 $processor->object->is_user_configured() && 3197 // Filter out processors that don't have and message preferences to configure. 3198 $processor->object->has_message_preferences(); 3199 }); 3200 3201 $providers = array_filter(message_get_providers_for_user($user->id), function($provider) { 3202 return $provider->component === 'moodle'; 3203 }); 3204 $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user); 3205 $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors, 3206 $providers, $preferences, $user); 3207 3208 $renderer = $PAGE->get_renderer('core_message'); 3209 3210 $entertosend = get_user_preferences('message_entertosend', $CFG->messagingdefaultpressenter, $user); 3211 3212 $result = array( 3213 'warnings' => array(), 3214 'preferences' => $notificationlistoutput->export_for_template($renderer), 3215 'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id), 3216 'entertosend' => $entertosend 3217 ); 3218 return $result; 3219 } 3220 3221 /** 3222 * Returns description of method result value 3223 * 3224 * @return external_description 3225 * @since 3.2 3226 */ 3227 public static function get_user_message_preferences_returns() { 3228 return new external_function_parameters( 3229 array( 3230 'preferences' => self::get_preferences_structure(), 3231 'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'), 3232 'entertosend' => new external_value(PARAM_BOOL, 'User preference for using enter to send messages'), 3233 'warnings' => new external_warnings(), 3234 ) 3235 ); 3236 } 3237 3238 /** 3239 * Returns description of method parameters for the favourite_conversations() method. 3240 * 3241 * @return external_function_parameters 3242 */ 3243 public static function set_favourite_conversations_parameters() { 3244 return new external_function_parameters( 3245 array( 3246 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0), 3247 'conversations' => new external_multiple_structure( 3248 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0) 3249 ) 3250 ) 3251 ); 3252 } 3253 3254 /** 3255 * Favourite a conversation, or list of conversations for a user. 3256 * 3257 * @param int $userid the id of the user, or 0 for the current user. 3258 * @param array $conversationids the list of conversations ids to favourite. 3259 * @return array 3260 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action. 3261 */ 3262 public static function set_favourite_conversations(int $userid, array $conversationids) { 3263 global $CFG, $USER; 3264 3265 // All the business logic checks that really shouldn't be in here. 3266 if (empty($CFG->messaging)) { 3267 throw new moodle_exception('disabled', 'message'); 3268 } 3269 $params = [ 3270 'userid' => $userid, 3271 'conversations' => $conversationids 3272 ]; 3273 $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params); 3274 $systemcontext = context_system::instance(); 3275 self::validate_context($systemcontext); 3276 3277 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 3278 throw new moodle_exception('You do not have permission to perform this action.'); 3279 } 3280 3281 foreach ($params['conversations'] as $conversationid) { 3282 \core_message\api::set_favourite_conversation($conversationid, $params['userid']); 3283 } 3284 3285 return []; 3286 } 3287 3288 /** 3289 * Return a description of the returns for the create_user_favourite_conversations() method. 3290 * 3291 * @return external_description 3292 */ 3293 public static function set_favourite_conversations_returns() { 3294 return new external_warnings(); 3295 } 3296 3297 /** 3298 * Returns description of method parameters for unfavourite_conversations() method. 3299 * 3300 * @return external_function_parameters 3301 */ 3302 public static function unset_favourite_conversations_parameters() { 3303 return new external_function_parameters( 3304 array( 3305 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0), 3306 'conversations' => new external_multiple_structure( 3307 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0) 3308 ) 3309 ) 3310 ); 3311 } 3312 3313 /** 3314 * Unfavourite a conversation, or list of conversations for a user. 3315 * 3316 * @param int $userid the id of the user, or 0 for the current user. 3317 * @param array $conversationids the list of conversations ids unset as favourites. 3318 * @return array 3319 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action. 3320 */ 3321 public static function unset_favourite_conversations(int $userid, array $conversationids) { 3322 global $CFG, $USER; 3323 3324 // All the business logic checks that really shouldn't be in here. 3325 if (empty($CFG->messaging)) { 3326 throw new moodle_exception('disabled', 'message'); 3327 } 3328 $params = [ 3329 'userid' => $userid, 3330 'conversations' => $conversationids 3331 ]; 3332 $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params); 3333 $systemcontext = context_system::instance(); 3334 self::validate_context($systemcontext); 3335 3336 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 3337 throw new moodle_exception('You do not have permission to perform this action.'); 3338 } 3339 3340 foreach ($params['conversations'] as $conversationid) { 3341 \core_message\api::unset_favourite_conversation($conversationid, $params['userid']); 3342 } 3343 3344 return []; 3345 } 3346 3347 /** 3348 * Unset favourite conversations return description. 3349 * 3350 * @return external_description 3351 */ 3352 public static function unset_favourite_conversations_returns() { 3353 return new external_warnings(); 3354 } 3355 3356 /** 3357 * Returns description of method parameters for get_member_info() method. 3358 * 3359 * @return external_function_parameters 3360 */ 3361 public static function get_member_info_parameters() { 3362 return new external_function_parameters( 3363 array( 3364 'referenceuserid' => new external_value(PARAM_INT, 'id of the user'), 3365 'userids' => new external_multiple_structure( 3366 new external_value(PARAM_INT, 'id of members to get') 3367 ), 3368 'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false), 3369 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'include privacy info in response', VALUE_DEFAULT, false) 3370 ) 3371 ); 3372 } 3373 3374 /** 3375 * Returns conversation member info for the supplied users, relative to the supplied referenceuserid. 3376 * 3377 * This is the basic structure used when returning members, and includes information about the relationship between each member 3378 * and the referenceuser, such as a whether the referenceuser has marked the member as a contact, or has blocked them. 3379 * 3380 * @param int $referenceuserid the id of the user which check contact and blocked status. 3381 * @param array $userids 3382 * @return array the array of objects containing member info. 3383 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action. 3384 */ 3385 public static function get_member_info( 3386 int $referenceuserid, 3387 array $userids, 3388 bool $includecontactrequests = false, 3389 bool $includeprivacyinfo = false 3390 ) { 3391 global $CFG, $USER; 3392 3393 // All the business logic checks that really shouldn't be in here. 3394 if (empty($CFG->messaging)) { 3395 throw new moodle_exception('disabled', 'message'); 3396 } 3397 $params = [ 3398 'referenceuserid' => $referenceuserid, 3399 'userids' => $userids, 3400 'includecontactrequests' => $includecontactrequests, 3401 'includeprivacyinfo' => $includeprivacyinfo 3402 ]; 3403 $params = self::validate_parameters(self::get_member_info_parameters(), $params); 3404 $systemcontext = context_system::instance(); 3405 self::validate_context($systemcontext); 3406 3407 if (($USER->id != $referenceuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 3408 throw new moodle_exception('You do not have permission to perform this action.'); 3409 } 3410 3411 return \core_message\helper::get_member_info( 3412 $params['referenceuserid'], 3413 $params['userids'], 3414 $params['includecontactrequests'], 3415 $params['includeprivacyinfo'] 3416 ); 3417 } 3418 3419 /** 3420 * Get member info return description. 3421 * 3422 * @return external_description 3423 */ 3424 public static function get_member_info_returns() { 3425 return new external_multiple_structure( 3426 self::get_conversation_member_structure() 3427 ); 3428 } 3429 3430 /** 3431 * Returns description of method parameters for get_conversation_counts() method. 3432 * 3433 * @return external_function_parameters 3434 */ 3435 public static function get_conversation_counts_parameters() { 3436 return new external_function_parameters( 3437 [ 3438 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0) 3439 ] 3440 ); 3441 } 3442 3443 /** 3444 * Returns an array of conversation counts for the various types of conversations, including favourites. 3445 * 3446 * Return format: 3447 * [ 3448 * 'favourites' => 0, 3449 * 'types' => [ 3450 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0, 3451 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0 3452 * ] 3453 * ] 3454 * 3455 * @param int $userid the id of the user whose counts we are fetching. 3456 * @return array the array of conversation counts, indexed by type. 3457 * @throws moodle_exception if the current user cannot perform this action. 3458 */ 3459 public static function get_conversation_counts(int $userid) { 3460 global $CFG, $USER; 3461 3462 // All the business logic checks that really shouldn't be in here. 3463 if (empty($CFG->messaging)) { 3464 throw new moodle_exception('disabled', 'message'); 3465 } 3466 3467 if (empty($userid)) { 3468 $userid = $USER->id; 3469 } 3470 3471 $params = ['userid' => $userid]; 3472 $params = self::validate_parameters(self::get_conversation_counts_parameters(), $params); 3473 3474 $systemcontext = context_system::instance(); 3475 self::validate_context($systemcontext); 3476 3477 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 3478 throw new moodle_exception('You do not have permission to perform this action.'); 3479 } 3480 3481 return \core_message\api::get_conversation_counts($params['userid']); 3482 } 3483 3484 /** 3485 * Get conversation counts return description. 3486 * 3487 * @return external_description 3488 */ 3489 public static function get_conversation_counts_returns() { 3490 return new external_single_structure( 3491 [ 3492 'favourites' => new external_value(PARAM_INT, 'Total number of favourite conversations'), 3493 'types' => new external_single_structure( 3494 [ 3495 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT, 3496 'Total number of individual conversations'), 3497 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT, 3498 'Total number of group conversations'), 3499 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT, 3500 'Total number of self conversations'), 3501 ] 3502 ), 3503 ] 3504 ); 3505 } 3506 3507 /** 3508 * Returns description of method parameters for get_unread_conversation_counts() method. 3509 * 3510 * @return external_function_parameters 3511 */ 3512 public static function get_unread_conversation_counts_parameters() { 3513 return new external_function_parameters( 3514 [ 3515 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0) 3516 ] 3517 ); 3518 } 3519 3520 /** 3521 * Returns an array of unread conversation counts for the various types of conversations, including favourites. 3522 * 3523 * Return format: 3524 * [ 3525 * 'favourites' => 0, 3526 * 'types' => [ 3527 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0, 3528 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0 3529 * ] 3530 * ] 3531 * 3532 * @param int $userid the id of the user whose counts we are fetching. 3533 * @return array the array of unread conversation counts, indexed by type. 3534 * @throws moodle_exception if the current user cannot perform this action. 3535 */ 3536 public static function get_unread_conversation_counts(int $userid) { 3537 global $CFG, $USER; 3538 3539 // All the business logic checks that really shouldn't be in here. 3540 if (empty($CFG->messaging)) { 3541 throw new moodle_exception('disabled', 'message'); 3542 } 3543 3544 if (empty($userid)) { 3545 $userid = $USER->id; 3546 } 3547 3548 $params = ['userid' => $userid]; 3549 $params = self::validate_parameters(self::get_unread_conversation_counts_parameters(), $params); 3550 3551 $systemcontext = context_system::instance(); 3552 self::validate_context($systemcontext); 3553 3554 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) { 3555 throw new moodle_exception('You do not have permission to perform this action.'); 3556 } 3557 3558 return \core_message\api::get_unread_conversation_counts($params['userid']); 3559 } 3560 3561 /** 3562 * Get unread conversation counts return description. 3563 * 3564 * @return external_description 3565 */ 3566 public static function get_unread_conversation_counts_returns() { 3567 return new external_single_structure( 3568 [ 3569 'favourites' => new external_value(PARAM_INT, 'Total number of unread favourite conversations'), 3570 'types' => new external_single_structure( 3571 [ 3572 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT, 3573 'Total number of unread individual conversations'), 3574 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT, 3575 'Total number of unread group conversations'), 3576 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT, 3577 'Total number of unread self conversations'), 3578 ] 3579 ), 3580 ] 3581 ); 3582 } 3583 3584 /** 3585 * Returns description of method parameters 3586 * 3587 * @return external_function_parameters 3588 * @since 3.7 3589 */ 3590 public static function delete_message_for_all_users_parameters() { 3591 return new external_function_parameters( 3592 array( 3593 'messageid' => new external_value(PARAM_INT, 'The message id'), 3594 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users') 3595 ) 3596 ); 3597 } 3598 /** 3599 * Deletes a message for all users 3600 * 3601 * @param int $messageid the message id 3602 * @param int $userid the user id of who we want to delete the message for all users, is no longer used. 3603 * @return external_description 3604 * @throws moodle_exception 3605 * @since 3.7 3606 */ 3607 public static function delete_message_for_all_users(int $messageid, int $userid) { 3608 global $CFG, $USER; 3609 3610 // Check if private messaging between users is allowed. 3611 if (empty($CFG->messaging)) { 3612 throw new moodle_exception('disabled', 'message'); 3613 } 3614 3615 // Validate params. 3616 $params = array( 3617 'messageid' => $messageid, 3618 'userid' => $userid 3619 ); 3620 $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params); 3621 3622 // Validate context. 3623 $context = context_system::instance(); 3624 self::validate_context($context); 3625 3626 core_user::require_active_user($USER); 3627 3628 // Checks if a user can delete a message for all users. 3629 if (core_message\api::can_delete_message_for_all_users($USER->id, $params['messageid'])) { 3630 \core_message\api::delete_message_for_all_users($params['messageid']); 3631 } else { 3632 throw new moodle_exception('You do not have permission to delete this message for everyone.'); 3633 } 3634 3635 return []; 3636 } 3637 /** 3638 * Returns description of method result value 3639 * 3640 * @return external_description 3641 * @since 3.7 3642 */ 3643 public static function delete_message_for_all_users_returns() { 3644 return new external_warnings(); 3645 } 3646 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body