MDL-66928 core: Move request dirs to system tmp instead of localcache
[moodle.git] / message / externallib.php
blob32504c6acf215b332cad92057bd75dbd57b15a8f
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.
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/>.
18 /**
19 * External message API
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
27 defined('MOODLE_INTERNAL') || die();
29 require_once("$CFG->libdir/externallib.php");
30 require_once($CFG->dirroot . "/message/lib.php");
32 /**
33 * Message external functions
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
41 class core_message_external extends external_api {
42 /**
43 * Returns description of method parameters
45 * @return external_function_parameters
46 * @since Moodle 3.6
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),
64 /**
65 * Send messages from the current USER to a conversation.
67 * This conversation may be any type of conversation, individual or group.
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
74 public static function send_messages_to_conversation(int $conversationid, array $messages = []) {
75 global $CFG, $USER;
77 // Check if messaging is enabled.
78 if (empty($CFG->messaging)) {
79 throw new moodle_exception('disabled', 'message');
82 // Ensure the current user is allowed to run this function.
83 $context = context_system::instance();
84 self::validate_context($context);
86 $params = self::validate_parameters(self::send_messages_to_conversation_parameters(), [
87 'conversationid' => $conversationid,
88 'messages' => $messages
89 ]);
91 $messages = [];
92 foreach ($params['messages'] as $message) {
93 $createdmessage = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
94 $message['textformat']);
95 $createdmessage->text = message_format_message_text((object) [
96 'smallmessage' => $createdmessage->text,
97 'fullmessageformat' => external_validate_format($message['textformat']),
98 'fullmessagetrust' => $createdmessage->fullmessagetrust
99 ]);
100 $messages[] = $createdmessage;
103 return $messages;
107 * Returns description of method result value.
109 * @return external_description
110 * @since Moodle 3.6
112 public static function send_messages_to_conversation_returns() {
113 return new external_multiple_structure(
114 self::get_conversation_message_structure()
120 * Returns description of method parameters
122 * @return external_function_parameters
123 * @since Moodle 2.2
125 public static function send_instant_messages_parameters() {
126 return new external_function_parameters(
127 array(
128 'messages' => new external_multiple_structure(
129 new external_single_structure(
130 array(
131 'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
132 'text' => new external_value(PARAM_RAW, 'the text of the message'),
133 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
134 '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 * Send private messages from the current USER to other users
145 * @param array $messages An array of message to send.
146 * @return array
147 * @since Moodle 2.2
149 public static function send_instant_messages($messages = array()) {
150 global $CFG, $USER, $DB;
152 // Check if messaging is enabled.
153 if (empty($CFG->messaging)) {
154 throw new moodle_exception('disabled', 'message');
157 // Ensure the current user is allowed to run this function
158 $context = context_system::instance();
159 self::validate_context($context);
160 require_capability('moodle/site:sendmessage', $context);
162 // Ensure the current user is allowed to delete message for everyone.
163 $candeletemessagesforallusers = has_capability('moodle/site:deleteanymessage', $context);
165 $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
167 //retrieve all tousers of the messages
168 $receivers = array();
169 foreach($params['messages'] as $message) {
170 $receivers[] = $message['touserid'];
172 list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
173 $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
175 $resultmessages = array();
176 $messageids = array();
177 foreach ($params['messages'] as $message) {
178 $resultmsg = array(); //the infos about the success of the operation
180 // We are going to do some checking.
181 // Code should match /messages/index.php checks.
182 $success = true;
184 // Check the user exists.
185 if (empty($tousers[$message['touserid']])) {
186 $success = false;
187 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
190 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
191 // Check if the recipient can be messaged by the sender.
192 if ($success && !\core_message\api::can_send_message($tousers[$message['touserid']]->id, $USER->id)) {
193 $success = false;
194 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
197 // Now we can send the message (at least try).
198 if ($success) {
199 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
200 $success = message_post_message($USER, $tousers[$message['touserid']],
201 $message['text'], external_validate_format($message['textformat']));
204 // Build the resultmsg.
205 if (isset($message['clientmsgid'])) {
206 $resultmsg['clientmsgid'] = $message['clientmsgid'];
208 if ($success) {
209 $resultmsg['msgid'] = $success;
210 $resultmsg['timecreated'] = time();
211 $resultmsg['candeletemessagesforallusers'] = $candeletemessagesforallusers;
212 $messageids[] = $success;
213 } else {
214 // WARNINGS: for backward compatibility we return this errormessage.
215 // We should have thrown exceptions as these errors prevent results to be returned.
216 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
217 $resultmsg['msgid'] = -1;
218 $resultmsg['errormessage'] = $errormessage;
221 $resultmessages[] = $resultmsg;
224 if (!empty($messageids)) {
225 $messagerecords = $DB->get_records_list(
226 'messages',
227 'id',
228 $messageids,
230 'id, conversationid, smallmessage, fullmessageformat, fullmessagetrust');
231 $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) {
232 $id = $resultmessage['msgid'];
233 $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null;
234 $resultmessage['useridfrom'] = $USER->id;
235 $resultmessage['text'] = message_format_message_text((object) [
236 'smallmessage' => $messagerecords[$id]->smallmessage,
237 'fullmessageformat' => external_validate_format($messagerecords[$id]->fullmessageformat),
238 'fullmessagetrust' => $messagerecords[$id]->fullmessagetrust
240 return $resultmessage;
241 }, $resultmessages);
244 return $resultmessages;
248 * Returns description of method result value
250 * @return external_description
251 * @since Moodle 2.2
253 public static function send_instant_messages_returns() {
254 return new external_multiple_structure(
255 new external_single_structure(
256 array(
257 'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds: id of the created message if it succeeded, -1 when failed'),
258 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
259 'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL),
260 'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL),
261 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
262 'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
263 'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
264 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
265 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
272 * Delete contacts parameters description.
274 * @return external_function_parameters
275 * @since Moodle 2.5
277 public static function delete_contacts_parameters() {
278 return new external_function_parameters(
279 array(
280 'userids' => new external_multiple_structure(
281 new external_value(PARAM_INT, 'User ID'),
282 'List of user IDs'
284 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
285 current user', VALUE_DEFAULT, 0)
291 * Delete contacts.
293 * @param array $userids array of user IDs.
294 * @param int $userid The id of the user we are deleting the contacts for
295 * @return null
296 * @since Moodle 2.5
298 public static function delete_contacts($userids, $userid = 0) {
299 global $CFG, $USER;
301 // Check if messaging is enabled.
302 if (empty($CFG->messaging)) {
303 throw new moodle_exception('disabled', 'message');
306 if (empty($userid)) {
307 $userid = $USER->id;
310 // Validate context.
311 $context = context_system::instance();
312 self::validate_context($context);
314 $params = array('userids' => $userids, 'userid' => $userid);
315 $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
317 $capability = 'moodle/site:manageallmessaging';
318 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
319 throw new required_capability_exception($context, $capability, 'nopermissions', '');
322 foreach ($params['userids'] as $id) {
323 \core_message\api::remove_contact($params['userid'], $id);
326 return null;
330 * Delete contacts return description.
332 * @return external_description
333 * @since Moodle 2.5
335 public static function delete_contacts_returns() {
336 return null;
340 * Mute conversations parameters description.
342 * @return external_function_parameters
344 public static function mute_conversations_parameters() {
345 return new external_function_parameters(
347 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
348 'conversationids' => new external_multiple_structure(
349 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
356 * Mutes conversations.
358 * @param int $userid The id of the user who is blocking
359 * @param array $conversationids The list of conversations being muted
360 * @return external_description
362 public static function mute_conversations(int $userid, array $conversationids) {
363 global $CFG, $USER;
365 // Check if messaging is enabled.
366 if (empty($CFG->messaging)) {
367 throw new moodle_exception('disabled', 'message');
370 // Validate context.
371 $context = context_system::instance();
372 self::validate_context($context);
374 $params = ['userid' => $userid, 'conversationids' => $conversationids];
375 $params = self::validate_parameters(self::mute_conversations_parameters(), $params);
377 $capability = 'moodle/site:manageallmessaging';
378 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
379 throw new required_capability_exception($context, $capability, 'nopermissions', '');
382 foreach ($params['conversationids'] as $conversationid) {
383 if (!\core_message\api::is_conversation_muted($params['userid'], $conversationid)) {
384 \core_message\api::mute_conversation($params['userid'], $conversationid);
388 return [];
392 * Mute conversations return description.
394 * @return external_description
396 public static function mute_conversations_returns() {
397 return new external_warnings();
401 * Unmute conversations parameters description.
403 * @return external_function_parameters
405 public static function unmute_conversations_parameters() {
406 return new external_function_parameters(
408 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
409 'conversationids' => new external_multiple_structure(
410 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
417 * Unmute conversations.
419 * @param int $userid The id of the user who is unblocking
420 * @param array $conversationids The list of conversations being muted
422 public static function unmute_conversations(int $userid, array $conversationids) {
423 global $CFG, $USER;
425 // Check if messaging is enabled.
426 if (empty($CFG->messaging)) {
427 throw new moodle_exception('disabled', 'message');
430 // Validate context.
431 $context = context_system::instance();
432 self::validate_context($context);
434 $params = ['userid' => $userid, 'conversationids' => $conversationids];
435 $params = self::validate_parameters(self::unmute_conversations_parameters(), $params);
437 $capability = 'moodle/site:manageallmessaging';
438 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
439 throw new required_capability_exception($context, $capability, 'nopermissions', '');
442 foreach ($params['conversationids'] as $conversationid) {
443 \core_message\api::unmute_conversation($params['userid'], $conversationid);
446 return [];
450 * Unmute conversations return description.
452 * @return external_description
454 public static function unmute_conversations_returns() {
455 return new external_warnings();
459 * Block user parameters description.
461 * @return external_function_parameters
463 public static function block_user_parameters() {
464 return new external_function_parameters(
466 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
467 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
473 * Blocks a user.
475 * @param int $userid The id of the user who is blocking
476 * @param int $blockeduserid The id of the user being blocked
477 * @return external_description
479 public static function block_user(int $userid, int $blockeduserid) {
480 global $CFG, $USER;
482 // Check if messaging is enabled.
483 if (empty($CFG->messaging)) {
484 throw new moodle_exception('disabled', 'message');
487 // Validate context.
488 $context = context_system::instance();
489 self::validate_context($context);
491 $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
492 $params = self::validate_parameters(self::block_user_parameters(), $params);
494 $capability = 'moodle/site:manageallmessaging';
495 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
496 throw new required_capability_exception($context, $capability, 'nopermissions', '');
499 // If the blocking is going to be useless then don't do it.
500 if (\core_message\api::can_send_message($userid, $blockeduserid, true)) {
501 return [];
504 if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
505 \core_message\api::block_user($params['userid'], $params['blockeduserid']);
508 return [];
512 * Block user return description.
514 * @return external_description
516 public static function block_user_returns() {
517 return new external_warnings();
521 * Unblock user parameters description.
523 * @return external_function_parameters
525 public static function unblock_user_parameters() {
526 return new external_function_parameters(
528 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
529 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
535 * Unblock user.
537 * @param int $userid The id of the user who is unblocking
538 * @param int $unblockeduserid The id of the user being unblocked
540 public static function unblock_user(int $userid, int $unblockeduserid) {
541 global $CFG, $USER;
543 // Check if messaging is enabled.
544 if (empty($CFG->messaging)) {
545 throw new moodle_exception('disabled', 'message');
548 // Validate context.
549 $context = context_system::instance();
550 self::validate_context($context);
552 $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
553 $params = self::validate_parameters(self::unblock_user_parameters(), $params);
555 $capability = 'moodle/site:manageallmessaging';
556 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
557 throw new required_capability_exception($context, $capability, 'nopermissions', '');
560 \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
562 return [];
566 * Unblock user return description.
568 * @return external_description
570 public static function unblock_user_returns() {
571 return new external_warnings();
575 * Returns contact requests parameters description.
577 * @return external_function_parameters
579 public static function get_contact_requests_parameters() {
580 return new external_function_parameters(
582 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
583 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
584 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
590 * Handles returning the contact requests for a user.
592 * This also includes the user data necessary to display information
593 * about the user.
595 * It will not include blocked users.
597 * @param int $userid The id of the user we want to get the contact requests for
598 * @param int $limitfrom
599 * @param int $limitnum
601 public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
602 global $CFG, $USER;
604 // Check if messaging is enabled.
605 if (empty($CFG->messaging)) {
606 throw new moodle_exception('disabled', 'message');
609 // Validate context.
610 $context = context_system::instance();
611 self::validate_context($context);
613 $params = [
614 'userid' => $userid,
615 'limitfrom' => $limitfrom,
616 'limitnum' => $limitnum
618 $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
620 $capability = 'moodle/site:manageallmessaging';
621 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
622 throw new required_capability_exception($context, $capability, 'nopermissions', '');
625 return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
629 * Returns the contact requests return description.
631 * @return external_description
633 public static function get_contact_requests_returns() {
634 return new external_multiple_structure(
635 self::get_conversation_member_structure()
640 * Returns the number of contact requests the user has received parameters description.
642 * @return external_function_parameters
644 public static function get_received_contact_requests_count_parameters() {
645 return new external_function_parameters(
646 array(
647 'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' .
648 'received contact requests for', VALUE_REQUIRED),
654 * Returns the number of contact requests the user has received.
656 * @param int $userid The ID of the user we want to return the number of received contact requests for
657 * @return external_value
659 public static function get_received_contact_requests_count(int $userid) {
660 global $CFG, $USER;
662 // Check if messaging is enabled.
663 if (empty($CFG->messaging)) {
664 throw new moodle_exception('disabled', 'message');
667 // Validate context.
668 $context = context_system::instance();
669 self::validate_context($context);
671 $params = [
672 'userid' => $userid,
674 $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params);
676 $capability = 'moodle/site:manageallmessaging';
677 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
678 throw new required_capability_exception($context, $capability, 'nopermissions', '');
681 return \core_message\api::get_received_contact_requests_count($params['userid']);
685 * Returns the number of contact requests the user has received return description.
687 * @return external_value
689 public static function get_received_contact_requests_count_returns() {
690 return new external_value(PARAM_INT, 'The number of received contact requests');
694 * Returns get conversation members parameters description.
696 * @return external_function_parameters
698 public static function get_conversation_members_parameters() {
699 return new external_function_parameters(
701 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
702 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
703 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
704 VALUE_DEFAULT, false),
705 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?',
706 VALUE_DEFAULT, false),
707 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
708 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
714 * Returns a list of conversation members.
716 * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
717 * @param int $conversationid The id of the conversation
718 * @param bool $includecontactrequests Do we want to include contact requests with this data?
719 * @param bool $includeprivacyinfo Do we want to include privacy info?
720 * @param int $limitfrom
721 * @param int $limitnum
722 * @return array
724 public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
725 bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) {
726 global $CFG, $USER;
728 // Check if messaging is enabled.
729 if (empty($CFG->messaging)) {
730 throw new moodle_exception('disabled', 'message');
733 // Validate context.
734 $context = context_system::instance();
735 self::validate_context($context);
737 $params = [
738 'userid' => $userid,
739 'conversationid' => $conversationid,
740 'includecontactrequests' => $includecontactrequests,
741 'includeprivacyinfo' => $includeprivacyinfo,
742 'limitfrom' => $limitfrom,
743 'limitnum' => $limitnum
745 $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
747 $capability = 'moodle/site:manageallmessaging';
748 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
749 throw new required_capability_exception($context, $capability, 'nopermissions', '');
752 // The user needs to be a part of the conversation before querying who the members are.
753 if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
754 throw new moodle_exception('You are not a member of this conversation.');
757 return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
758 $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']);
762 * Returns the get conversation members return description.
764 * @return external_description
766 public static function get_conversation_members_returns() {
767 return new external_multiple_structure(
768 self::get_conversation_member_structure()
773 * Creates a contact request parameters description.
775 * @return external_function_parameters
777 public static function create_contact_request_parameters() {
778 return new external_function_parameters(
780 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
781 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
787 * Creates a contact request.
789 * @param int $userid The id of the user who is creating the contact request
790 * @param int $requesteduserid The id of the user being requested
792 public static function create_contact_request(int $userid, int $requesteduserid) {
793 global $CFG, $USER;
795 // Check if messaging is enabled.
796 if (empty($CFG->messaging)) {
797 throw new moodle_exception('disabled', 'message');
800 // Validate context.
801 $context = context_system::instance();
802 self::validate_context($context);
804 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
805 $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
807 $capability = 'moodle/site:manageallmessaging';
808 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
809 throw new required_capability_exception($context, $capability, 'nopermissions', '');
812 $result = [
813 'warnings' => []
816 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
817 $result['warnings'][] = [
818 'item' => 'user',
819 'itemid' => $params['requesteduserid'],
820 'warningcode' => 'cannotcreatecontactrequest',
821 'message' => 'You are unable to create a contact request for this user'
823 } else {
824 if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
825 // There should only ever be one but just in case there are multiple then we can return the first.
826 $result['request'] = array_shift($requests);
827 } else {
828 $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
832 return $result;
836 * Creates a contact request return description.
838 * @return external_description
840 public static function create_contact_request_returns() {
841 return new external_single_structure(
842 array(
843 'request' => new external_single_structure(
844 array(
845 'id' => new external_value(PARAM_INT, 'Message id'),
846 'userid' => new external_value(PARAM_INT, 'User from id'),
847 'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
848 'timecreated' => new external_value(PARAM_INT, 'Time created'),
850 'request record',
851 VALUE_OPTIONAL
853 'warnings' => new external_warnings()
859 * Confirm a contact request parameters description.
861 * @return external_function_parameters
863 public static function confirm_contact_request_parameters() {
864 return new external_function_parameters(
866 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
867 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
873 * Confirm a contact request.
875 * @param int $userid The id of the user who is creating the contact request
876 * @param int $requesteduserid The id of the user being requested
878 public static function confirm_contact_request(int $userid, int $requesteduserid) {
879 global $CFG, $USER;
881 // Check if messaging is enabled.
882 if (empty($CFG->messaging)) {
883 throw new moodle_exception('disabled', 'message');
886 // Validate context.
887 $context = context_system::instance();
888 self::validate_context($context);
890 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
891 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
893 $capability = 'moodle/site:manageallmessaging';
894 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
895 throw new required_capability_exception($context, $capability, 'nopermissions', '');
898 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
900 return [];
904 * Confirm a contact request return description.
906 * @return external_description
908 public static function confirm_contact_request_returns() {
909 return new external_warnings();
913 * Declines a contact request parameters description.
915 * @return external_function_parameters
917 public static function decline_contact_request_parameters() {
918 return new external_function_parameters(
920 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
921 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
927 * Declines a contact request.
929 * @param int $userid The id of the user who is creating the contact request
930 * @param int $requesteduserid The id of the user being requested
932 public static function decline_contact_request(int $userid, int $requesteduserid) {
933 global $CFG, $USER;
935 // Check if messaging is enabled.
936 if (empty($CFG->messaging)) {
937 throw new moodle_exception('disabled', 'message');
940 // Validate context.
941 $context = context_system::instance();
942 self::validate_context($context);
944 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
945 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
947 $capability = 'moodle/site:manageallmessaging';
948 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
949 throw new required_capability_exception($context, $capability, 'nopermissions', '');
952 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
954 return [];
958 * Declines a contact request return description.
960 * @return external_description
962 public static function decline_contact_request_returns() {
963 return new external_warnings();
967 * Return the structure of a message area contact.
969 * @return external_single_structure
970 * @since Moodle 3.2
972 private static function get_messagearea_contact_structure() {
973 return new external_single_structure(
974 array(
975 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
976 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
977 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
978 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
979 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
980 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
981 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
982 'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null),
983 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
984 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
985 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
986 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
987 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
988 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
989 VALUE_DEFAULT, null),
990 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null),
996 * Return the structure of a conversation.
998 * @return external_single_structure
999 * @since Moodle 3.6
1001 private static function get_conversation_structure() {
1002 return new external_single_structure(
1003 array(
1004 'id' => new external_value(PARAM_INT, 'The conversation id'),
1005 'name' => new external_value(PARAM_RAW, 'The conversation name, if set', VALUE_DEFAULT, null),
1006 'subname' => new external_value(PARAM_RAW, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1007 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1008 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group,3=self)'),
1009 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1010 'ismuted' => new external_value(PARAM_BOOL, 'If the user muted this conversation'),
1011 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this conversation as a favourite'),
1012 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1013 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1014 VALUE_DEFAULT, null),
1015 'members' => new external_multiple_structure(
1016 self::get_conversation_member_structure()
1018 'messages' => new external_multiple_structure(
1019 self::get_conversation_message_structure()
1021 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
1022 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
1028 * Return the structure of a conversation member.
1030 * @return external_single_structure
1031 * @since Moodle 3.6
1033 private static function get_conversation_member_structure() {
1034 $result = [
1035 'id' => new external_value(PARAM_INT, 'The user id'),
1036 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1037 'profileurl' => new external_value(PARAM_URL, 'The link to the user\'s profile page'),
1038 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1039 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1040 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1041 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1042 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1043 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1044 'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1045 'canmessageevenifblocked' => new external_value(PARAM_BOOL,
1046 'If the user can still message even if they get blocked'),
1047 'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1048 'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1051 $result['contactrequests'] = new external_multiple_structure(
1052 new external_single_structure(
1054 'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1055 'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1056 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1057 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1059 ), 'The contact requests', VALUE_OPTIONAL
1062 $result['conversations'] = new external_multiple_structure(new external_single_structure(
1063 array(
1064 'id' => new external_value(PARAM_INT, 'Conversations id'),
1065 'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1066 'name' => new external_value(PARAM_RAW, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1067 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1068 ), 'information about conversation', VALUE_OPTIONAL),
1069 'Conversations between users', VALUE_OPTIONAL
1072 return new external_single_structure(
1073 $result
1078 * Return the structure of a message area message.
1080 * @return external_single_structure
1081 * @since Moodle 3.6
1083 private static function get_conversation_message_structure() {
1084 return new external_single_structure(
1085 array(
1086 'id' => new external_value(PARAM_INT, 'The id of the message'),
1087 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1088 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1089 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1095 * Get messagearea message search users parameters.
1097 * @return external_function_parameters
1098 * @since 3.6
1100 public static function message_search_users_parameters() {
1101 return new external_function_parameters(
1102 array(
1103 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1104 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1105 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1106 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1112 * Get search users results.
1114 * @param int $userid The id of the user who is performing the search
1115 * @param string $search The string being searched
1116 * @param int $limitfrom
1117 * @param int $limitnum
1118 * @return array
1119 * @throws moodle_exception
1120 * @since 3.6
1122 public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1123 global $USER;
1125 $systemcontext = context_system::instance();
1127 $params = array(
1128 'userid' => $userid,
1129 'search' => $search,
1130 'limitfrom' => $limitfrom,
1131 'limitnum' => $limitnum
1133 $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1134 self::validate_context($systemcontext);
1136 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1137 throw new moodle_exception('You do not have permission to perform this action.');
1140 list($contacts, $noncontacts) = \core_message\api::message_search_users(
1141 $params['userid'],
1142 $params['search'],
1143 $params['limitfrom'],
1144 $params['limitnum']);
1146 return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1150 * Get messagearea message search users returns.
1152 * @return external_single_structure
1153 * @since 3.2
1155 public static function message_search_users_returns() {
1156 return new external_single_structure(
1157 array(
1158 'contacts' => new external_multiple_structure(
1159 self::get_conversation_member_structure()
1161 'noncontacts' => new external_multiple_structure(
1162 self::get_conversation_member_structure()
1169 * Get messagearea search messages parameters.
1171 * @return external_function_parameters
1172 * @since 3.2
1174 public static function data_for_messagearea_search_messages_parameters() {
1175 return new external_function_parameters(
1176 array(
1177 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1178 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1179 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1180 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1186 * Get messagearea search messages results.
1188 * @param int $userid The id of the user who is performing the search
1189 * @param string $search The string being searched
1190 * @param int $limitfrom
1191 * @param int $limitnum
1192 * @return stdClass
1193 * @throws moodle_exception
1194 * @since 3.2
1196 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1197 global $CFG, $USER;
1199 // Check if messaging is enabled.
1200 if (empty($CFG->messaging)) {
1201 throw new moodle_exception('disabled', 'message');
1204 $systemcontext = context_system::instance();
1206 $params = array(
1207 'userid' => $userid,
1208 'search' => $search,
1209 'limitfrom' => $limitfrom,
1210 'limitnum' => $limitnum
1213 $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1214 self::validate_context($systemcontext);
1216 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1217 throw new moodle_exception('You do not have permission to perform this action.');
1220 $messages = \core_message\api::search_messages(
1221 $params['userid'],
1222 $params['search'],
1223 $params['limitfrom'],
1224 $params['limitnum']
1227 $data = new \stdClass();
1228 $data->contacts = [];
1229 foreach ($messages as $message) {
1230 $contact = new \stdClass();
1231 $contact->userid = $message->userid;
1232 $contact->fullname = $message->fullname;
1233 $contact->profileimageurl = $message->profileimageurl;
1234 $contact->profileimageurlsmall = $message->profileimageurlsmall;
1235 $contact->messageid = $message->messageid;
1236 $contact->ismessaging = $message->ismessaging;
1237 $contact->sentfromcurrentuser = false;
1238 if ($message->lastmessage) {
1239 if ($message->userid !== $message->useridfrom) {
1240 $contact->sentfromcurrentuser = true;
1242 $contact->lastmessage = shorten_text($message->lastmessage, 60);
1243 } else {
1244 $contact->lastmessage = null;
1246 $contact->lastmessagedate = $message->lastmessagedate;
1247 $contact->showonlinestatus = is_null($message->isonline) ? false : true;
1248 $contact->isonline = $message->isonline;
1249 $contact->isblocked = $message->isblocked;
1250 $contact->isread = $message->isread;
1251 $contact->unreadcount = $message->unreadcount;
1252 $contact->conversationid = $message->conversationid;
1254 $data->contacts[] = $contact;
1257 return $data;
1261 * Get messagearea search messages returns.
1263 * @return external_single_structure
1264 * @since 3.2
1266 public static function data_for_messagearea_search_messages_returns() {
1267 return new external_single_structure(
1268 array(
1269 'contacts' => new external_multiple_structure(
1270 self::get_messagearea_contact_structure()
1277 * Get conversations parameters.
1279 * @return external_function_parameters
1280 * @since 3.6
1282 public static function get_conversations_parameters() {
1283 return new external_function_parameters(
1284 array(
1285 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1286 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1287 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1288 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1289 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1290 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1291 VALUE_DEFAULT, null),
1292 'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private
1293 conversations (false) when private conversations are requested.',
1294 VALUE_DEFAULT, false),
1300 * Get the list of conversations for the user.
1302 * @param int $userid The id of the user who is performing the search
1303 * @param int $limitfrom
1304 * @param int $limitnum
1305 * @param int|null $type
1306 * @param bool|null $favourites
1307 * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false)
1308 * when private conversations are requested.
1309 * @return stdClass
1310 * @throws \moodle_exception if the messaging feature is disabled on the site.
1311 * @since 3.2
1313 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null,
1314 bool $mergeself = false) {
1315 global $CFG, $USER;
1317 // All the standard BL checks.
1318 if (empty($CFG->messaging)) {
1319 throw new moodle_exception('disabled', 'message');
1322 $params = array(
1323 'userid' => $userid,
1324 'limitfrom' => $limitfrom,
1325 'limitnum' => $limitnum,
1326 'type' => $type,
1327 'favourites' => $favourites,
1328 'mergeself' => $mergeself
1330 $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1332 $systemcontext = context_system::instance();
1333 self::validate_context($systemcontext);
1335 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1336 throw new moodle_exception('You do not have permission to perform this action.');
1339 $conversations = \core_message\api::get_conversations(
1340 $params['userid'],
1341 $params['limitfrom'],
1342 $params['limitnum'],
1343 $params['type'],
1344 $params['favourites'],
1345 $params['mergeself']
1348 return (object) ['conversations' => $conversations];
1352 * Get conversations returns.
1354 * @return external_single_structure
1355 * @since 3.6
1357 public static function get_conversations_returns() {
1358 return new external_single_structure(
1360 'conversations' => new external_multiple_structure(
1361 self::get_conversation_structure(true)
1368 * Get conversation parameters.
1370 * @return external_function_parameters
1372 public static function get_conversation_parameters() {
1373 return new external_function_parameters(
1374 array(
1375 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1376 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1377 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1378 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1379 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1380 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1381 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1382 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1383 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1389 * Get a single conversation.
1391 * @param int $userid The user id to get the conversation for
1392 * @param int $conversationid The id of the conversation to fetch
1393 * @param bool $includecontactrequests Should contact requests be included between members
1394 * @param bool $includeprivacyinfo Should privacy info be included between members
1395 * @param int $memberlimit Limit number of members to load
1396 * @param int $memberoffset Offset members by this amount
1397 * @param int $messagelimit Limit number of messages to load
1398 * @param int $messageoffset Offset the messages
1399 * @param bool $newestmessagesfirst Order messages by newest first
1400 * @return stdClass
1401 * @throws \moodle_exception if the messaging feature is disabled on the site.
1403 public static function get_conversation(
1404 int $userid,
1405 int $conversationid,
1406 bool $includecontactrequests = false,
1407 bool $includeprivacyinfo = false,
1408 int $memberlimit = 0,
1409 int $memberoffset = 0,
1410 int $messagelimit = 0,
1411 int $messageoffset = 0,
1412 bool $newestmessagesfirst = true
1414 global $CFG, $DB, $USER;
1416 // All the standard BL checks.
1417 if (empty($CFG->messaging)) {
1418 throw new moodle_exception('disabled', 'message');
1421 $params = [
1422 'userid' => $userid,
1423 'conversationid' => $conversationid,
1424 'includecontactrequests' => $includecontactrequests,
1425 'includeprivacyinfo' => $includeprivacyinfo,
1426 'memberlimit' => $memberlimit,
1427 'memberoffset' => $memberoffset,
1428 'messagelimit' => $messagelimit,
1429 'messageoffset' => $messageoffset,
1430 'newestmessagesfirst' => $newestmessagesfirst
1432 self::validate_parameters(self::get_conversation_parameters(), $params);
1434 $systemcontext = context_system::instance();
1435 self::validate_context($systemcontext);
1437 $conversation = \core_message\api::get_conversation(
1438 $params['userid'],
1439 $params['conversationid'],
1440 $params['includecontactrequests'],
1441 $params['includeprivacyinfo'],
1442 $params['memberlimit'],
1443 $params['memberoffset'],
1444 $params['messagelimit'],
1445 $params['messageoffset'],
1446 $params['newestmessagesfirst']
1449 if ($conversation) {
1450 return $conversation;
1451 } else {
1452 // We have to throw an exception here because the external functions annoyingly
1453 // don't accept null to be returned for a single structure.
1454 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1459 * Get conversation returns.
1461 * @return external_single_structure
1463 public static function get_conversation_returns() {
1464 return self::get_conversation_structure();
1468 * Get conversation parameters.
1470 * @return external_function_parameters
1472 public static function get_conversation_between_users_parameters() {
1473 return new external_function_parameters(
1474 array(
1475 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1476 'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1477 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1478 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1479 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1480 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1481 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1482 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1483 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1489 * Get a single conversation between users.
1491 * @param int $userid The user id to get the conversation for
1492 * @param int $otheruserid The other user id
1493 * @param bool $includecontactrequests Should contact requests be included between members
1494 * @param bool $includeprivacyinfo Should privacy info be included between members
1495 * @param int $memberlimit Limit number of members to load
1496 * @param int $memberoffset Offset members by this amount
1497 * @param int $messagelimit Limit number of messages to load
1498 * @param int $messageoffset Offset the messages
1499 * @param bool $newestmessagesfirst Order messages by newest first
1500 * @return stdClass
1501 * @throws \moodle_exception if the messaging feature is disabled on the site.
1503 public static function get_conversation_between_users(
1504 int $userid,
1505 int $otheruserid,
1506 bool $includecontactrequests = false,
1507 bool $includeprivacyinfo = false,
1508 int $memberlimit = 0,
1509 int $memberoffset = 0,
1510 int $messagelimit = 0,
1511 int $messageoffset = 0,
1512 bool $newestmessagesfirst = true
1514 global $CFG, $DB, $USER;
1516 // All the standard BL checks.
1517 if (empty($CFG->messaging)) {
1518 throw new moodle_exception('disabled', 'message');
1521 $params = [
1522 'userid' => $userid,
1523 'otheruserid' => $otheruserid,
1524 'includecontactrequests' => $includecontactrequests,
1525 'includeprivacyinfo' => $includeprivacyinfo,
1526 'memberlimit' => $memberlimit,
1527 'memberoffset' => $memberoffset,
1528 'messagelimit' => $messagelimit,
1529 'messageoffset' => $messageoffset,
1530 'newestmessagesfirst' => $newestmessagesfirst
1532 self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
1534 $systemcontext = context_system::instance();
1535 self::validate_context($systemcontext);
1537 $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
1538 $conversation = null;
1540 if ($conversationid) {
1541 $conversation = \core_message\api::get_conversation(
1542 $params['userid'],
1543 $conversationid,
1544 $params['includecontactrequests'],
1545 $params['includeprivacyinfo'],
1546 $params['memberlimit'],
1547 $params['memberoffset'],
1548 $params['messagelimit'],
1549 $params['messageoffset'],
1550 $params['newestmessagesfirst']
1554 if ($conversation) {
1555 return $conversation;
1556 } else {
1557 // We have to throw an exception here because the external functions annoyingly
1558 // don't accept null to be returned for a single structure.
1559 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1564 * Get conversation returns.
1566 * @return external_single_structure
1568 public static function get_conversation_between_users_returns() {
1569 return self::get_conversation_structure(true);
1573 * Get self-conversation parameters.
1575 * @return external_function_parameters
1577 public static function get_self_conversation_parameters() {
1578 return new external_function_parameters(
1579 array(
1580 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'),
1581 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1582 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1583 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1589 * Get a single self-conversation.
1591 * @param int $userid The user id to get the self-conversation for
1592 * @param int $messagelimit Limit number of messages to load
1593 * @param int $messageoffset Offset the messages
1594 * @param bool $newestmessagesfirst Order messages by newest first
1595 * @return stdClass
1596 * @throws \moodle_exception if the messaging feature is disabled on the site.
1597 * @since Moodle 3.7
1599 public static function get_self_conversation(
1600 int $userid,
1601 int $messagelimit = 0,
1602 int $messageoffset = 0,
1603 bool $newestmessagesfirst = true
1605 global $CFG;
1607 // All the standard BL checks.
1608 if (empty($CFG->messaging)) {
1609 throw new moodle_exception('disabled', 'message');
1612 $params = [
1613 'userid' => $userid,
1614 'messagelimit' => $messagelimit,
1615 'messageoffset' => $messageoffset,
1616 'newestmessagesfirst' => $newestmessagesfirst
1618 self::validate_parameters(self::get_self_conversation_parameters(), $params);
1620 $systemcontext = context_system::instance();
1621 self::validate_context($systemcontext);
1623 $conversation = \core_message\api::get_self_conversation($params['userid']);
1625 if ($conversation) {
1626 $conversation = \core_message\api::get_conversation(
1627 $params['userid'],
1628 $conversation->id,
1629 false,
1630 false,
1633 $params['messagelimit'],
1634 $params['messageoffset'],
1635 $params['newestmessagesfirst']
1639 if ($conversation) {
1640 return $conversation;
1641 } else {
1642 // We have to throw an exception here because the external functions annoyingly
1643 // don't accept null to be returned for a single structure.
1644 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1649 * Get conversation returns.
1651 * @return external_single_structure
1653 public static function get_self_conversation_returns() {
1654 return self::get_conversation_structure();
1658 * The conversation messages parameters.
1660 * @return external_function_parameters
1661 * @since 3.6
1663 public static function get_conversation_messages_parameters() {
1664 return new external_function_parameters(
1665 array(
1666 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1667 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1668 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1669 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1670 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1671 'timefrom' => new external_value(PARAM_INT,
1672 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1678 * Get conversation messages.
1680 * @param int $currentuserid The current user's id.
1681 * @param int $convid The conversation id.
1682 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1683 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1684 * @param bool $newest True for getting first newest messages, false otherwise.
1685 * @param int $timefrom The time from the conversation messages to get.
1686 * @return array The messages and members who have sent some of these messages.
1687 * @throws moodle_exception
1688 * @since 3.6
1690 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1691 bool $newest = false, int $timefrom = 0) {
1692 global $CFG, $USER;
1694 // Check if messaging is enabled.
1695 if (empty($CFG->messaging)) {
1696 throw new moodle_exception('disabled', 'message');
1699 $systemcontext = context_system::instance();
1701 $params = array(
1702 'currentuserid' => $currentuserid,
1703 'convid' => $convid,
1704 'limitfrom' => $limitfrom,
1705 'limitnum' => $limitnum,
1706 'newest' => $newest,
1707 'timefrom' => $timefrom,
1709 $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1710 self::validate_context($systemcontext);
1712 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1713 throw new moodle_exception('You do not have permission to perform this action.');
1716 // Check that the user belongs to the conversation.
1717 if (!\core_message\api::is_user_in_conversation($params['currentuserid'], $params['convid'])) {
1718 throw new moodle_exception('User is not part of conversation.');
1721 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1723 // We need to enforce a one second delay on messages to avoid race conditions of current
1724 // messages still being sent.
1726 // There is a chance that we could request messages before the current time's
1727 // second has elapsed and while other messages are being sent in that same second. In which
1728 // case those messages will be lost.
1730 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1731 $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1733 // No requesting messages from the current time, as stated above.
1734 if ($params['timefrom'] == time()) {
1735 $messages = [];
1736 } else {
1737 $messages = \core_message\api::get_conversation_messages(
1738 $params['currentuserid'],
1739 $params['convid'],
1740 $params['limitfrom'],
1741 $params['limitnum'],
1742 $sort,
1743 $params['timefrom'],
1744 $timeto);
1747 return $messages;
1751 * The messagearea messages return structure.
1753 * @return external_single_structure
1754 * @since 3.6
1756 public static function get_conversation_messages_returns() {
1757 return new external_single_structure(
1758 array(
1759 'id' => new external_value(PARAM_INT, 'The conversation id'),
1760 'members' => new external_multiple_structure(
1761 self::get_conversation_member_structure()
1763 'messages' => new external_multiple_structure(
1764 self::get_conversation_message_structure()
1771 * The user contacts return parameters.
1773 * @return external_function_parameters
1775 public static function get_user_contacts_parameters() {
1776 return new external_function_parameters(
1777 array(
1778 'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
1779 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1780 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1786 * Get user contacts.
1788 * @param int $userid The id of the user who we are viewing conversations for
1789 * @param int $limitfrom
1790 * @param int $limitnum
1791 * @return array
1792 * @throws moodle_exception
1794 public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
1795 global $CFG, $USER;
1797 // Check if messaging is enabled.
1798 if (empty($CFG->messaging)) {
1799 throw new moodle_exception('disabled', 'message');
1802 $systemcontext = context_system::instance();
1804 $params = array(
1805 'userid' => $userid,
1806 'limitfrom' => $limitfrom,
1807 'limitnum' => $limitnum
1809 $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
1810 self::validate_context($systemcontext);
1812 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1813 throw new moodle_exception('You do not have permission to perform this action.');
1816 return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1820 * The user contacts return structure.
1822 * @return external_multiple_structure
1824 public static function get_user_contacts_returns() {
1825 return new external_multiple_structure(
1826 self::get_conversation_member_structure()
1831 * Search contacts parameters description.
1833 * @return external_function_parameters
1834 * @since Moodle 2.5
1836 public static function search_contacts_parameters() {
1837 return new external_function_parameters(
1838 array(
1839 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1840 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1841 VALUE_DEFAULT, false)
1847 * Search contacts.
1849 * @param string $searchtext query string.
1850 * @param bool $onlymycourses limit the search to the user's courses only.
1851 * @return external_description
1852 * @since Moodle 2.5
1854 public static function search_contacts($searchtext, $onlymycourses = false) {
1855 global $CFG, $USER, $PAGE;
1856 require_once($CFG->dirroot . '/user/lib.php');
1858 // Check if messaging is enabled.
1859 if (empty($CFG->messaging)) {
1860 throw new moodle_exception('disabled', 'message');
1863 require_once($CFG->libdir . '/enrollib.php');
1865 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1866 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1868 // Extra validation, we do not allow empty queries.
1869 if ($params['searchtext'] === '') {
1870 throw new moodle_exception('querystringcannotbeempty');
1873 $courseids = array();
1874 if ($params['onlymycourses']) {
1875 $mycourses = enrol_get_my_courses(array('id'));
1876 foreach ($mycourses as $mycourse) {
1877 $courseids[] = $mycourse->id;
1879 } else {
1880 $courseids[] = SITEID;
1883 // Retrieving the users matching the query.
1884 $users = message_search_users($courseids, $params['searchtext']);
1885 $results = array();
1886 foreach ($users as $user) {
1887 $results[$user->id] = $user;
1890 // Reorganising information.
1891 foreach ($results as &$user) {
1892 $newuser = array(
1893 'id' => $user->id,
1894 'fullname' => fullname($user)
1897 // Avoid undefined property notice as phone not specified.
1898 $user->phone1 = null;
1899 $user->phone2 = null;
1901 $userpicture = new user_picture($user);
1902 $userpicture->size = 1; // Size f1.
1903 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1904 $userpicture->size = 0; // Size f2.
1905 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1907 $user = $newuser;
1910 return $results;
1914 * Search contacts return description.
1916 * @return external_description
1917 * @since Moodle 2.5
1919 public static function search_contacts_returns() {
1920 return new external_multiple_structure(
1921 new external_single_structure(
1922 array(
1923 'id' => new external_value(PARAM_INT, 'User ID'),
1924 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1925 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1926 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1929 'List of contacts'
1934 * Get messages parameters description.
1936 * @return external_function_parameters
1937 * @since 2.8
1939 public static function get_messages_parameters() {
1940 return new external_function_parameters(
1941 array(
1942 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1943 'useridfrom' => new external_value(
1944 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1945 VALUE_DEFAULT, 0),
1946 'type' => new external_value(
1947 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1948 VALUE_DEFAULT, 'both'),
1949 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
1950 'newestfirst' => new external_value(
1951 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1952 VALUE_DEFAULT, true),
1953 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1954 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1960 * Get messages function implementation.
1962 * @since 2.8
1963 * @throws invalid_parameter_exception
1964 * @throws moodle_exception
1965 * @param int $useridto the user id who received the message
1966 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
1967 * @param string $type type of message to return, expected values: notifications, conversations and both
1968 * @param bool $read true for retreiving read messages, false for unread
1969 * @param bool $newestfirst true for ordering by newest first, false for oldest first
1970 * @param int $limitfrom limit from
1971 * @param int $limitnum limit num
1972 * @return external_description
1974 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
1975 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
1976 global $CFG, $USER;
1978 $warnings = array();
1980 $params = array(
1981 'useridto' => $useridto,
1982 'useridfrom' => $useridfrom,
1983 'type' => $type,
1984 'read' => $read,
1985 'newestfirst' => $newestfirst,
1986 'limitfrom' => $limitfrom,
1987 'limitnum' => $limitnum
1990 $params = self::validate_parameters(self::get_messages_parameters(), $params);
1992 $context = context_system::instance();
1993 self::validate_context($context);
1995 $useridto = $params['useridto'];
1996 $useridfrom = $params['useridfrom'];
1997 $type = $params['type'];
1998 $read = $params['read'];
1999 $newestfirst = $params['newestfirst'];
2000 $limitfrom = $params['limitfrom'];
2001 $limitnum = $params['limitnum'];
2003 $allowedvalues = array('notifications', 'conversations', 'both');
2004 if (!in_array($type, $allowedvalues)) {
2005 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2006 'allowed values are: ' . implode(',', $allowedvalues));
2009 // Check if private messaging between users is allowed.
2010 if (empty($CFG->messaging)) {
2011 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2012 if ($type == "conversations") {
2013 throw new moodle_exception('disabled', 'message');
2015 if ($type == "both") {
2016 $warning = array();
2017 $warning['item'] = 'message';
2018 $warning['itemid'] = $USER->id;
2019 $warning['warningcode'] = '1';
2020 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2021 Only notifications will be returned';
2022 $warnings[] = $warning;
2026 if (!empty($useridto)) {
2027 if (core_user::is_real_user($useridto)) {
2028 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2029 } else {
2030 throw new moodle_exception('invaliduser');
2034 if (!empty($useridfrom)) {
2035 // We use get_user here because the from user can be the noreply or support user.
2036 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2039 // Check if the current user is the sender/receiver or just a privileged user.
2040 if ($useridto != $USER->id and $useridfrom != $USER->id and
2041 !has_capability('moodle/site:readallmessages', $context)) {
2042 throw new moodle_exception('accessdenied', 'admin');
2045 // Which type of messages to retrieve.
2046 $notifications = -1;
2047 if ($type != 'both') {
2048 $notifications = ($type == 'notifications') ? 1 : 0;
2051 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2052 $sort = "mr.timecreated $orderdirection";
2054 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2055 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2057 // In some cases, we don't need to get the to/from user objects from the sql query.
2058 $userfromfullname = '';
2059 $usertofullname = '';
2061 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2062 if (!empty($useridto)) {
2063 $usertofullname = fullname($userto, $canviewfullname);
2064 // The user from may or may not be filled.
2065 if (!empty($useridfrom)) {
2066 $userfromfullname = fullname($userfrom, $canviewfullname);
2068 } else {
2069 // If the useridto field is empty, the useridfrom must be filled.
2070 $userfromfullname = fullname($userfrom, $canviewfullname);
2072 foreach ($messages as $mid => $message) {
2074 // Do not return deleted messages.
2075 if (!$message->notification) {
2076 if (($useridto == $USER->id and $message->timeusertodeleted) or
2077 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2078 unset($messages[$mid]);
2079 continue;
2083 // We need to get the user from the query.
2084 if (empty($userfromfullname)) {
2085 // Check for non-reply and support users.
2086 if (core_user::is_real_user($message->useridfrom)) {
2087 $user = new stdClass();
2088 $user = username_load_fields_from_object($user, $message, 'userfrom');
2089 $message->userfromfullname = fullname($user, $canviewfullname);
2090 } else {
2091 $user = core_user::get_user($message->useridfrom);
2092 $message->userfromfullname = fullname($user, $canviewfullname);
2094 } else {
2095 $message->userfromfullname = $userfromfullname;
2098 // We need to get the user from the query.
2099 if (empty($usertofullname)) {
2100 $user = new stdClass();
2101 $user = username_load_fields_from_object($user, $message, 'userto');
2102 $message->usertofullname = fullname($user, $canviewfullname);
2103 } else {
2104 $message->usertofullname = $usertofullname;
2107 $message->text = message_format_message_text($message);
2108 $messages[$mid] = (array) $message;
2112 $results = array(
2113 'messages' => $messages,
2114 'warnings' => $warnings
2117 return $results;
2121 * Get messages return description.
2123 * @return external_single_structure
2124 * @since 2.8
2126 public static function get_messages_returns() {
2127 return new external_single_structure(
2128 array(
2129 'messages' => new external_multiple_structure(
2130 new external_single_structure(
2131 array(
2132 'id' => new external_value(PARAM_INT, 'Message id'),
2133 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2134 'useridto' => new external_value(PARAM_INT, 'User to id'),
2135 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2136 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2137 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2138 'fullmessageformat' => new external_format_value('fullmessage'),
2139 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2140 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2141 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2142 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2143 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2144 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2145 'timeread' => new external_value(PARAM_INT, 'Time read'),
2146 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2147 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
2148 'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
2149 VALUE_OPTIONAL),
2150 'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
2151 'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
2152 The data here is serialised using json_encode().', VALUE_OPTIONAL),
2153 ), 'message'
2156 'warnings' => new external_warnings()
2162 * Mark all notifications as read parameters description.
2164 * @return external_function_parameters
2165 * @since 3.2
2167 public static function mark_all_notifications_as_read_parameters() {
2168 return new external_function_parameters(
2169 array(
2170 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2171 'useridfrom' => new external_value(
2172 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2173 VALUE_DEFAULT, 0),
2174 'timecreatedto' => new external_value(
2175 PARAM_INT, 'mark messages created before this time as read, 0 for all messages',
2176 VALUE_DEFAULT, 0),
2182 * Mark all notifications as read function.
2184 * @since 3.2
2185 * @throws invalid_parameter_exception
2186 * @throws moodle_exception
2187 * @param int $useridto the user id who received the message
2188 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2189 * @param int $timecreatedto mark message created before this time as read, 0 for all messages
2190 * @return external_description
2192 public static function mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto = 0) {
2193 global $USER;
2195 $params = self::validate_parameters(
2196 self::mark_all_notifications_as_read_parameters(),
2197 array(
2198 'useridto' => $useridto,
2199 'useridfrom' => $useridfrom,
2200 'timecreatedto' => $timecreatedto,
2204 $context = context_system::instance();
2205 self::validate_context($context);
2207 $useridto = $params['useridto'];
2208 $useridfrom = $params['useridfrom'];
2209 $timecreatedto = $params['timecreatedto'];
2211 if (!empty($useridto)) {
2212 if (core_user::is_real_user($useridto)) {
2213 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2214 } else {
2215 throw new moodle_exception('invaliduser');
2219 if (!empty($useridfrom)) {
2220 // We use get_user here because the from user can be the noreply or support user.
2221 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2224 // Check if the current user is the sender/receiver or just a privileged user.
2225 if ($useridto != $USER->id and $useridfrom != $USER->id and
2226 // The deleteanymessage cap seems more reasonable here than readallmessages.
2227 !has_capability('moodle/site:deleteanymessage', $context)) {
2228 throw new moodle_exception('accessdenied', 'admin');
2231 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto);
2233 return true;
2237 * Mark all notifications as read return description.
2239 * @return external_single_structure
2240 * @since 3.2
2242 public static function mark_all_notifications_as_read_returns() {
2243 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2247 * Get unread conversations count parameters description.
2249 * @return external_function_parameters
2250 * @since 3.2
2252 public static function get_unread_conversations_count_parameters() {
2253 return new external_function_parameters(
2254 array(
2255 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2261 * Get unread messages count function.
2263 * @since 3.2
2264 * @throws invalid_parameter_exception
2265 * @throws moodle_exception
2266 * @param int $useridto the user id who received the message
2267 * @return external_description
2269 public static function get_unread_conversations_count($useridto) {
2270 global $USER, $CFG;
2272 // Check if messaging is enabled.
2273 if (empty($CFG->messaging)) {
2274 throw new moodle_exception('disabled', 'message');
2277 $params = self::validate_parameters(
2278 self::get_unread_conversations_count_parameters(),
2279 array('useridto' => $useridto)
2282 $context = context_system::instance();
2283 self::validate_context($context);
2285 $useridto = $params['useridto'];
2287 if (!empty($useridto)) {
2288 if (core_user::is_real_user($useridto)) {
2289 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2290 } else {
2291 throw new moodle_exception('invaliduser');
2293 } else {
2294 $useridto = $USER->id;
2297 // Check if the current user is the receiver or just a privileged user.
2298 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2299 throw new moodle_exception('accessdenied', 'admin');
2302 return \core_message\api::count_unread_conversations($userto);
2306 * Get unread conversations count return description.
2308 * @return external_single_structure
2309 * @since 3.2
2311 public static function get_unread_conversations_count_returns() {
2312 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2316 * Get blocked users parameters description.
2318 * @return external_function_parameters
2319 * @since 2.9
2321 public static function get_blocked_users_parameters() {
2322 return new external_function_parameters(
2323 array(
2324 'userid' => new external_value(PARAM_INT,
2325 'the user whose blocked users we want to retrieve',
2326 VALUE_REQUIRED),
2332 * Retrieve a list of users blocked
2334 * @param int $userid the user whose blocked users we want to retrieve
2335 * @return external_description
2336 * @since 2.9
2338 public static function get_blocked_users($userid) {
2339 global $CFG, $USER, $PAGE;
2341 // Warnings array, it can be empty at the end but is mandatory.
2342 $warnings = array();
2344 // Validate params.
2345 $params = array(
2346 'userid' => $userid
2348 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2349 $userid = $params['userid'];
2351 // Validate context.
2352 $context = context_system::instance();
2353 self::validate_context($context);
2355 // Check if private messaging between users is allowed.
2356 if (empty($CFG->messaging)) {
2357 throw new moodle_exception('disabled', 'message');
2360 $user = core_user::get_user($userid, '*', MUST_EXIST);
2361 core_user::require_active_user($user);
2363 // Check if we have permissions for retrieve the information.
2364 $capability = 'moodle/site:manageallmessaging';
2365 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2366 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2369 // Now, we can get safely all the blocked users.
2370 $users = \core_message\api::get_blocked_users($user->id);
2372 $blockedusers = array();
2373 foreach ($users as $user) {
2374 $newuser = array(
2375 'id' => $user->id,
2376 'fullname' => fullname($user),
2379 $userpicture = new user_picture($user);
2380 $userpicture->size = 1; // Size f1.
2381 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2383 $blockedusers[] = $newuser;
2386 $results = array(
2387 'users' => $blockedusers,
2388 'warnings' => $warnings
2390 return $results;
2394 * Get blocked users return description.
2396 * @return external_single_structure
2397 * @since 2.9
2399 public static function get_blocked_users_returns() {
2400 return new external_single_structure(
2401 array(
2402 'users' => new external_multiple_structure(
2403 new external_single_structure(
2404 array(
2405 'id' => new external_value(PARAM_INT, 'User ID'),
2406 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2407 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2410 'List of blocked users'
2412 'warnings' => new external_warnings()
2418 * Returns description of method parameters
2420 * @return external_function_parameters
2421 * @since 2.9
2423 public static function mark_message_read_parameters() {
2424 return new external_function_parameters(
2425 array(
2426 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2427 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2428 VALUE_DEFAULT, 0)
2434 * Mark a single message as read, trigger message_viewed event
2436 * @param int $messageid id of the message (in the message table)
2437 * @param int $timeread timestamp for when the message should be marked read
2438 * @return external_description
2439 * @throws invalid_parameter_exception
2440 * @throws moodle_exception
2441 * @since 2.9
2443 public static function mark_message_read($messageid, $timeread) {
2444 global $CFG, $DB, $USER;
2446 // Check if private messaging between users is allowed.
2447 if (empty($CFG->messaging)) {
2448 throw new moodle_exception('disabled', 'message');
2451 // Warnings array, it can be empty at the end but is mandatory.
2452 $warnings = array();
2454 // Validate params.
2455 $params = array(
2456 'messageid' => $messageid,
2457 'timeread' => $timeread
2459 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2461 if (empty($params['timeread'])) {
2462 $timeread = time();
2463 } else {
2464 $timeread = $params['timeread'];
2467 // Validate context.
2468 $context = context_system::instance();
2469 self::validate_context($context);
2471 $sql = "SELECT m.*, mcm.userid as useridto
2472 FROM {messages} m
2473 INNER JOIN {message_conversations} mc
2474 ON m.conversationid = mc.id
2475 INNER JOIN {message_conversation_members} mcm
2476 ON mcm.conversationid = mc.id
2477 LEFT JOIN {message_user_actions} mua
2478 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2479 WHERE mua.id is NULL
2480 AND mcm.userid != m.useridfrom
2481 AND m.id = ?";
2482 $messageparams = [];
2483 $messageparams[] = $USER->id;
2484 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2485 $messageparams[] = $params['messageid'];
2486 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2488 if ($message->useridto != $USER->id) {
2489 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2492 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2494 $results = array(
2495 'messageid' => $message->id,
2496 'warnings' => $warnings
2498 return $results;
2502 * Returns description of method result value
2504 * @return external_description
2505 * @since 2.9
2507 public static function mark_message_read_returns() {
2508 return new external_single_structure(
2509 array(
2510 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2511 'warnings' => new external_warnings()
2517 * Returns description of method parameters
2519 * @return external_function_parameters
2521 public static function mark_notification_read_parameters() {
2522 return new external_function_parameters(
2523 array(
2524 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2525 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2526 VALUE_DEFAULT, 0)
2532 * Mark a single notification as read.
2534 * This will trigger a 'notification_viewed' event.
2536 * @param int $notificationid id of the notification
2537 * @param int $timeread timestamp for when the notification should be marked read
2538 * @return external_description
2539 * @throws invalid_parameter_exception
2540 * @throws moodle_exception
2542 public static function mark_notification_read($notificationid, $timeread) {
2543 global $CFG, $DB, $USER;
2545 // Warnings array, it can be empty at the end but is mandatory.
2546 $warnings = array();
2548 // Validate params.
2549 $params = array(
2550 'notificationid' => $notificationid,
2551 'timeread' => $timeread
2553 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2555 if (empty($params['timeread'])) {
2556 $timeread = time();
2557 } else {
2558 $timeread = $params['timeread'];
2561 // Validate context.
2562 $context = context_system::instance();
2563 self::validate_context($context);
2565 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2567 if ($notification->useridto != $USER->id) {
2568 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2569 'notification as read');
2572 \core_message\api::mark_notification_as_read($notification, $timeread);
2574 $results = array(
2575 'notificationid' => $notification->id,
2576 'warnings' => $warnings
2579 return $results;
2583 * Returns description of method result value
2585 * @return external_description
2587 public static function mark_notification_read_returns() {
2588 return new external_single_structure(
2589 array(
2590 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2591 'warnings' => new external_warnings()
2597 * Mark all conversation messages as read parameters description.
2599 * @return external_function_parameters
2600 * @since 3.6
2602 public static function mark_all_conversation_messages_as_read_parameters() {
2603 return new external_function_parameters(
2604 array(
2605 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2606 'conversationid' =>
2607 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2613 * Mark all conversation messages as read function.
2615 * @param int $userid The user id of who we want to delete the conversation for
2616 * @param int $conversationid The id of the conversations
2617 * @since 3.6
2619 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2620 global $CFG;
2622 // Check if messaging is enabled.
2623 if (empty($CFG->messaging)) {
2624 throw new moodle_exception('disabled', 'message');
2627 $params = array(
2628 'userid' => $userid,
2629 'conversationid' => $conversationid,
2631 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2633 $context = context_system::instance();
2634 self::validate_context($context);
2636 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2637 core_user::require_active_user($user);
2639 if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
2640 \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
2641 } else {
2642 throw new moodle_exception('accessdenied', 'admin');
2647 * Mark all conversation messages as read return description.
2649 * @return external_warnings
2650 * @since 3.6
2652 public static function mark_all_conversation_messages_as_read_returns() {
2653 return null;
2657 * Returns description of method parameters.
2659 * @return external_function_parameters
2660 * @since 3.6
2662 public static function delete_conversations_by_id_parameters() {
2663 return new external_function_parameters(
2664 array(
2665 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2666 'conversationids' => new external_multiple_structure(
2667 new external_value(PARAM_INT, 'The id of the conversation'),
2668 'List of conversation IDs'
2675 * Deletes a conversation.
2677 * @param int $userid The user id of who we want to delete the conversation for
2678 * @param int[] $conversationids The ids of the conversations
2679 * @return array
2680 * @throws moodle_exception
2681 * @since 3.6
2683 public static function delete_conversations_by_id($userid, array $conversationids) {
2684 global $CFG;
2686 // Check if private messaging between users is allowed.
2687 if (empty($CFG->messaging)) {
2688 throw new moodle_exception('disabled', 'message');
2691 // Validate params.
2692 $params = [
2693 'userid' => $userid,
2694 'conversationids' => $conversationids,
2696 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
2698 // Validate context.
2699 $context = context_system::instance();
2700 self::validate_context($context);
2702 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2703 core_user::require_active_user($user);
2705 foreach ($params['conversationids'] as $conversationid) {
2706 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2707 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2708 } else {
2709 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2713 return [];
2717 * Returns description of method result value.
2719 * @return external_description
2720 * @since 3.6
2722 public static function delete_conversations_by_id_returns() {
2723 return new external_warnings();
2727 * Returns description of method parameters
2729 * @return external_function_parameters
2730 * @since 3.1
2732 public static function delete_message_parameters() {
2733 return new external_function_parameters(
2734 array(
2735 'messageid' => new external_value(PARAM_INT, 'The message id'),
2736 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2737 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2743 * Deletes a message
2745 * @param int $messageid the message id
2746 * @param int $userid the user id of who we want to delete the message for
2747 * @param bool $read if is a message read (default to true)
2748 * @return external_description
2749 * @throws moodle_exception
2750 * @since 3.1
2752 public static function delete_message($messageid, $userid, $read = true) {
2753 global $CFG;
2755 // Check if private messaging between users is allowed.
2756 if (empty($CFG->messaging)) {
2757 throw new moodle_exception('disabled', 'message');
2760 // Warnings array, it can be empty at the end but is mandatory.
2761 $warnings = array();
2763 // Validate params.
2764 $params = array(
2765 'messageid' => $messageid,
2766 'userid' => $userid,
2767 'read' => $read
2769 $params = self::validate_parameters(self::delete_message_parameters(), $params);
2771 // Validate context.
2772 $context = context_system::instance();
2773 self::validate_context($context);
2775 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2776 core_user::require_active_user($user);
2778 if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
2779 $status = \core_message\api::delete_message($user->id, $params['messageid']);
2780 } else {
2781 throw new moodle_exception('You do not have permission to delete this message');
2784 $results = array(
2785 'status' => $status,
2786 'warnings' => $warnings
2788 return $results;
2792 * Returns description of method result value
2794 * @return external_description
2795 * @since 3.1
2797 public static function delete_message_returns() {
2798 return new external_single_structure(
2799 array(
2800 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2801 'warnings' => new external_warnings()
2807 * Returns description of method parameters
2809 * @return external_function_parameters
2810 * @since 3.2
2812 public static function message_processor_config_form_parameters() {
2813 return new external_function_parameters(
2814 array(
2815 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2816 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
2817 'formvalues' => new external_multiple_structure(
2818 new external_single_structure(
2819 array(
2820 'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2821 'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2824 'Config form values',
2825 VALUE_REQUIRED
2832 * Processes a message processor config form.
2834 * @param int $userid the user id
2835 * @param string $name the name of the processor
2836 * @param array $formvalues the form values
2837 * @return external_description
2838 * @throws moodle_exception
2839 * @since 3.2
2841 public static function message_processor_config_form($userid, $name, $formvalues) {
2842 global $USER, $CFG;
2844 // Check if messaging is enabled.
2845 if (empty($CFG->messaging)) {
2846 throw new moodle_exception('disabled', 'message');
2849 $params = self::validate_parameters(
2850 self::message_processor_config_form_parameters(),
2851 array(
2852 'userid' => $userid,
2853 'name' => $name,
2854 'formvalues' => $formvalues,
2858 $user = self::validate_preferences_permissions($params['userid']);
2860 $processor = get_message_processor($params['name']);
2861 $preferences = [];
2862 $form = new stdClass();
2864 foreach ($params['formvalues'] as $formvalue) {
2865 // Curly braces to ensure interpretation is consistent between
2866 // php 5 and php 7.
2867 $form->{$formvalue['name']} = $formvalue['value'];
2870 $processor->process_form($form, $preferences);
2872 if (!empty($preferences)) {
2873 set_user_preferences($preferences, $params['userid']);
2878 * Returns description of method result value
2880 * @return external_description
2881 * @since 3.2
2883 public static function message_processor_config_form_returns() {
2884 return null;
2888 * Returns description of method parameters
2890 * @return external_function_parameters
2891 * @since 3.2
2893 public static function get_message_processor_parameters() {
2894 return new external_function_parameters(
2895 array(
2896 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2897 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
2903 * Get a message processor.
2905 * @param int $userid
2906 * @param string $name the name of the processor
2907 * @return external_description
2908 * @throws moodle_exception
2909 * @since 3.2
2911 public static function get_message_processor($userid = 0, $name) {
2912 global $USER, $PAGE, $CFG;
2914 // Check if messaging is enabled.
2915 if (empty($CFG->messaging)) {
2916 throw new moodle_exception('disabled', 'message');
2919 $params = self::validate_parameters(
2920 self::get_message_processor_parameters(),
2921 array(
2922 'userid' => $userid,
2923 'name' => $name,
2927 if (empty($params['userid'])) {
2928 $params['userid'] = $USER->id;
2931 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2932 core_user::require_active_user($user);
2933 self::validate_context(context_user::instance($params['userid']));
2935 $processor = get_message_processor($params['name']);
2937 $processoroutput = new \core_message\output\processor($processor, $user);
2938 $renderer = $PAGE->get_renderer('core_message');
2940 return $processoroutput->export_for_template($renderer);
2944 * Returns description of method result value
2946 * @return external_description
2947 * @since 3.2
2949 public static function get_message_processor_returns() {
2950 return new external_function_parameters(
2951 array(
2952 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2953 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2959 * Check that the user has enough permission to retrieve message or notifications preferences.
2961 * @param int $userid the user id requesting the preferences
2962 * @return stdClass full user object
2963 * @throws moodle_exception
2964 * @since Moodle 3.2
2966 protected static function validate_preferences_permissions($userid) {
2967 global $USER;
2969 if (empty($userid)) {
2970 $user = $USER;
2971 } else {
2972 $user = core_user::get_user($userid, '*', MUST_EXIST);
2973 core_user::require_active_user($user);
2976 $systemcontext = context_system::instance();
2977 self::validate_context($systemcontext);
2979 // Check access control.
2980 if ($user->id == $USER->id) {
2981 // Editing own message profile.
2982 require_capability('moodle/user:editownmessageprofile', $systemcontext);
2983 } else {
2984 // Teachers, parents, etc.
2985 $personalcontext = context_user::instance($user->id);
2986 require_capability('moodle/user:editmessageprofile', $personalcontext);
2988 return $user;
2992 * Returns a notification or message preference structure.
2994 * @return external_single_structure the structure
2995 * @since Moodle 3.2
2997 protected static function get_preferences_structure() {
2998 return new external_single_structure(
2999 array(
3000 'userid' => new external_value(PARAM_INT, 'User id'),
3001 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3002 'processors' => new external_multiple_structure(
3003 new external_single_structure(
3004 array(
3005 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3006 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3007 'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3008 'contextid' => new external_value(PARAM_INT, 'Context id'),
3009 'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3012 'Config form values'
3014 'components' => new external_multiple_structure(
3015 new external_single_structure(
3016 array(
3017 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3018 'notifications' => new external_multiple_structure(
3019 new external_single_structure(
3020 array(
3021 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3022 'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3023 'processors' => new external_multiple_structure(
3024 new external_single_structure(
3025 array(
3026 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3027 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3028 'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3029 'lockedmessage' => new external_value(PARAM_TEXT,
3030 'Text to display if locked', VALUE_OPTIONAL),
3031 'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3032 'loggedin' => new external_single_structure(
3033 array(
3034 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3035 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3036 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3039 'loggedoff' => new external_single_structure(
3040 array(
3041 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3042 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3043 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3048 'Processors values for this notification'
3052 'List of notificaitons for the component'
3056 'Available components'
3063 * Returns description of method parameters
3065 * @return external_function_parameters
3066 * @since 3.2
3068 public static function get_user_notification_preferences_parameters() {
3069 return new external_function_parameters(
3070 array(
3071 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3077 * Get the notification preferences for a given user.
3079 * @param int $userid id of the user, 0 for current user
3080 * @return external_description
3081 * @throws moodle_exception
3082 * @since 3.2
3084 public static function get_user_notification_preferences($userid = 0) {
3085 global $PAGE;
3087 $params = self::validate_parameters(
3088 self::get_user_notification_preferences_parameters(),
3089 array(
3090 'userid' => $userid,
3093 $user = self::validate_preferences_permissions($params['userid']);
3095 $processors = get_message_processors();
3096 $providers = message_get_providers_for_user($user->id);
3097 $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3098 $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3100 $renderer = $PAGE->get_renderer('core_message');
3102 $result = array(
3103 'warnings' => array(),
3104 'preferences' => $notificationlist->export_for_template($renderer)
3106 return $result;
3110 * Returns description of method result value
3112 * @return external_description
3113 * @since 3.2
3115 public static function get_user_notification_preferences_returns() {
3116 return new external_function_parameters(
3117 array(
3118 'preferences' => self::get_preferences_structure(),
3119 'warnings' => new external_warnings(),
3125 * Returns description of method parameters
3127 * @return external_function_parameters
3128 * @since 3.2
3130 public static function get_user_message_preferences_parameters() {
3131 return new external_function_parameters(
3132 array(
3133 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3139 * Get the notification preferences for a given user.
3141 * @param int $userid id of the user, 0 for current user
3142 * @return external_description
3143 * @throws moodle_exception
3144 * @since 3.2
3146 public static function get_user_message_preferences($userid = 0) {
3147 global $CFG, $PAGE;
3149 $params = self::validate_parameters(
3150 self::get_user_message_preferences_parameters(),
3151 array(
3152 'userid' => $userid,
3156 $user = self::validate_preferences_permissions($params['userid']);
3158 // Filter out enabled, available system_configured and user_configured processors only.
3159 $readyprocessors = array_filter(get_message_processors(), function($processor) {
3160 return $processor->enabled &&
3161 $processor->configured &&
3162 $processor->object->is_user_configured() &&
3163 // Filter out processors that don't have and message preferences to configure.
3164 $processor->object->has_message_preferences();
3167 $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
3168 return $provider->component === 'moodle';
3170 $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
3171 $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
3172 $providers, $preferences, $user);
3174 $renderer = $PAGE->get_renderer('core_message');
3176 $entertosend = get_user_preferences('message_entertosend', $CFG->messagingdefaultpressenter, $user);
3178 $result = array(
3179 'warnings' => array(),
3180 'preferences' => $notificationlistoutput->export_for_template($renderer),
3181 'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id),
3182 'entertosend' => $entertosend
3184 return $result;
3188 * Returns description of method result value
3190 * @return external_description
3191 * @since 3.2
3193 public static function get_user_message_preferences_returns() {
3194 return new external_function_parameters(
3195 array(
3196 'preferences' => self::get_preferences_structure(),
3197 'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'),
3198 'entertosend' => new external_value(PARAM_BOOL, 'User preference for using enter to send messages'),
3199 'warnings' => new external_warnings(),
3205 * Returns description of method parameters for the favourite_conversations() method.
3207 * @return external_function_parameters
3209 public static function set_favourite_conversations_parameters() {
3210 return new external_function_parameters(
3211 array(
3212 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3213 'conversations' => new external_multiple_structure(
3214 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3221 * Favourite a conversation, or list of conversations for a user.
3223 * @param int $userid the id of the user, or 0 for the current user.
3224 * @param array $conversationids the list of conversations ids to favourite.
3225 * @return array
3226 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3228 public static function set_favourite_conversations(int $userid, array $conversationids) {
3229 global $CFG, $USER;
3231 // All the business logic checks that really shouldn't be in here.
3232 if (empty($CFG->messaging)) {
3233 throw new moodle_exception('disabled', 'message');
3235 $params = [
3236 'userid' => $userid,
3237 'conversations' => $conversationids
3239 $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params);
3240 $systemcontext = context_system::instance();
3241 self::validate_context($systemcontext);
3243 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3244 throw new moodle_exception('You do not have permission to perform this action.');
3247 foreach ($params['conversations'] as $conversationid) {
3248 \core_message\api::set_favourite_conversation($conversationid, $params['userid']);
3251 return [];
3255 * Return a description of the returns for the create_user_favourite_conversations() method.
3257 * @return external_description
3259 public static function set_favourite_conversations_returns() {
3260 return new external_warnings();
3264 * Returns description of method parameters for unfavourite_conversations() method.
3266 * @return external_function_parameters
3268 public static function unset_favourite_conversations_parameters() {
3269 return new external_function_parameters(
3270 array(
3271 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3272 'conversations' => new external_multiple_structure(
3273 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3280 * Unfavourite a conversation, or list of conversations for a user.
3282 * @param int $userid the id of the user, or 0 for the current user.
3283 * @param array $conversationids the list of conversations ids unset as favourites.
3284 * @return array
3285 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3287 public static function unset_favourite_conversations(int $userid, array $conversationids) {
3288 global $CFG, $USER;
3290 // All the business logic checks that really shouldn't be in here.
3291 if (empty($CFG->messaging)) {
3292 throw new moodle_exception('disabled', 'message');
3294 $params = [
3295 'userid' => $userid,
3296 'conversations' => $conversationids
3298 $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params);
3299 $systemcontext = context_system::instance();
3300 self::validate_context($systemcontext);
3302 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3303 throw new moodle_exception('You do not have permission to perform this action.');
3306 foreach ($params['conversations'] as $conversationid) {
3307 \core_message\api::unset_favourite_conversation($conversationid, $params['userid']);
3310 return [];
3314 * Unset favourite conversations return description.
3316 * @return external_description
3318 public static function unset_favourite_conversations_returns() {
3319 return new external_warnings();
3323 * Returns description of method parameters for get_member_info() method.
3325 * @return external_function_parameters
3327 public static function get_member_info_parameters() {
3328 return new external_function_parameters(
3329 array(
3330 'referenceuserid' => new external_value(PARAM_INT, 'id of the user'),
3331 'userids' => new external_multiple_structure(
3332 new external_value(PARAM_INT, 'id of members to get')
3334 'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false),
3335 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'include privacy info in response', VALUE_DEFAULT, false)
3341 * Returns conversation member info for the supplied users, relative to the supplied referenceuserid.
3343 * This is the basic structure used when returning members, and includes information about the relationship between each member
3344 * and the referenceuser, such as a whether the referenceuser has marked the member as a contact, or has blocked them.
3346 * @param int $referenceuserid the id of the user which check contact and blocked status.
3347 * @param array $userids
3348 * @return array the array of objects containing member info.
3349 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3351 public static function get_member_info(
3352 int $referenceuserid,
3353 array $userids,
3354 bool $includecontactrequests = false,
3355 bool $includeprivacyinfo = false
3357 global $CFG, $USER;
3359 // All the business logic checks that really shouldn't be in here.
3360 if (empty($CFG->messaging)) {
3361 throw new moodle_exception('disabled', 'message');
3363 $params = [
3364 'referenceuserid' => $referenceuserid,
3365 'userids' => $userids,
3366 'includecontactrequests' => $includecontactrequests,
3367 'includeprivacyinfo' => $includeprivacyinfo
3369 $params = self::validate_parameters(self::get_member_info_parameters(), $params);
3370 $systemcontext = context_system::instance();
3371 self::validate_context($systemcontext);
3373 if (($USER->id != $referenceuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3374 throw new moodle_exception('You do not have permission to perform this action.');
3377 return \core_message\helper::get_member_info(
3378 $params['referenceuserid'],
3379 $params['userids'],
3380 $params['includecontactrequests'],
3381 $params['includeprivacyinfo']
3386 * Get member info return description.
3388 * @return external_description
3390 public static function get_member_info_returns() {
3391 return new external_multiple_structure(
3392 self::get_conversation_member_structure()
3397 * Returns description of method parameters for get_conversation_counts() method.
3399 * @return external_function_parameters
3401 public static function get_conversation_counts_parameters() {
3402 return new external_function_parameters(
3404 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3410 * Returns an array of conversation counts for the various types of conversations, including favourites.
3412 * Return format:
3414 * 'favourites' => 0,
3415 * 'types' => [
3416 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3417 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3421 * @param int $userid the id of the user whose counts we are fetching.
3422 * @return array the array of conversation counts, indexed by type.
3423 * @throws moodle_exception if the current user cannot perform this action.
3425 public static function get_conversation_counts(int $userid) {
3426 global $CFG, $USER;
3428 // All the business logic checks that really shouldn't be in here.
3429 if (empty($CFG->messaging)) {
3430 throw new moodle_exception('disabled', 'message');
3433 if (empty($userid)) {
3434 $userid = $USER->id;
3437 $params = ['userid' => $userid];
3438 $params = self::validate_parameters(self::get_conversation_counts_parameters(), $params);
3440 $systemcontext = context_system::instance();
3441 self::validate_context($systemcontext);
3443 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3444 throw new moodle_exception('You do not have permission to perform this action.');
3447 return \core_message\api::get_conversation_counts($params['userid']);
3451 * Get conversation counts return description.
3453 * @return external_description
3455 public static function get_conversation_counts_returns() {
3456 return new external_single_structure(
3458 'favourites' => new external_value(PARAM_INT, 'Total number of favourite conversations'),
3459 'types' => new external_single_structure(
3461 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3462 'Total number of individual conversations'),
3463 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3464 'Total number of group conversations'),
3465 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3466 'Total number of self conversations'),
3474 * Returns description of method parameters for get_unread_conversation_counts() method.
3476 * @return external_function_parameters
3478 public static function get_unread_conversation_counts_parameters() {
3479 return new external_function_parameters(
3481 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3487 * Returns an array of unread conversation counts for the various types of conversations, including favourites.
3489 * Return format:
3491 * 'favourites' => 0,
3492 * 'types' => [
3493 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3494 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3498 * @param int $userid the id of the user whose counts we are fetching.
3499 * @return array the array of unread conversation counts, indexed by type.
3500 * @throws moodle_exception if the current user cannot perform this action.
3502 public static function get_unread_conversation_counts(int $userid) {
3503 global $CFG, $USER;
3505 // All the business logic checks that really shouldn't be in here.
3506 if (empty($CFG->messaging)) {
3507 throw new moodle_exception('disabled', 'message');
3510 if (empty($userid)) {
3511 $userid = $USER->id;
3514 $params = ['userid' => $userid];
3515 $params = self::validate_parameters(self::get_unread_conversation_counts_parameters(), $params);
3517 $systemcontext = context_system::instance();
3518 self::validate_context($systemcontext);
3520 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3521 throw new moodle_exception('You do not have permission to perform this action.');
3524 return \core_message\api::get_unread_conversation_counts($params['userid']);
3528 * Get unread conversation counts return description.
3530 * @return external_description
3532 public static function get_unread_conversation_counts_returns() {
3533 return new external_single_structure(
3535 'favourites' => new external_value(PARAM_INT, 'Total number of unread favourite conversations'),
3536 'types' => new external_single_structure(
3538 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3539 'Total number of unread individual conversations'),
3540 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3541 'Total number of unread group conversations'),
3542 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3543 'Total number of unread self conversations'),
3551 * Returns description of method parameters
3553 * @return external_function_parameters
3554 * @since 3.7
3556 public static function delete_message_for_all_users_parameters() {
3557 return new external_function_parameters(
3558 array(
3559 'messageid' => new external_value(PARAM_INT, 'The message id'),
3560 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users')
3565 * Deletes a message for all users
3567 * @param int $messageid the message id
3568 * @param int $userid the user id of who we want to delete the message for all users
3569 * @return external_description
3570 * @throws moodle_exception
3571 * @since 3.7
3573 public static function delete_message_for_all_users(int $messageid, int $userid) {
3574 global $CFG;
3576 // Check if private messaging between users is allowed.
3577 if (empty($CFG->messaging)) {
3578 throw new moodle_exception('disabled', 'message');
3581 // Validate params.
3582 $params = array(
3583 'messageid' => $messageid,
3584 'userid' => $userid
3586 $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params);
3588 // Validate context.
3589 $context = context_system::instance();
3590 self::validate_context($context);
3592 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3593 core_user::require_active_user($user);
3595 // Checks if a user can delete a message for all users.
3596 if (core_message\api::can_delete_message_for_all_users($user->id, $params['messageid'])) {
3597 \core_message\api::delete_message_for_all_users($params['messageid']);
3598 } else {
3599 throw new moodle_exception('You do not have permission to delete this message for everyone.');
3602 return [];
3605 * Returns description of method result value
3607 * @return external_description
3608 * @since 3.7
3610 public static function delete_message_for_all_users_returns() {
3611 return new external_warnings();