Merge branch 'MDL-76310' of https://github.com/paulholden/moodle
[moodle.git] / message / externallib.php
blob6e6bc119497a6d67ca6bc1a20b3d80266ad01ab2
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 // Validate messages content before posting them.
92 foreach ($params['messages'] as $message) {
93 // Check message length.
94 if (strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
95 throw new moodle_exception('errormessagetoolong', 'message');
99 $messages = [];
100 foreach ($params['messages'] as $message) {
101 $createdmessage = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
102 $message['textformat']);
103 $createdmessage->text = message_format_message_text((object) [
104 'smallmessage' => $createdmessage->text,
105 'fullmessageformat' => external_validate_format($message['textformat']),
106 'fullmessagetrust' => $createdmessage->fullmessagetrust
108 $messages[] = $createdmessage;
111 return $messages;
115 * Returns description of method result value.
117 * @return external_description
118 * @since Moodle 3.6
120 public static function send_messages_to_conversation_returns() {
121 return new external_multiple_structure(
122 self::get_conversation_message_structure()
128 * Returns description of method parameters
130 * @return external_function_parameters
131 * @since Moodle 2.2
133 public static function send_instant_messages_parameters() {
134 return new external_function_parameters(
135 array(
136 'messages' => new external_multiple_structure(
137 new external_single_structure(
138 array(
139 'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
140 'text' => new external_value(PARAM_RAW, 'the text of the message'),
141 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
142 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the message. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL),
151 * Send private messages from the current USER to other users
153 * @param array $messages An array of message to send.
154 * @return array
155 * @since Moodle 2.2
157 public static function send_instant_messages($messages = array()) {
158 global $CFG, $USER, $DB;
160 // Check if messaging is enabled.
161 if (empty($CFG->messaging)) {
162 throw new moodle_exception('disabled', 'message');
165 // Ensure the current user is allowed to run this function
166 $context = context_system::instance();
167 self::validate_context($context);
168 require_capability('moodle/site:sendmessage', $context);
170 // Ensure the current user is allowed to delete message for everyone.
171 $candeletemessagesforallusers = has_capability('moodle/site:deleteanymessage', $context);
173 $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
175 //retrieve all tousers of the messages
176 $receivers = array();
177 foreach($params['messages'] as $message) {
178 $receivers[] = $message['touserid'];
180 list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
181 $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
183 $resultmessages = array();
184 $messageids = array();
185 foreach ($params['messages'] as $message) {
186 $resultmsg = array(); //the infos about the success of the operation
188 // We are going to do some checking.
189 // Code should match /messages/index.php checks.
190 $success = true;
192 // Check the user exists.
193 if (empty($tousers[$message['touserid']])) {
194 $success = false;
195 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
198 // Check message length.
199 if ($success && strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
200 $success = false;
201 $errormessage = get_string('errormessagetoolong', 'message');
204 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
205 // Check if the recipient can be messaged by the sender.
206 if ($success && !\core_message\api::can_send_message($tousers[$message['touserid']]->id, $USER->id)) {
207 $success = false;
208 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
211 // Now we can send the message (at least try).
212 if ($success) {
213 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
214 $success = message_post_message($USER, $tousers[$message['touserid']],
215 $message['text'], external_validate_format($message['textformat']));
218 // Build the resultmsg.
219 if (isset($message['clientmsgid'])) {
220 $resultmsg['clientmsgid'] = $message['clientmsgid'];
222 if ($success) {
223 $resultmsg['msgid'] = $success;
224 $resultmsg['timecreated'] = time();
225 $resultmsg['candeletemessagesforallusers'] = $candeletemessagesforallusers;
226 $messageids[] = $success;
227 } else {
228 // WARNINGS: for backward compatibility we return this errormessage.
229 // We should have thrown exceptions as these errors prevent results to be returned.
230 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
231 $resultmsg['msgid'] = -1;
232 if (!isset($errormessage)) { // Nobody has set a message error or thrown an exception, let's set it.
233 $errormessage = get_string('messageundeliveredbynotificationsettings', 'error');
235 $resultmsg['errormessage'] = $errormessage;
238 $resultmessages[] = $resultmsg;
241 if (!empty($messageids)) {
242 $messagerecords = $DB->get_records_list(
243 'messages',
244 'id',
245 $messageids,
247 'id, conversationid, smallmessage, fullmessageformat, fullmessagetrust');
248 $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) {
249 $id = $resultmessage['msgid'];
250 $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null;
251 $resultmessage['useridfrom'] = $USER->id;
252 $resultmessage['text'] = message_format_message_text((object) [
253 'smallmessage' => $messagerecords[$id]->smallmessage,
254 'fullmessageformat' => external_validate_format($messagerecords[$id]->fullmessageformat),
255 'fullmessagetrust' => $messagerecords[$id]->fullmessagetrust
257 return $resultmessage;
258 }, $resultmessages);
261 return $resultmessages;
265 * Returns description of method result value
267 * @return external_description
268 * @since Moodle 2.2
270 public static function send_instant_messages_returns() {
271 return new external_multiple_structure(
272 new external_single_structure(
273 array(
274 'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds: id of the created message if it succeeded, -1 when failed'),
275 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
276 'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL),
277 'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL),
278 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
279 'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
280 'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
281 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
282 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
289 * Delete contacts parameters description.
291 * @return external_function_parameters
292 * @since Moodle 2.5
294 public static function delete_contacts_parameters() {
295 return new external_function_parameters(
296 array(
297 'userids' => new external_multiple_structure(
298 new external_value(PARAM_INT, 'User ID'),
299 'List of user IDs'
301 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
302 current user', VALUE_DEFAULT, 0)
308 * Delete contacts.
310 * @param array $userids array of user IDs.
311 * @param int $userid The id of the user we are deleting the contacts for
312 * @return null
313 * @since Moodle 2.5
315 public static function delete_contacts($userids, $userid = 0) {
316 global $CFG, $USER;
318 // Check if messaging is enabled.
319 if (empty($CFG->messaging)) {
320 throw new moodle_exception('disabled', 'message');
323 if (empty($userid)) {
324 $userid = $USER->id;
327 // Validate context.
328 $context = context_system::instance();
329 self::validate_context($context);
331 $params = array('userids' => $userids, 'userid' => $userid);
332 $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
334 $capability = 'moodle/site:manageallmessaging';
335 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
336 throw new required_capability_exception($context, $capability, 'nopermissions', '');
339 foreach ($params['userids'] as $id) {
340 \core_message\api::remove_contact($params['userid'], $id);
343 return null;
347 * Delete contacts return description.
349 * @return external_description
350 * @since Moodle 2.5
352 public static function delete_contacts_returns() {
353 return null;
357 * Mute conversations parameters description.
359 * @return external_function_parameters
361 public static function mute_conversations_parameters() {
362 return new external_function_parameters(
364 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
365 'conversationids' => new external_multiple_structure(
366 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
373 * Mutes conversations.
375 * @param int $userid The id of the user who is blocking
376 * @param array $conversationids The list of conversations being muted
377 * @return external_description
379 public static function mute_conversations(int $userid, array $conversationids) {
380 global $CFG, $USER;
382 // Check if messaging is enabled.
383 if (empty($CFG->messaging)) {
384 throw new moodle_exception('disabled', 'message');
387 // Validate context.
388 $context = context_system::instance();
389 self::validate_context($context);
391 $params = ['userid' => $userid, 'conversationids' => $conversationids];
392 $params = self::validate_parameters(self::mute_conversations_parameters(), $params);
394 $capability = 'moodle/site:manageallmessaging';
395 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
396 throw new required_capability_exception($context, $capability, 'nopermissions', '');
399 foreach ($params['conversationids'] as $conversationid) {
400 if (!\core_message\api::is_conversation_muted($params['userid'], $conversationid)) {
401 \core_message\api::mute_conversation($params['userid'], $conversationid);
405 return [];
409 * Mute conversations return description.
411 * @return external_description
413 public static function mute_conversations_returns() {
414 return new external_warnings();
418 * Unmute conversations parameters description.
420 * @return external_function_parameters
422 public static function unmute_conversations_parameters() {
423 return new external_function_parameters(
425 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
426 'conversationids' => new external_multiple_structure(
427 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
434 * Unmute conversations.
436 * @param int $userid The id of the user who is unblocking
437 * @param array $conversationids The list of conversations being muted
439 public static function unmute_conversations(int $userid, array $conversationids) {
440 global $CFG, $USER;
442 // Check if messaging is enabled.
443 if (empty($CFG->messaging)) {
444 throw new moodle_exception('disabled', 'message');
447 // Validate context.
448 $context = context_system::instance();
449 self::validate_context($context);
451 $params = ['userid' => $userid, 'conversationids' => $conversationids];
452 $params = self::validate_parameters(self::unmute_conversations_parameters(), $params);
454 $capability = 'moodle/site:manageallmessaging';
455 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
456 throw new required_capability_exception($context, $capability, 'nopermissions', '');
459 foreach ($params['conversationids'] as $conversationid) {
460 \core_message\api::unmute_conversation($params['userid'], $conversationid);
463 return [];
467 * Unmute conversations return description.
469 * @return external_description
471 public static function unmute_conversations_returns() {
472 return new external_warnings();
476 * Block user parameters description.
478 * @return external_function_parameters
480 public static function block_user_parameters() {
481 return new external_function_parameters(
483 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
484 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
490 * Blocks a user.
492 * @param int $userid The id of the user who is blocking
493 * @param int $blockeduserid The id of the user being blocked
494 * @return external_description
496 public static function block_user(int $userid, int $blockeduserid) {
497 global $CFG, $USER;
499 // Check if messaging is enabled.
500 if (empty($CFG->messaging)) {
501 throw new moodle_exception('disabled', 'message');
504 // Validate context.
505 $context = context_system::instance();
506 self::validate_context($context);
508 $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
509 $params = self::validate_parameters(self::block_user_parameters(), $params);
511 $capability = 'moodle/site:manageallmessaging';
512 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
513 throw new required_capability_exception($context, $capability, 'nopermissions', '');
516 // If the blocking is going to be useless then don't do it.
517 if (\core_message\api::can_send_message($userid, $blockeduserid, true)) {
518 return [];
521 if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
522 \core_message\api::block_user($params['userid'], $params['blockeduserid']);
525 return [];
529 * Block user return description.
531 * @return external_description
533 public static function block_user_returns() {
534 return new external_warnings();
538 * Unblock user parameters description.
540 * @return external_function_parameters
542 public static function unblock_user_parameters() {
543 return new external_function_parameters(
545 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
546 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
552 * Unblock user.
554 * @param int $userid The id of the user who is unblocking
555 * @param int $unblockeduserid The id of the user being unblocked
557 public static function unblock_user(int $userid, int $unblockeduserid) {
558 global $CFG, $USER;
560 // Check if messaging is enabled.
561 if (empty($CFG->messaging)) {
562 throw new moodle_exception('disabled', 'message');
565 // Validate context.
566 $context = context_system::instance();
567 self::validate_context($context);
569 $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
570 $params = self::validate_parameters(self::unblock_user_parameters(), $params);
572 $capability = 'moodle/site:manageallmessaging';
573 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
574 throw new required_capability_exception($context, $capability, 'nopermissions', '');
577 \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
579 return [];
583 * Unblock user return description.
585 * @return external_description
587 public static function unblock_user_returns() {
588 return new external_warnings();
592 * Returns contact requests parameters description.
594 * @return external_function_parameters
596 public static function get_contact_requests_parameters() {
597 return new external_function_parameters(
599 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
600 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
601 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
607 * Handles returning the contact requests for a user.
609 * This also includes the user data necessary to display information
610 * about the user.
612 * It will not include blocked users.
614 * @param int $userid The id of the user we want to get the contact requests for
615 * @param int $limitfrom
616 * @param int $limitnum
618 public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
619 global $CFG, $USER;
621 // Check if messaging is enabled.
622 if (empty($CFG->messaging)) {
623 throw new moodle_exception('disabled', 'message');
626 // Validate context.
627 $context = context_system::instance();
628 self::validate_context($context);
630 $params = [
631 'userid' => $userid,
632 'limitfrom' => $limitfrom,
633 'limitnum' => $limitnum
635 $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
637 $capability = 'moodle/site:manageallmessaging';
638 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
639 throw new required_capability_exception($context, $capability, 'nopermissions', '');
642 return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
646 * Returns the contact requests return description.
648 * @return external_description
650 public static function get_contact_requests_returns() {
651 return new external_multiple_structure(
652 self::get_conversation_member_structure()
657 * Returns the number of contact requests the user has received parameters description.
659 * @return external_function_parameters
661 public static function get_received_contact_requests_count_parameters() {
662 return new external_function_parameters(
663 array(
664 'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' .
665 'received contact requests for', VALUE_REQUIRED),
671 * Returns the number of contact requests the user has received.
673 * @param int $userid The ID of the user we want to return the number of received contact requests for
674 * @return external_value
676 public static function get_received_contact_requests_count(int $userid) {
677 global $CFG, $USER;
679 // Check if messaging is enabled.
680 if (empty($CFG->messaging)) {
681 throw new moodle_exception('disabled', 'message');
684 // Validate context.
685 $context = context_system::instance();
686 self::validate_context($context);
688 $params = [
689 'userid' => $userid,
691 $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params);
693 $capability = 'moodle/site:manageallmessaging';
694 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
695 throw new required_capability_exception($context, $capability, 'nopermissions', '');
698 return \core_message\api::get_received_contact_requests_count($params['userid']);
702 * Returns the number of contact requests the user has received return description.
704 * @return external_value
706 public static function get_received_contact_requests_count_returns() {
707 return new external_value(PARAM_INT, 'The number of received contact requests');
711 * Returns get conversation members parameters description.
713 * @return external_function_parameters
715 public static function get_conversation_members_parameters() {
716 return new external_function_parameters(
718 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
719 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
720 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
721 VALUE_DEFAULT, false),
722 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?',
723 VALUE_DEFAULT, false),
724 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
725 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
731 * Returns a list of conversation members.
733 * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
734 * @param int $conversationid The id of the conversation
735 * @param bool $includecontactrequests Do we want to include contact requests with this data?
736 * @param bool $includeprivacyinfo Do we want to include privacy info?
737 * @param int $limitfrom
738 * @param int $limitnum
739 * @return array
741 public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
742 bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) {
743 global $CFG, $USER;
745 // Check if messaging is enabled.
746 if (empty($CFG->messaging)) {
747 throw new moodle_exception('disabled', 'message');
750 // Validate context.
751 $context = context_system::instance();
752 self::validate_context($context);
754 $params = [
755 'userid' => $userid,
756 'conversationid' => $conversationid,
757 'includecontactrequests' => $includecontactrequests,
758 'includeprivacyinfo' => $includeprivacyinfo,
759 'limitfrom' => $limitfrom,
760 'limitnum' => $limitnum
762 $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
764 $capability = 'moodle/site:manageallmessaging';
765 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
766 throw new required_capability_exception($context, $capability, 'nopermissions', '');
769 // The user needs to be a part of the conversation before querying who the members are.
770 if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
771 throw new moodle_exception('You are not a member of this conversation.');
774 return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
775 $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']);
779 * Returns the get conversation members return description.
781 * @return external_description
783 public static function get_conversation_members_returns() {
784 return new external_multiple_structure(
785 self::get_conversation_member_structure()
790 * Creates a contact request parameters description.
792 * @return external_function_parameters
794 public static function create_contact_request_parameters() {
795 return new external_function_parameters(
797 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
798 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
804 * Creates a contact request.
806 * @param int $userid The id of the user who is creating the contact request
807 * @param int $requesteduserid The id of the user being requested
809 public static function create_contact_request(int $userid, int $requesteduserid) {
810 global $CFG, $USER;
812 // Check if messaging is enabled.
813 if (empty($CFG->messaging)) {
814 throw new moodle_exception('disabled', 'message');
817 // Validate context.
818 $context = context_system::instance();
819 self::validate_context($context);
821 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
822 $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
824 $capability = 'moodle/site:manageallmessaging';
825 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
826 throw new required_capability_exception($context, $capability, 'nopermissions', '');
829 $result = [
830 'warnings' => []
833 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
834 $result['warnings'][] = [
835 'item' => 'user',
836 'itemid' => $params['requesteduserid'],
837 'warningcode' => 'cannotcreatecontactrequest',
838 'message' => 'You are unable to create a contact request for this user'
840 } else {
841 if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
842 // There should only ever be one but just in case there are multiple then we can return the first.
843 $result['request'] = array_shift($requests);
844 } else {
845 $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
849 return $result;
853 * Creates a contact request return description.
855 * @return external_description
857 public static function create_contact_request_returns() {
858 return new external_single_structure(
859 array(
860 'request' => new external_single_structure(
861 array(
862 'id' => new external_value(PARAM_INT, 'Message id'),
863 'userid' => new external_value(PARAM_INT, 'User from id'),
864 'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
865 'timecreated' => new external_value(PARAM_INT, 'Time created'),
867 'request record',
868 VALUE_OPTIONAL
870 'warnings' => new external_warnings()
876 * Confirm a contact request parameters description.
878 * @return external_function_parameters
880 public static function confirm_contact_request_parameters() {
881 return new external_function_parameters(
883 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
884 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
890 * Confirm a contact request.
892 * @param int $userid The id of the user who is creating the contact request
893 * @param int $requesteduserid The id of the user being requested
895 public static function confirm_contact_request(int $userid, int $requesteduserid) {
896 global $CFG, $USER;
898 // Check if messaging is enabled.
899 if (empty($CFG->messaging)) {
900 throw new moodle_exception('disabled', 'message');
903 // Validate context.
904 $context = context_system::instance();
905 self::validate_context($context);
907 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
908 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
910 $capability = 'moodle/site:manageallmessaging';
911 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
912 throw new required_capability_exception($context, $capability, 'nopermissions', '');
915 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
917 return [];
921 * Confirm a contact request return description.
923 * @return external_description
925 public static function confirm_contact_request_returns() {
926 return new external_warnings();
930 * Declines a contact request parameters description.
932 * @return external_function_parameters
934 public static function decline_contact_request_parameters() {
935 return new external_function_parameters(
937 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
938 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
944 * Declines a contact request.
946 * @param int $userid The id of the user who is creating the contact request
947 * @param int $requesteduserid The id of the user being requested
949 public static function decline_contact_request(int $userid, int $requesteduserid) {
950 global $CFG, $USER;
952 // Check if messaging is enabled.
953 if (empty($CFG->messaging)) {
954 throw new moodle_exception('disabled', 'message');
957 // Validate context.
958 $context = context_system::instance();
959 self::validate_context($context);
961 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
962 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
964 $capability = 'moodle/site:manageallmessaging';
965 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
966 throw new required_capability_exception($context, $capability, 'nopermissions', '');
969 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
971 return [];
975 * Declines a contact request return description.
977 * @return external_description
979 public static function decline_contact_request_returns() {
980 return new external_warnings();
984 * Return the structure of a message area contact.
986 * @return external_single_structure
987 * @since Moodle 3.2
989 private static function get_messagearea_contact_structure() {
990 return new external_single_structure(
991 array(
992 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
993 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
994 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
995 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
996 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
997 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
998 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
999 'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null),
1000 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
1001 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1002 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1003 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
1004 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1005 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1006 VALUE_DEFAULT, null),
1007 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null),
1013 * Return the structure of a conversation.
1015 * @return external_single_structure
1016 * @since Moodle 3.6
1018 private static function get_conversation_structure() {
1019 return new external_single_structure(
1020 array(
1021 'id' => new external_value(PARAM_INT, 'The conversation id'),
1022 'name' => new external_value(PARAM_RAW, 'The conversation name, if set', VALUE_DEFAULT, null),
1023 'subname' => new external_value(PARAM_RAW, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1024 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1025 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group,3=self)'),
1026 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1027 'ismuted' => new external_value(PARAM_BOOL, 'If the user muted this conversation'),
1028 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this conversation as a favourite'),
1029 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1030 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1031 VALUE_DEFAULT, null),
1032 'members' => new external_multiple_structure(
1033 self::get_conversation_member_structure()
1035 'messages' => new external_multiple_structure(
1036 self::get_conversation_message_structure()
1038 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
1039 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
1045 * Return the structure of a conversation member.
1047 * @return external_single_structure
1048 * @since Moodle 3.6
1050 private static function get_conversation_member_structure() {
1051 $result = [
1052 'id' => new external_value(PARAM_INT, 'The user id'),
1053 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1054 'profileurl' => new external_value(PARAM_URL, 'The link to the user\'s profile page'),
1055 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1056 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1057 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1058 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1059 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1060 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1061 'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1062 'canmessageevenifblocked' => new external_value(PARAM_BOOL,
1063 'If the user can still message even if they get blocked'),
1064 'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1065 'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1068 $result['contactrequests'] = new external_multiple_structure(
1069 new external_single_structure(
1071 'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1072 'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1073 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1074 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1076 ), 'The contact requests', VALUE_OPTIONAL
1079 $result['conversations'] = new external_multiple_structure(new external_single_structure(
1080 array(
1081 'id' => new external_value(PARAM_INT, 'Conversations id'),
1082 'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1083 'name' => new external_value(PARAM_RAW, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1084 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1085 ), 'information about conversation', VALUE_OPTIONAL),
1086 'Conversations between users', VALUE_OPTIONAL
1089 return new external_single_structure(
1090 $result
1095 * Return the structure of a message area message.
1097 * @return external_single_structure
1098 * @since Moodle 3.6
1100 private static function get_conversation_message_structure() {
1101 return new external_single_structure(
1102 array(
1103 'id' => new external_value(PARAM_INT, 'The id of the message'),
1104 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1105 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1106 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1112 * Get messagearea message search users parameters.
1114 * @return external_function_parameters
1115 * @since 3.6
1117 public static function message_search_users_parameters() {
1118 return new external_function_parameters(
1119 array(
1120 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1121 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1122 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1123 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1129 * Get search users results.
1131 * @param int $userid The id of the user who is performing the search
1132 * @param string $search The string being searched
1133 * @param int $limitfrom
1134 * @param int $limitnum
1135 * @return array
1136 * @throws moodle_exception
1137 * @since 3.6
1139 public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1140 global $USER;
1142 $systemcontext = context_system::instance();
1144 $params = array(
1145 'userid' => $userid,
1146 'search' => $search,
1147 'limitfrom' => $limitfrom,
1148 'limitnum' => $limitnum
1150 $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1151 self::validate_context($systemcontext);
1153 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1154 throw new moodle_exception('You do not have permission to perform this action.');
1157 list($contacts, $noncontacts) = \core_message\api::message_search_users(
1158 $params['userid'],
1159 $params['search'],
1160 $params['limitfrom'],
1161 $params['limitnum']);
1163 return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1167 * Get messagearea message search users returns.
1169 * @return external_single_structure
1170 * @since 3.2
1172 public static function message_search_users_returns() {
1173 return new external_single_structure(
1174 array(
1175 'contacts' => new external_multiple_structure(
1176 self::get_conversation_member_structure()
1178 'noncontacts' => new external_multiple_structure(
1179 self::get_conversation_member_structure()
1186 * Get messagearea search messages parameters.
1188 * @return external_function_parameters
1189 * @since 3.2
1191 public static function data_for_messagearea_search_messages_parameters() {
1192 return new external_function_parameters(
1193 array(
1194 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1195 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1196 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1197 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1203 * Get messagearea search messages results.
1205 * @param int $userid The id of the user who is performing the search
1206 * @param string $search The string being searched
1207 * @param int $limitfrom
1208 * @param int $limitnum
1209 * @return stdClass
1210 * @throws moodle_exception
1211 * @since 3.2
1213 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1214 global $CFG, $USER;
1216 // Check if messaging is enabled.
1217 if (empty($CFG->messaging)) {
1218 throw new moodle_exception('disabled', 'message');
1221 $systemcontext = context_system::instance();
1223 $params = array(
1224 'userid' => $userid,
1225 'search' => $search,
1226 'limitfrom' => $limitfrom,
1227 'limitnum' => $limitnum
1230 $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1231 self::validate_context($systemcontext);
1233 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1234 throw new moodle_exception('You do not have permission to perform this action.');
1237 $messages = \core_message\api::search_messages(
1238 $params['userid'],
1239 $params['search'],
1240 $params['limitfrom'],
1241 $params['limitnum']
1244 $data = new \stdClass();
1245 $data->contacts = [];
1246 foreach ($messages as $message) {
1247 $contact = new \stdClass();
1248 $contact->userid = $message->userid;
1249 $contact->fullname = $message->fullname;
1250 $contact->profileimageurl = $message->profileimageurl;
1251 $contact->profileimageurlsmall = $message->profileimageurlsmall;
1252 $contact->messageid = $message->messageid;
1253 $contact->ismessaging = $message->ismessaging;
1254 $contact->sentfromcurrentuser = false;
1255 if ($message->lastmessage) {
1256 if ($message->userid !== $message->useridfrom) {
1257 $contact->sentfromcurrentuser = true;
1259 $contact->lastmessage = shorten_text($message->lastmessage, 60);
1260 } else {
1261 $contact->lastmessage = null;
1263 $contact->lastmessagedate = $message->lastmessagedate;
1264 $contact->showonlinestatus = is_null($message->isonline) ? false : true;
1265 $contact->isonline = $message->isonline;
1266 $contact->isblocked = $message->isblocked;
1267 $contact->isread = $message->isread;
1268 $contact->unreadcount = $message->unreadcount;
1269 $contact->conversationid = $message->conversationid;
1271 $data->contacts[] = $contact;
1274 return $data;
1278 * Get messagearea search messages returns.
1280 * @return external_single_structure
1281 * @since 3.2
1283 public static function data_for_messagearea_search_messages_returns() {
1284 return new external_single_structure(
1285 array(
1286 'contacts' => new external_multiple_structure(
1287 self::get_messagearea_contact_structure()
1294 * Get conversations parameters.
1296 * @return external_function_parameters
1297 * @since 3.6
1299 public static function get_conversations_parameters() {
1300 return new external_function_parameters(
1301 array(
1302 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1303 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1304 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1305 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1306 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1307 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1308 VALUE_DEFAULT, null),
1309 'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private
1310 conversations (false) when private conversations are requested.',
1311 VALUE_DEFAULT, false),
1317 * Get the list of conversations for the user.
1319 * @param int $userid The id of the user who is performing the search
1320 * @param int $limitfrom
1321 * @param int $limitnum
1322 * @param int|null $type
1323 * @param bool|null $favourites
1324 * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false)
1325 * when private conversations are requested.
1326 * @return stdClass
1327 * @throws \moodle_exception if the messaging feature is disabled on the site.
1328 * @since 3.2
1330 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null,
1331 bool $mergeself = false) {
1332 global $CFG, $USER;
1334 // All the standard BL checks.
1335 if (empty($CFG->messaging)) {
1336 throw new moodle_exception('disabled', 'message');
1339 $params = array(
1340 'userid' => $userid,
1341 'limitfrom' => $limitfrom,
1342 'limitnum' => $limitnum,
1343 'type' => $type,
1344 'favourites' => $favourites,
1345 'mergeself' => $mergeself
1347 $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1349 $systemcontext = context_system::instance();
1350 self::validate_context($systemcontext);
1352 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1353 throw new moodle_exception('You do not have permission to perform this action.');
1356 $conversations = \core_message\api::get_conversations(
1357 $params['userid'],
1358 $params['limitfrom'],
1359 $params['limitnum'],
1360 $params['type'],
1361 $params['favourites'],
1362 $params['mergeself']
1365 return (object) ['conversations' => $conversations];
1369 * Get conversations returns.
1371 * @return external_single_structure
1372 * @since 3.6
1374 public static function get_conversations_returns() {
1375 return new external_single_structure(
1377 'conversations' => new external_multiple_structure(
1378 self::get_conversation_structure(true)
1385 * Get conversation parameters.
1387 * @return external_function_parameters
1389 public static function get_conversation_parameters() {
1390 return new external_function_parameters(
1391 array(
1392 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1393 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1394 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1395 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1396 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1397 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1398 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1399 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1400 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1406 * Get a single conversation.
1408 * @param int $userid The user id to get the conversation for
1409 * @param int $conversationid The id of the conversation to fetch
1410 * @param bool $includecontactrequests Should contact requests be included between members
1411 * @param bool $includeprivacyinfo Should privacy info be included between members
1412 * @param int $memberlimit Limit number of members to load
1413 * @param int $memberoffset Offset members by this amount
1414 * @param int $messagelimit Limit number of messages to load
1415 * @param int $messageoffset Offset the messages
1416 * @param bool $newestmessagesfirst Order messages by newest first
1417 * @return stdClass
1418 * @throws \moodle_exception if the messaging feature is disabled on the site.
1420 public static function get_conversation(
1421 int $userid,
1422 int $conversationid,
1423 bool $includecontactrequests = false,
1424 bool $includeprivacyinfo = false,
1425 int $memberlimit = 0,
1426 int $memberoffset = 0,
1427 int $messagelimit = 0,
1428 int $messageoffset = 0,
1429 bool $newestmessagesfirst = true
1431 global $CFG, $DB, $USER;
1433 // All the standard BL checks.
1434 if (empty($CFG->messaging)) {
1435 throw new moodle_exception('disabled', 'message');
1438 $params = [
1439 'userid' => $userid,
1440 'conversationid' => $conversationid,
1441 'includecontactrequests' => $includecontactrequests,
1442 'includeprivacyinfo' => $includeprivacyinfo,
1443 'memberlimit' => $memberlimit,
1444 'memberoffset' => $memberoffset,
1445 'messagelimit' => $messagelimit,
1446 'messageoffset' => $messageoffset,
1447 'newestmessagesfirst' => $newestmessagesfirst
1449 self::validate_parameters(self::get_conversation_parameters(), $params);
1451 $systemcontext = context_system::instance();
1452 self::validate_context($systemcontext);
1454 $conversation = \core_message\api::get_conversation(
1455 $params['userid'],
1456 $params['conversationid'],
1457 $params['includecontactrequests'],
1458 $params['includeprivacyinfo'],
1459 $params['memberlimit'],
1460 $params['memberoffset'],
1461 $params['messagelimit'],
1462 $params['messageoffset'],
1463 $params['newestmessagesfirst']
1466 if ($conversation) {
1467 return $conversation;
1468 } else {
1469 // We have to throw an exception here because the external functions annoyingly
1470 // don't accept null to be returned for a single structure.
1471 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1476 * Get conversation returns.
1478 * @return external_single_structure
1480 public static function get_conversation_returns() {
1481 return self::get_conversation_structure();
1485 * Get conversation parameters.
1487 * @return external_function_parameters
1489 public static function get_conversation_between_users_parameters() {
1490 return new external_function_parameters(
1491 array(
1492 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1493 'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1494 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1495 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1496 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1497 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1498 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1499 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1500 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1506 * Get a single conversation between users.
1508 * @param int $userid The user id to get the conversation for
1509 * @param int $otheruserid The other user id
1510 * @param bool $includecontactrequests Should contact requests be included between members
1511 * @param bool $includeprivacyinfo Should privacy info be included between members
1512 * @param int $memberlimit Limit number of members to load
1513 * @param int $memberoffset Offset members by this amount
1514 * @param int $messagelimit Limit number of messages to load
1515 * @param int $messageoffset Offset the messages
1516 * @param bool $newestmessagesfirst Order messages by newest first
1517 * @return stdClass
1518 * @throws \moodle_exception if the messaging feature is disabled on the site.
1520 public static function get_conversation_between_users(
1521 int $userid,
1522 int $otheruserid,
1523 bool $includecontactrequests = false,
1524 bool $includeprivacyinfo = false,
1525 int $memberlimit = 0,
1526 int $memberoffset = 0,
1527 int $messagelimit = 0,
1528 int $messageoffset = 0,
1529 bool $newestmessagesfirst = true
1531 global $CFG, $DB, $USER;
1533 // All the standard BL checks.
1534 if (empty($CFG->messaging)) {
1535 throw new moodle_exception('disabled', 'message');
1538 $params = [
1539 'userid' => $userid,
1540 'otheruserid' => $otheruserid,
1541 'includecontactrequests' => $includecontactrequests,
1542 'includeprivacyinfo' => $includeprivacyinfo,
1543 'memberlimit' => $memberlimit,
1544 'memberoffset' => $memberoffset,
1545 'messagelimit' => $messagelimit,
1546 'messageoffset' => $messageoffset,
1547 'newestmessagesfirst' => $newestmessagesfirst
1549 self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
1551 $systemcontext = context_system::instance();
1552 self::validate_context($systemcontext);
1554 $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
1555 $conversation = null;
1557 if ($conversationid) {
1558 $conversation = \core_message\api::get_conversation(
1559 $params['userid'],
1560 $conversationid,
1561 $params['includecontactrequests'],
1562 $params['includeprivacyinfo'],
1563 $params['memberlimit'],
1564 $params['memberoffset'],
1565 $params['messagelimit'],
1566 $params['messageoffset'],
1567 $params['newestmessagesfirst']
1571 if ($conversation) {
1572 return $conversation;
1573 } else {
1574 // We have to throw an exception here because the external functions annoyingly
1575 // don't accept null to be returned for a single structure.
1576 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1581 * Get conversation returns.
1583 * @return external_single_structure
1585 public static function get_conversation_between_users_returns() {
1586 return self::get_conversation_structure(true);
1590 * Get self-conversation parameters.
1592 * @return external_function_parameters
1594 public static function get_self_conversation_parameters() {
1595 return new external_function_parameters(
1596 array(
1597 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'),
1598 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1599 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1600 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1606 * Get a single self-conversation.
1608 * @param int $userid The user id to get the self-conversation for
1609 * @param int $messagelimit Limit number of messages to load
1610 * @param int $messageoffset Offset the messages
1611 * @param bool $newestmessagesfirst Order messages by newest first
1612 * @return stdClass
1613 * @throws \moodle_exception if the messaging feature is disabled on the site.
1614 * @since Moodle 3.7
1616 public static function get_self_conversation(
1617 int $userid,
1618 int $messagelimit = 0,
1619 int $messageoffset = 0,
1620 bool $newestmessagesfirst = true
1622 global $CFG;
1624 // All the standard BL checks.
1625 if (empty($CFG->messaging)) {
1626 throw new moodle_exception('disabled', 'message');
1629 $params = [
1630 'userid' => $userid,
1631 'messagelimit' => $messagelimit,
1632 'messageoffset' => $messageoffset,
1633 'newestmessagesfirst' => $newestmessagesfirst
1635 self::validate_parameters(self::get_self_conversation_parameters(), $params);
1637 $systemcontext = context_system::instance();
1638 self::validate_context($systemcontext);
1640 $conversation = \core_message\api::get_self_conversation($params['userid']);
1642 if ($conversation) {
1643 $conversation = \core_message\api::get_conversation(
1644 $params['userid'],
1645 $conversation->id,
1646 false,
1647 false,
1650 $params['messagelimit'],
1651 $params['messageoffset'],
1652 $params['newestmessagesfirst']
1656 if ($conversation) {
1657 return $conversation;
1658 } else {
1659 // We have to throw an exception here because the external functions annoyingly
1660 // don't accept null to be returned for a single structure.
1661 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1666 * Get conversation returns.
1668 * @return external_single_structure
1670 public static function get_self_conversation_returns() {
1671 return self::get_conversation_structure();
1675 * The conversation messages parameters.
1677 * @return external_function_parameters
1678 * @since 3.6
1680 public static function get_conversation_messages_parameters() {
1681 return new external_function_parameters(
1682 array(
1683 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1684 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1685 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1686 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1687 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1688 'timefrom' => new external_value(PARAM_INT,
1689 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1695 * Get conversation messages.
1697 * @param int $currentuserid The current user's id.
1698 * @param int $convid The conversation id.
1699 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1700 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1701 * @param bool $newest True for getting first newest messages, false otherwise.
1702 * @param int $timefrom The time from the conversation messages to get.
1703 * @return array The messages and members who have sent some of these messages.
1704 * @throws moodle_exception
1705 * @since 3.6
1707 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1708 bool $newest = false, int $timefrom = 0) {
1709 global $CFG, $USER;
1711 // Check if messaging is enabled.
1712 if (empty($CFG->messaging)) {
1713 throw new moodle_exception('disabled', 'message');
1716 $systemcontext = context_system::instance();
1718 $params = array(
1719 'currentuserid' => $currentuserid,
1720 'convid' => $convid,
1721 'limitfrom' => $limitfrom,
1722 'limitnum' => $limitnum,
1723 'newest' => $newest,
1724 'timefrom' => $timefrom,
1726 $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1727 self::validate_context($systemcontext);
1729 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1730 throw new moodle_exception('You do not have permission to perform this action.');
1733 // Check that the user belongs to the conversation.
1734 if (!\core_message\api::is_user_in_conversation($params['currentuserid'], $params['convid'])) {
1735 throw new moodle_exception('User is not part of conversation.');
1738 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1740 // We need to enforce a one second delay on messages to avoid race conditions of current
1741 // messages still being sent.
1743 // There is a chance that we could request messages before the current time's
1744 // second has elapsed and while other messages are being sent in that same second. In which
1745 // case those messages will be lost.
1747 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1748 $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1750 // No requesting messages from the current time, as stated above.
1751 if ($params['timefrom'] == time()) {
1752 $messages = [];
1753 } else {
1754 $messages = \core_message\api::get_conversation_messages(
1755 $params['currentuserid'],
1756 $params['convid'],
1757 $params['limitfrom'],
1758 $params['limitnum'],
1759 $sort,
1760 $params['timefrom'],
1761 $timeto);
1764 return $messages;
1768 * The messagearea messages return structure.
1770 * @return external_single_structure
1771 * @since 3.6
1773 public static function get_conversation_messages_returns() {
1774 return new external_single_structure(
1775 array(
1776 'id' => new external_value(PARAM_INT, 'The conversation id'),
1777 'members' => new external_multiple_structure(
1778 self::get_conversation_member_structure()
1780 'messages' => new external_multiple_structure(
1781 self::get_conversation_message_structure()
1788 * The user contacts return parameters.
1790 * @return external_function_parameters
1792 public static function get_user_contacts_parameters() {
1793 return new external_function_parameters(
1794 array(
1795 'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
1796 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1797 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1803 * Get user contacts.
1805 * @param int $userid The id of the user who we are viewing conversations for
1806 * @param int $limitfrom
1807 * @param int $limitnum
1808 * @return array
1809 * @throws moodle_exception
1811 public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
1812 global $CFG, $USER;
1814 // Check if messaging is enabled.
1815 if (empty($CFG->messaging)) {
1816 throw new moodle_exception('disabled', 'message');
1819 $systemcontext = context_system::instance();
1821 $params = array(
1822 'userid' => $userid,
1823 'limitfrom' => $limitfrom,
1824 'limitnum' => $limitnum
1826 $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
1827 self::validate_context($systemcontext);
1829 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1830 throw new moodle_exception('You do not have permission to perform this action.');
1833 return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1837 * The user contacts return structure.
1839 * @return external_multiple_structure
1841 public static function get_user_contacts_returns() {
1842 return new external_multiple_structure(
1843 self::get_conversation_member_structure()
1848 * Search contacts parameters description.
1850 * @return external_function_parameters
1851 * @since Moodle 2.5
1853 public static function search_contacts_parameters() {
1854 return new external_function_parameters(
1855 array(
1856 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1857 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1858 VALUE_DEFAULT, false)
1864 * Search contacts.
1866 * @param string $searchtext query string.
1867 * @param bool $onlymycourses limit the search to the user's courses only.
1868 * @return external_description
1869 * @since Moodle 2.5
1871 public static function search_contacts($searchtext, $onlymycourses = false) {
1872 global $CFG, $USER, $PAGE;
1873 require_once($CFG->dirroot . '/user/lib.php');
1875 // Check if messaging is enabled.
1876 if (empty($CFG->messaging)) {
1877 throw new moodle_exception('disabled', 'message');
1880 require_once($CFG->libdir . '/enrollib.php');
1882 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1883 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1885 // Extra validation, we do not allow empty queries.
1886 if ($params['searchtext'] === '') {
1887 throw new moodle_exception('querystringcannotbeempty');
1890 $courseids = array();
1891 if ($params['onlymycourses']) {
1892 $mycourses = enrol_get_my_courses(array('id'));
1893 foreach ($mycourses as $mycourse) {
1894 $courseids[] = $mycourse->id;
1896 } else {
1897 $courseids[] = SITEID;
1900 // Retrieving the users matching the query.
1901 $users = message_search_users($courseids, $params['searchtext']);
1902 $results = array();
1903 foreach ($users as $user) {
1904 $results[$user->id] = $user;
1907 // Reorganising information.
1908 foreach ($results as &$user) {
1909 $newuser = array(
1910 'id' => $user->id,
1911 'fullname' => fullname($user)
1914 // Avoid undefined property notice as phone not specified.
1915 $user->phone1 = null;
1916 $user->phone2 = null;
1918 $userpicture = new user_picture($user);
1919 $userpicture->size = 1; // Size f1.
1920 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1921 $userpicture->size = 0; // Size f2.
1922 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1924 $user = $newuser;
1927 return $results;
1931 * Search contacts return description.
1933 * @return external_description
1934 * @since Moodle 2.5
1936 public static function search_contacts_returns() {
1937 return new external_multiple_structure(
1938 new external_single_structure(
1939 array(
1940 'id' => new external_value(PARAM_INT, 'User ID'),
1941 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1942 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1943 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1946 'List of contacts'
1951 * Get messages parameters description.
1953 * @return external_function_parameters
1954 * @since 2.8
1956 public static function get_messages_parameters() {
1957 return new external_function_parameters(
1958 array(
1959 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1960 'useridfrom' => new external_value(
1961 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1962 VALUE_DEFAULT, 0),
1963 'type' => new external_value(
1964 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1965 VALUE_DEFAULT, 'both'),
1966 'read' => new external_value(PARAM_INT, '1 for getting read messages, 0 for unread, 2 for both',
1967 VALUE_DEFAULT, 1),
1968 'newestfirst' => new external_value(
1969 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1970 VALUE_DEFAULT, true),
1971 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1972 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1978 * Get messages function implementation.
1980 * @since 2.8
1981 * @throws invalid_parameter_exception
1982 * @throws moodle_exception
1983 * @param int $useridto the user id who received the message
1984 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
1985 * @param string $type type of message to return, expected values: notifications, conversations and both
1986 * @param int $read 1 for getting read messages, 0 for unread, 2 for both
1987 * @param bool $newestfirst true for ordering by newest first, false for oldest first
1988 * @param int $limitfrom limit from
1989 * @param int $limitnum limit num
1990 * @return external_description
1992 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = MESSAGE_GET_READ,
1993 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
1994 global $CFG, $USER, $PAGE;
1996 $warnings = array();
1998 $params = array(
1999 'useridto' => $useridto,
2000 'useridfrom' => $useridfrom,
2001 'type' => $type,
2002 'read' => $read,
2003 'newestfirst' => $newestfirst,
2004 'limitfrom' => $limitfrom,
2005 'limitnum' => $limitnum
2008 $params = self::validate_parameters(self::get_messages_parameters(), $params);
2010 $context = context_system::instance();
2011 self::validate_context($context);
2013 $useridto = $params['useridto'];
2014 $useridfrom = $params['useridfrom'];
2015 $type = $params['type'];
2016 $read = $params['read'];
2017 $newestfirst = $params['newestfirst'];
2018 $limitfrom = $params['limitfrom'];
2019 $limitnum = $params['limitnum'];
2021 $allowedvalues = array('notifications', 'conversations', 'both');
2022 if (!in_array($type, $allowedvalues)) {
2023 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2024 'allowed values are: ' . implode(',', $allowedvalues));
2027 // Check if private messaging between users is allowed.
2028 if (empty($CFG->messaging)) {
2029 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2030 if ($type == "conversations") {
2031 throw new moodle_exception('disabled', 'message');
2033 if ($type == "both") {
2034 $warning = array();
2035 $warning['item'] = 'message';
2036 $warning['itemid'] = $USER->id;
2037 $warning['warningcode'] = '1';
2038 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2039 Only notifications will be returned';
2040 $warnings[] = $warning;
2044 if (!empty($useridto)) {
2045 if (core_user::is_real_user($useridto)) {
2046 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2047 } else {
2048 throw new moodle_exception('invaliduser');
2052 if (!empty($useridfrom)) {
2053 // We use get_user here because the from user can be the noreply or support user.
2054 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2057 // Check if the current user is the sender/receiver or just a privileged user.
2058 if ($useridto != $USER->id and $useridfrom != $USER->id and
2059 !has_capability('moodle/site:readallmessages', $context)) {
2060 throw new moodle_exception('accessdenied', 'admin');
2063 // Which type of messages to retrieve.
2064 $notifications = -1;
2065 if ($type != 'both') {
2066 $notifications = ($type == 'notifications') ? 1 : 0;
2069 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2070 $sort = "mr.timecreated $orderdirection";
2072 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2073 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2075 // In some cases, we don't need to get the to/from user objects from the sql query.
2076 $userfromfullname = '';
2077 $usertofullname = '';
2079 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2080 if (!empty($useridto)) {
2081 $usertofullname = fullname($userto, $canviewfullname);
2082 // The user from may or may not be filled.
2083 if (!empty($useridfrom)) {
2084 $userfromfullname = fullname($userfrom, $canviewfullname);
2086 } else {
2087 // If the useridto field is empty, the useridfrom must be filled.
2088 $userfromfullname = fullname($userfrom, $canviewfullname);
2090 foreach ($messages as $mid => $message) {
2092 if (!$message->notification) {
2093 // Do not return deleted messages.
2094 if (($useridto == $USER->id and $message->timeusertodeleted) or
2095 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2096 unset($messages[$mid]);
2097 continue;
2099 } else {
2100 // Return iconurl for notifications.
2101 if (!isset($output)) {
2102 $output = $PAGE->get_renderer('core');
2105 if (!empty($message->component) && substr($message->component, 0, 4) == 'mod_') {
2106 $iconurl = $output->image_url('monologo', $message->component);
2107 } else {
2108 $iconurl = $output->image_url('i/marker', 'core');
2111 $message->iconurl = clean_param($iconurl->out(), PARAM_URL);
2114 // We need to get the user from the query.
2115 if (empty($userfromfullname)) {
2116 // Check for non-reply and support users.
2117 if (core_user::is_real_user($message->useridfrom)) {
2118 $user = new stdClass();
2119 $user = username_load_fields_from_object($user, $message, 'userfrom');
2120 $message->userfromfullname = fullname($user, $canviewfullname);
2121 } else {
2122 $user = core_user::get_user($message->useridfrom);
2123 $message->userfromfullname = fullname($user, $canviewfullname);
2125 } else {
2126 $message->userfromfullname = $userfromfullname;
2129 // We need to get the user from the query.
2130 if (empty($usertofullname)) {
2131 $user = new stdClass();
2132 $user = username_load_fields_from_object($user, $message, 'userto');
2133 $message->usertofullname = fullname($user, $canviewfullname);
2134 } else {
2135 $message->usertofullname = $usertofullname;
2138 $message->text = message_format_message_text($message);
2139 $messages[$mid] = (array) $message;
2143 $results = array(
2144 'messages' => $messages,
2145 'warnings' => $warnings
2148 return $results;
2152 * Get messages return description.
2154 * @return external_single_structure
2155 * @since 2.8
2157 public static function get_messages_returns() {
2158 return new external_single_structure(
2159 array(
2160 'messages' => new external_multiple_structure(
2161 new external_single_structure(
2162 array(
2163 'id' => new external_value(PARAM_INT, 'Message id'),
2164 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2165 'useridto' => new external_value(PARAM_INT, 'User to id'),
2166 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2167 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2168 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2169 'fullmessageformat' => new external_format_value('fullmessage'),
2170 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2171 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2172 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2173 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2174 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2175 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2176 'timeread' => new external_value(PARAM_INT, 'Time read'),
2177 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2178 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
2179 'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
2180 VALUE_OPTIONAL),
2181 'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
2182 'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
2183 The data here is serialised using json_encode().', VALUE_OPTIONAL),
2184 'iconurl' => new external_value(PARAM_URL, 'URL for icon, only for notifications.', VALUE_OPTIONAL),
2185 ), 'message'
2188 'warnings' => new external_warnings()
2194 * Mark all notifications as read parameters description.
2196 * @return external_function_parameters
2197 * @since 3.2
2199 public static function mark_all_notifications_as_read_parameters() {
2200 return new external_function_parameters(
2201 array(
2202 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2203 'useridfrom' => new external_value(
2204 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2205 VALUE_DEFAULT, 0),
2206 'timecreatedto' => new external_value(
2207 PARAM_INT, 'mark messages created before this time as read, 0 for all messages',
2208 VALUE_DEFAULT, 0),
2214 * Mark all notifications as read function.
2216 * @since 3.2
2217 * @throws invalid_parameter_exception
2218 * @throws moodle_exception
2219 * @param int $useridto the user id who received the message
2220 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2221 * @param int $timecreatedto mark message created before this time as read, 0 for all messages
2222 * @return external_description
2224 public static function mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto = 0) {
2225 global $USER;
2227 $params = self::validate_parameters(
2228 self::mark_all_notifications_as_read_parameters(),
2229 array(
2230 'useridto' => $useridto,
2231 'useridfrom' => $useridfrom,
2232 'timecreatedto' => $timecreatedto,
2236 $context = context_system::instance();
2237 self::validate_context($context);
2239 $useridto = $params['useridto'];
2240 $useridfrom = $params['useridfrom'];
2241 $timecreatedto = $params['timecreatedto'];
2243 if (!empty($useridto)) {
2244 if (core_user::is_real_user($useridto)) {
2245 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2246 } else {
2247 throw new moodle_exception('invaliduser');
2251 if (!empty($useridfrom)) {
2252 // We use get_user here because the from user can be the noreply or support user.
2253 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2256 // Check if the current user is the sender/receiver or just a privileged user.
2257 if ($useridto != $USER->id and $useridfrom != $USER->id and
2258 // The deleteanymessage cap seems more reasonable here than readallmessages.
2259 !has_capability('moodle/site:deleteanymessage', $context)) {
2260 throw new moodle_exception('accessdenied', 'admin');
2263 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto);
2265 return true;
2269 * Mark all notifications as read return description.
2271 * @return external_single_structure
2272 * @since 3.2
2274 public static function mark_all_notifications_as_read_returns() {
2275 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2279 * Get unread conversations count parameters description.
2281 * @return external_function_parameters
2282 * @since 3.2
2284 public static function get_unread_conversations_count_parameters() {
2285 return new external_function_parameters(
2286 array(
2287 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2293 * Get unread messages count function.
2295 * @since 3.2
2296 * @throws invalid_parameter_exception
2297 * @throws moodle_exception
2298 * @param int $useridto the user id who received the message
2299 * @return external_description
2301 public static function get_unread_conversations_count($useridto) {
2302 global $USER, $CFG;
2304 // Check if messaging is enabled.
2305 if (empty($CFG->messaging)) {
2306 throw new moodle_exception('disabled', 'message');
2309 $params = self::validate_parameters(
2310 self::get_unread_conversations_count_parameters(),
2311 array('useridto' => $useridto)
2314 $context = context_system::instance();
2315 self::validate_context($context);
2317 $useridto = $params['useridto'];
2319 if (!empty($useridto)) {
2320 if (core_user::is_real_user($useridto)) {
2321 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2322 } else {
2323 throw new moodle_exception('invaliduser');
2325 } else {
2326 $useridto = $USER->id;
2329 // Check if the current user is the receiver or just a privileged user.
2330 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2331 throw new moodle_exception('accessdenied', 'admin');
2334 return \core_message\api::count_unread_conversations($userto);
2338 * Get unread conversations count return description.
2340 * @return external_single_structure
2341 * @since 3.2
2343 public static function get_unread_conversations_count_returns() {
2344 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2348 * Get blocked users parameters description.
2350 * @return external_function_parameters
2351 * @since 2.9
2353 public static function get_blocked_users_parameters() {
2354 return new external_function_parameters(
2355 array(
2356 'userid' => new external_value(PARAM_INT,
2357 'the user whose blocked users we want to retrieve',
2358 VALUE_REQUIRED),
2364 * Retrieve a list of users blocked
2366 * @param int $userid the user whose blocked users we want to retrieve
2367 * @return external_description
2368 * @since 2.9
2370 public static function get_blocked_users($userid) {
2371 global $CFG, $USER, $PAGE;
2373 // Warnings array, it can be empty at the end but is mandatory.
2374 $warnings = array();
2376 // Validate params.
2377 $params = array(
2378 'userid' => $userid
2380 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2381 $userid = $params['userid'];
2383 // Validate context.
2384 $context = context_system::instance();
2385 self::validate_context($context);
2387 // Check if private messaging between users is allowed.
2388 if (empty($CFG->messaging)) {
2389 throw new moodle_exception('disabled', 'message');
2392 $user = core_user::get_user($userid, '*', MUST_EXIST);
2393 core_user::require_active_user($user);
2395 // Check if we have permissions for retrieve the information.
2396 $capability = 'moodle/site:manageallmessaging';
2397 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2398 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2401 // Now, we can get safely all the blocked users.
2402 $users = \core_message\api::get_blocked_users($user->id);
2404 $blockedusers = array();
2405 foreach ($users as $user) {
2406 $newuser = array(
2407 'id' => $user->id,
2408 'fullname' => fullname($user),
2411 $userpicture = new user_picture($user);
2412 $userpicture->size = 1; // Size f1.
2413 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2415 $blockedusers[] = $newuser;
2418 $results = array(
2419 'users' => $blockedusers,
2420 'warnings' => $warnings
2422 return $results;
2426 * Get blocked users return description.
2428 * @return external_single_structure
2429 * @since 2.9
2431 public static function get_blocked_users_returns() {
2432 return new external_single_structure(
2433 array(
2434 'users' => new external_multiple_structure(
2435 new external_single_structure(
2436 array(
2437 'id' => new external_value(PARAM_INT, 'User ID'),
2438 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2439 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2442 'List of blocked users'
2444 'warnings' => new external_warnings()
2450 * Returns description of method parameters
2452 * @return external_function_parameters
2453 * @since 2.9
2455 public static function mark_message_read_parameters() {
2456 return new external_function_parameters(
2457 array(
2458 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2459 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2460 VALUE_DEFAULT, 0)
2466 * Mark a single message as read, trigger message_viewed event
2468 * @param int $messageid id of the message (in the message table)
2469 * @param int $timeread timestamp for when the message should be marked read
2470 * @return external_description
2471 * @throws invalid_parameter_exception
2472 * @throws moodle_exception
2473 * @since 2.9
2475 public static function mark_message_read($messageid, $timeread) {
2476 global $CFG, $DB, $USER;
2478 // Check if private messaging between users is allowed.
2479 if (empty($CFG->messaging)) {
2480 throw new moodle_exception('disabled', 'message');
2483 // Warnings array, it can be empty at the end but is mandatory.
2484 $warnings = array();
2486 // Validate params.
2487 $params = array(
2488 'messageid' => $messageid,
2489 'timeread' => $timeread
2491 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2493 if (empty($params['timeread'])) {
2494 $timeread = time();
2495 } else {
2496 $timeread = $params['timeread'];
2499 // Validate context.
2500 $context = context_system::instance();
2501 self::validate_context($context);
2503 $sql = "SELECT m.*, mcm.userid as useridto
2504 FROM {messages} m
2505 INNER JOIN {message_conversations} mc
2506 ON m.conversationid = mc.id
2507 INNER JOIN {message_conversation_members} mcm
2508 ON mcm.conversationid = mc.id
2509 LEFT JOIN {message_user_actions} mua
2510 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2511 WHERE mua.id is NULL
2512 AND mcm.userid != m.useridfrom
2513 AND m.id = ?";
2514 $messageparams = [];
2515 $messageparams[] = $USER->id;
2516 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2517 $messageparams[] = $params['messageid'];
2518 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2520 if ($message->useridto != $USER->id) {
2521 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2524 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2526 $results = array(
2527 'messageid' => $message->id,
2528 'warnings' => $warnings
2530 return $results;
2534 * Returns description of method result value
2536 * @return external_description
2537 * @since 2.9
2539 public static function mark_message_read_returns() {
2540 return new external_single_structure(
2541 array(
2542 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2543 'warnings' => new external_warnings()
2549 * Returns description of method parameters
2551 * @return external_function_parameters
2553 public static function mark_notification_read_parameters() {
2554 return new external_function_parameters(
2555 array(
2556 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2557 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2558 VALUE_DEFAULT, 0)
2564 * Mark a single notification as read.
2566 * This will trigger a 'notification_viewed' event.
2568 * @param int $notificationid id of the notification
2569 * @param int $timeread timestamp for when the notification should be marked read
2570 * @return external_description
2571 * @throws invalid_parameter_exception
2572 * @throws moodle_exception
2574 public static function mark_notification_read($notificationid, $timeread) {
2575 global $CFG, $DB, $USER;
2577 // Warnings array, it can be empty at the end but is mandatory.
2578 $warnings = array();
2580 // Validate params.
2581 $params = array(
2582 'notificationid' => $notificationid,
2583 'timeread' => $timeread
2585 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2587 if (empty($params['timeread'])) {
2588 $timeread = time();
2589 } else {
2590 $timeread = $params['timeread'];
2593 // Validate context.
2594 $context = context_system::instance();
2595 self::validate_context($context);
2597 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2599 if ($notification->useridto != $USER->id) {
2600 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2601 'notification as read');
2604 \core_message\api::mark_notification_as_read($notification, $timeread);
2606 $results = array(
2607 'notificationid' => $notification->id,
2608 'warnings' => $warnings
2611 return $results;
2615 * Returns description of method result value
2617 * @return external_description
2619 public static function mark_notification_read_returns() {
2620 return new external_single_structure(
2621 array(
2622 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2623 'warnings' => new external_warnings()
2629 * Mark all conversation messages as read parameters description.
2631 * @return external_function_parameters
2632 * @since 3.6
2634 public static function mark_all_conversation_messages_as_read_parameters() {
2635 return new external_function_parameters(
2636 array(
2637 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2638 'conversationid' =>
2639 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2645 * Mark all conversation messages as read function.
2647 * @param int $userid The user id of who we want to delete the conversation for
2648 * @param int $conversationid The id of the conversations
2649 * @since 3.6
2651 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2652 global $CFG;
2654 // Check if messaging is enabled.
2655 if (empty($CFG->messaging)) {
2656 throw new moodle_exception('disabled', 'message');
2659 $params = array(
2660 'userid' => $userid,
2661 'conversationid' => $conversationid,
2663 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2665 $context = context_system::instance();
2666 self::validate_context($context);
2668 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2669 core_user::require_active_user($user);
2671 if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
2672 \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
2673 } else {
2674 throw new moodle_exception('accessdenied', 'admin');
2679 * Mark all conversation messages as read return description.
2681 * @return external_warnings
2682 * @since 3.6
2684 public static function mark_all_conversation_messages_as_read_returns() {
2685 return null;
2689 * Returns description of method parameters.
2691 * @return external_function_parameters
2692 * @since 3.6
2694 public static function delete_conversations_by_id_parameters() {
2695 return new external_function_parameters(
2696 array(
2697 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2698 'conversationids' => new external_multiple_structure(
2699 new external_value(PARAM_INT, 'The id of the conversation'),
2700 'List of conversation IDs'
2707 * Deletes a conversation.
2709 * @param int $userid The user id of who we want to delete the conversation for
2710 * @param int[] $conversationids The ids of the conversations
2711 * @return array
2712 * @throws moodle_exception
2713 * @since 3.6
2715 public static function delete_conversations_by_id($userid, array $conversationids) {
2716 global $CFG;
2718 // Check if private messaging between users is allowed.
2719 if (empty($CFG->messaging)) {
2720 throw new moodle_exception('disabled', 'message');
2723 // Validate params.
2724 $params = [
2725 'userid' => $userid,
2726 'conversationids' => $conversationids,
2728 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
2730 // Validate context.
2731 $context = context_system::instance();
2732 self::validate_context($context);
2734 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2735 core_user::require_active_user($user);
2737 foreach ($params['conversationids'] as $conversationid) {
2738 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2739 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2740 } else {
2741 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2745 return [];
2749 * Returns description of method result value.
2751 * @return external_description
2752 * @since 3.6
2754 public static function delete_conversations_by_id_returns() {
2755 return new external_warnings();
2759 * Returns description of method parameters
2761 * @return external_function_parameters
2762 * @since 3.1
2764 public static function delete_message_parameters() {
2765 return new external_function_parameters(
2766 array(
2767 'messageid' => new external_value(PARAM_INT, 'The message id'),
2768 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2769 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2775 * Deletes a message
2777 * @param int $messageid the message id
2778 * @param int $userid the user id of who we want to delete the message for
2779 * @param bool $read if is a message read (default to true)
2780 * @return external_description
2781 * @throws moodle_exception
2782 * @since 3.1
2784 public static function delete_message($messageid, $userid, $read = true) {
2785 global $CFG;
2787 // Check if private messaging between users is allowed.
2788 if (empty($CFG->messaging)) {
2789 throw new moodle_exception('disabled', 'message');
2792 // Warnings array, it can be empty at the end but is mandatory.
2793 $warnings = array();
2795 // Validate params.
2796 $params = array(
2797 'messageid' => $messageid,
2798 'userid' => $userid,
2799 'read' => $read
2801 $params = self::validate_parameters(self::delete_message_parameters(), $params);
2803 // Validate context.
2804 $context = context_system::instance();
2805 self::validate_context($context);
2807 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2808 core_user::require_active_user($user);
2810 if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
2811 $status = \core_message\api::delete_message($user->id, $params['messageid']);
2812 } else {
2813 throw new moodle_exception('You do not have permission to delete this message');
2816 $results = array(
2817 'status' => $status,
2818 'warnings' => $warnings
2820 return $results;
2824 * Returns description of method result value
2826 * @return external_description
2827 * @since 3.1
2829 public static function delete_message_returns() {
2830 return new external_single_structure(
2831 array(
2832 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2833 'warnings' => new external_warnings()
2839 * Returns description of method parameters
2841 * @return external_function_parameters
2842 * @since 3.2
2844 public static function message_processor_config_form_parameters() {
2845 return new external_function_parameters(
2846 array(
2847 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2848 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
2849 'formvalues' => new external_multiple_structure(
2850 new external_single_structure(
2851 array(
2852 'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2853 'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2856 'Config form values',
2857 VALUE_REQUIRED
2864 * Processes a message processor config form.
2866 * @param int $userid the user id
2867 * @param string $name the name of the processor
2868 * @param array $formvalues the form values
2869 * @return external_description
2870 * @throws moodle_exception
2871 * @since 3.2
2873 public static function message_processor_config_form($userid, $name, $formvalues) {
2874 global $USER, $CFG;
2876 $params = self::validate_parameters(
2877 self::message_processor_config_form_parameters(),
2878 array(
2879 'userid' => $userid,
2880 'name' => $name,
2881 'formvalues' => $formvalues,
2885 $user = self::validate_preferences_permissions($params['userid']);
2887 $processor = get_message_processor($params['name']);
2888 $preferences = [];
2889 $form = new stdClass();
2891 foreach ($params['formvalues'] as $formvalue) {
2892 // Curly braces to ensure interpretation is consistent between
2893 // php 5 and php 7.
2894 $form->{$formvalue['name']} = $formvalue['value'];
2897 $processor->process_form($form, $preferences);
2899 if (!empty($preferences)) {
2900 set_user_preferences($preferences, $params['userid']);
2905 * Returns description of method result value
2907 * @return external_description
2908 * @since 3.2
2910 public static function message_processor_config_form_returns() {
2911 return null;
2915 * Returns description of method parameters
2917 * @return external_function_parameters
2918 * @since 3.2
2920 public static function get_message_processor_parameters() {
2921 return new external_function_parameters(
2922 array(
2923 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2924 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
2930 * Get a message processor.
2932 * @param int $userid
2933 * @param string $name the name of the processor
2934 * @return external_description
2935 * @throws moodle_exception
2936 * @since 3.2
2938 public static function get_message_processor($userid, $name) {
2939 global $USER, $PAGE, $CFG;
2941 // Check if messaging is enabled.
2942 if (empty($CFG->messaging)) {
2943 throw new moodle_exception('disabled', 'message');
2946 $params = self::validate_parameters(
2947 self::get_message_processor_parameters(),
2948 array(
2949 'userid' => $userid,
2950 'name' => $name,
2954 if (empty($params['userid'])) {
2955 $params['userid'] = $USER->id;
2958 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2959 core_user::require_active_user($user);
2960 self::validate_context(context_user::instance($params['userid']));
2962 $processor = get_message_processor($params['name']);
2964 $processoroutput = new \core_message\output\processor($processor, $user);
2965 $renderer = $PAGE->get_renderer('core_message');
2967 return $processoroutput->export_for_template($renderer);
2971 * Returns description of method result value
2973 * @return external_description
2974 * @since 3.2
2976 public static function get_message_processor_returns() {
2977 return new external_function_parameters(
2978 array(
2979 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2980 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2986 * Check that the user has enough permission to retrieve message or notifications preferences.
2988 * @param int $userid the user id requesting the preferences
2989 * @return stdClass full user object
2990 * @throws moodle_exception
2991 * @since Moodle 3.2
2993 protected static function validate_preferences_permissions($userid) {
2994 global $USER;
2996 if (empty($userid)) {
2997 $user = $USER;
2998 } else {
2999 $user = core_user::get_user($userid, '*', MUST_EXIST);
3000 core_user::require_active_user($user);
3003 $systemcontext = context_system::instance();
3004 self::validate_context($systemcontext);
3006 // Check access control.
3007 if ($user->id == $USER->id) {
3008 // Editing own message profile.
3009 require_capability('moodle/user:editownmessageprofile', $systemcontext);
3010 } else {
3011 // Teachers, parents, etc.
3012 $personalcontext = context_user::instance($user->id);
3013 require_capability('moodle/user:editmessageprofile', $personalcontext);
3015 return $user;
3019 * Returns a notification or message preference structure.
3021 * @return external_single_structure the structure
3022 * @since Moodle 3.2
3023 * @todo Remove loggedin and loggedoff from processors structure on MDL-73284.
3025 protected static function get_preferences_structure() {
3026 return new external_single_structure(
3027 array(
3028 'userid' => new external_value(PARAM_INT, 'User id'),
3029 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3030 'processors' => new external_multiple_structure(
3031 new external_single_structure(
3032 array(
3033 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3034 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3035 'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3036 'contextid' => new external_value(PARAM_INT, 'Context id'),
3037 'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3040 'Config form values'
3042 'components' => new external_multiple_structure(
3043 new external_single_structure(
3044 array(
3045 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3046 'notifications' => new external_multiple_structure(
3047 new external_single_structure(
3048 array(
3049 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3050 'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3051 'processors' => new external_multiple_structure(
3052 new external_single_structure(
3053 array(
3054 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3055 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3056 'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3057 'lockedmessage' => new external_value(PARAM_TEXT,
3058 'Text to display if locked', VALUE_OPTIONAL),
3059 'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3060 'loggedin' => new external_single_structure(
3061 array(
3062 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3063 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3064 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3066 'DEPRECATED ATTRIBUTE -
3067 Kept for backward compatibility, use enabled instead.',
3069 'loggedoff' => new external_single_structure(
3070 array(
3071 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3072 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3073 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3075 'DEPRECATED ATTRIBUTE -
3076 Kept for backward compatibility, use enabled instead.',
3078 'enabled' => new external_value(PARAM_BOOL, 'Is enabled?'),
3081 'Processors values for this notification'
3085 'List of notificaitons for the component'
3089 'Available components'
3096 * Returns description of method parameters
3098 * @return external_function_parameters
3099 * @since 3.2
3101 public static function get_user_notification_preferences_parameters() {
3102 return new external_function_parameters(
3103 array(
3104 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3110 * Get the notification preferences for a given user.
3112 * @param int $userid id of the user, 0 for current user
3113 * @return external_description
3114 * @throws moodle_exception
3115 * @since 3.2
3117 public static function get_user_notification_preferences($userid = 0) {
3118 global $PAGE;
3120 $params = self::validate_parameters(
3121 self::get_user_notification_preferences_parameters(),
3122 array(
3123 'userid' => $userid,
3126 $user = self::validate_preferences_permissions($params['userid']);
3128 $processors = get_message_processors();
3129 $providers = message_get_providers_for_user($user->id);
3130 $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3131 $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3133 $renderer = $PAGE->get_renderer('core_message');
3135 $result = array(
3136 'warnings' => array(),
3137 'preferences' => $notificationlist->export_for_template($renderer)
3139 return $result;
3143 * Returns description of method result value
3145 * @return external_description
3146 * @since 3.2
3148 public static function get_user_notification_preferences_returns() {
3149 return new external_function_parameters(
3150 array(
3151 'preferences' => self::get_preferences_structure(),
3152 'warnings' => new external_warnings(),
3158 * Returns description of method parameters
3160 * @return external_function_parameters
3161 * @since 3.2
3163 public static function get_user_message_preferences_parameters() {
3164 return new external_function_parameters(
3165 array(
3166 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3172 * Get the notification preferences for a given user.
3174 * @param int $userid id of the user, 0 for current user
3175 * @return external_description
3176 * @throws moodle_exception
3177 * @since 3.2
3179 public static function get_user_message_preferences($userid = 0) {
3180 global $CFG, $PAGE;
3182 $params = self::validate_parameters(
3183 self::get_user_message_preferences_parameters(),
3184 array(
3185 'userid' => $userid,
3189 $user = self::validate_preferences_permissions($params['userid']);
3191 // Filter out enabled, available system_configured and user_configured processors only.
3192 $readyprocessors = array_filter(get_message_processors(), function($processor) {
3193 return $processor->enabled &&
3194 $processor->configured &&
3195 $processor->object->is_user_configured() &&
3196 // Filter out processors that don't have and message preferences to configure.
3197 $processor->object->has_message_preferences();
3200 $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
3201 return $provider->component === 'moodle';
3203 $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
3204 $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
3205 $providers, $preferences, $user);
3207 $renderer = $PAGE->get_renderer('core_message');
3209 $entertosend = get_user_preferences('message_entertosend', $CFG->messagingdefaultpressenter, $user);
3211 $result = array(
3212 'warnings' => array(),
3213 'preferences' => $notificationlistoutput->export_for_template($renderer),
3214 'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id),
3215 'entertosend' => $entertosend
3217 return $result;
3221 * Returns description of method result value
3223 * @return external_description
3224 * @since 3.2
3226 public static function get_user_message_preferences_returns() {
3227 return new external_function_parameters(
3228 array(
3229 'preferences' => self::get_preferences_structure(),
3230 'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'),
3231 'entertosend' => new external_value(PARAM_BOOL, 'User preference for using enter to send messages'),
3232 'warnings' => new external_warnings(),
3238 * Returns description of method parameters for the favourite_conversations() method.
3240 * @return external_function_parameters
3242 public static function set_favourite_conversations_parameters() {
3243 return new external_function_parameters(
3244 array(
3245 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3246 'conversations' => new external_multiple_structure(
3247 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3254 * Favourite a conversation, or list of conversations for a user.
3256 * @param int $userid the id of the user, or 0 for the current user.
3257 * @param array $conversationids the list of conversations ids to favourite.
3258 * @return array
3259 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3261 public static function set_favourite_conversations(int $userid, array $conversationids) {
3262 global $CFG, $USER;
3264 // All the business logic checks that really shouldn't be in here.
3265 if (empty($CFG->messaging)) {
3266 throw new moodle_exception('disabled', 'message');
3268 $params = [
3269 'userid' => $userid,
3270 'conversations' => $conversationids
3272 $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params);
3273 $systemcontext = context_system::instance();
3274 self::validate_context($systemcontext);
3276 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3277 throw new moodle_exception('You do not have permission to perform this action.');
3280 foreach ($params['conversations'] as $conversationid) {
3281 \core_message\api::set_favourite_conversation($conversationid, $params['userid']);
3284 return [];
3288 * Return a description of the returns for the create_user_favourite_conversations() method.
3290 * @return external_description
3292 public static function set_favourite_conversations_returns() {
3293 return new external_warnings();
3297 * Returns description of method parameters for unfavourite_conversations() method.
3299 * @return external_function_parameters
3301 public static function unset_favourite_conversations_parameters() {
3302 return new external_function_parameters(
3303 array(
3304 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3305 'conversations' => new external_multiple_structure(
3306 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3313 * Unfavourite a conversation, or list of conversations for a user.
3315 * @param int $userid the id of the user, or 0 for the current user.
3316 * @param array $conversationids the list of conversations ids unset as favourites.
3317 * @return array
3318 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3320 public static function unset_favourite_conversations(int $userid, array $conversationids) {
3321 global $CFG, $USER;
3323 // All the business logic checks that really shouldn't be in here.
3324 if (empty($CFG->messaging)) {
3325 throw new moodle_exception('disabled', 'message');
3327 $params = [
3328 'userid' => $userid,
3329 'conversations' => $conversationids
3331 $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params);
3332 $systemcontext = context_system::instance();
3333 self::validate_context($systemcontext);
3335 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3336 throw new moodle_exception('You do not have permission to perform this action.');
3339 foreach ($params['conversations'] as $conversationid) {
3340 \core_message\api::unset_favourite_conversation($conversationid, $params['userid']);
3343 return [];
3347 * Unset favourite conversations return description.
3349 * @return external_description
3351 public static function unset_favourite_conversations_returns() {
3352 return new external_warnings();
3356 * Returns description of method parameters for get_member_info() method.
3358 * @return external_function_parameters
3360 public static function get_member_info_parameters() {
3361 return new external_function_parameters(
3362 array(
3363 'referenceuserid' => new external_value(PARAM_INT, 'id of the user'),
3364 'userids' => new external_multiple_structure(
3365 new external_value(PARAM_INT, 'id of members to get')
3367 'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false),
3368 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'include privacy info in response', VALUE_DEFAULT, false)
3374 * Returns conversation member info for the supplied users, relative to the supplied referenceuserid.
3376 * This is the basic structure used when returning members, and includes information about the relationship between each member
3377 * and the referenceuser, such as a whether the referenceuser has marked the member as a contact, or has blocked them.
3379 * @param int $referenceuserid the id of the user which check contact and blocked status.
3380 * @param array $userids
3381 * @return array the array of objects containing member info.
3382 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3384 public static function get_member_info(
3385 int $referenceuserid,
3386 array $userids,
3387 bool $includecontactrequests = false,
3388 bool $includeprivacyinfo = false
3390 global $CFG, $USER;
3392 // All the business logic checks that really shouldn't be in here.
3393 if (empty($CFG->messaging)) {
3394 throw new moodle_exception('disabled', 'message');
3396 $params = [
3397 'referenceuserid' => $referenceuserid,
3398 'userids' => $userids,
3399 'includecontactrequests' => $includecontactrequests,
3400 'includeprivacyinfo' => $includeprivacyinfo
3402 $params = self::validate_parameters(self::get_member_info_parameters(), $params);
3403 $systemcontext = context_system::instance();
3404 self::validate_context($systemcontext);
3406 if (($USER->id != $referenceuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3407 throw new moodle_exception('You do not have permission to perform this action.');
3410 return \core_message\helper::get_member_info(
3411 $params['referenceuserid'],
3412 $params['userids'],
3413 $params['includecontactrequests'],
3414 $params['includeprivacyinfo']
3419 * Get member info return description.
3421 * @return external_description
3423 public static function get_member_info_returns() {
3424 return new external_multiple_structure(
3425 self::get_conversation_member_structure()
3430 * Returns description of method parameters for get_conversation_counts() method.
3432 * @return external_function_parameters
3434 public static function get_conversation_counts_parameters() {
3435 return new external_function_parameters(
3437 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3443 * Returns an array of conversation counts for the various types of conversations, including favourites.
3445 * Return format:
3447 * 'favourites' => 0,
3448 * 'types' => [
3449 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3450 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3454 * @param int $userid the id of the user whose counts we are fetching.
3455 * @return array the array of conversation counts, indexed by type.
3456 * @throws moodle_exception if the current user cannot perform this action.
3458 public static function get_conversation_counts(int $userid) {
3459 global $CFG, $USER;
3461 // All the business logic checks that really shouldn't be in here.
3462 if (empty($CFG->messaging)) {
3463 throw new moodle_exception('disabled', 'message');
3466 if (empty($userid)) {
3467 $userid = $USER->id;
3470 $params = ['userid' => $userid];
3471 $params = self::validate_parameters(self::get_conversation_counts_parameters(), $params);
3473 $systemcontext = context_system::instance();
3474 self::validate_context($systemcontext);
3476 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3477 throw new moodle_exception('You do not have permission to perform this action.');
3480 return \core_message\api::get_conversation_counts($params['userid']);
3484 * Get conversation counts return description.
3486 * @return external_description
3488 public static function get_conversation_counts_returns() {
3489 return new external_single_structure(
3491 'favourites' => new external_value(PARAM_INT, 'Total number of favourite conversations'),
3492 'types' => new external_single_structure(
3494 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3495 'Total number of individual conversations'),
3496 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3497 'Total number of group conversations'),
3498 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3499 'Total number of self conversations'),
3507 * Returns description of method parameters for get_unread_conversation_counts() method.
3509 * @return external_function_parameters
3511 public static function get_unread_conversation_counts_parameters() {
3512 return new external_function_parameters(
3514 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3520 * Returns an array of unread conversation counts for the various types of conversations, including favourites.
3522 * Return format:
3524 * 'favourites' => 0,
3525 * 'types' => [
3526 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3527 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3531 * @param int $userid the id of the user whose counts we are fetching.
3532 * @return array the array of unread conversation counts, indexed by type.
3533 * @throws moodle_exception if the current user cannot perform this action.
3535 public static function get_unread_conversation_counts(int $userid) {
3536 global $CFG, $USER;
3538 // All the business logic checks that really shouldn't be in here.
3539 if (empty($CFG->messaging)) {
3540 throw new moodle_exception('disabled', 'message');
3543 if (empty($userid)) {
3544 $userid = $USER->id;
3547 $params = ['userid' => $userid];
3548 $params = self::validate_parameters(self::get_unread_conversation_counts_parameters(), $params);
3550 $systemcontext = context_system::instance();
3551 self::validate_context($systemcontext);
3553 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3554 throw new moodle_exception('You do not have permission to perform this action.');
3557 return \core_message\api::get_unread_conversation_counts($params['userid']);
3561 * Get unread conversation counts return description.
3563 * @return external_description
3565 public static function get_unread_conversation_counts_returns() {
3566 return new external_single_structure(
3568 'favourites' => new external_value(PARAM_INT, 'Total number of unread favourite conversations'),
3569 'types' => new external_single_structure(
3571 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3572 'Total number of unread individual conversations'),
3573 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3574 'Total number of unread group conversations'),
3575 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3576 'Total number of unread self conversations'),
3584 * Returns description of method parameters
3586 * @return external_function_parameters
3587 * @since 3.7
3589 public static function delete_message_for_all_users_parameters() {
3590 return new external_function_parameters(
3591 array(
3592 'messageid' => new external_value(PARAM_INT, 'The message id'),
3593 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users')
3598 * Deletes a message for all users
3600 * @param int $messageid the message id
3601 * @param int $userid the user id of who we want to delete the message for all users, is no longer used.
3602 * @return external_description
3603 * @throws moodle_exception
3604 * @since 3.7
3606 public static function delete_message_for_all_users(int $messageid, int $userid) {
3607 global $CFG, $USER;
3609 // Check if private messaging between users is allowed.
3610 if (empty($CFG->messaging)) {
3611 throw new moodle_exception('disabled', 'message');
3614 // Validate params.
3615 $params = array(
3616 'messageid' => $messageid,
3617 'userid' => $userid
3619 $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params);
3621 // Validate context.
3622 $context = context_system::instance();
3623 self::validate_context($context);
3625 core_user::require_active_user($USER);
3627 // Checks if a user can delete a message for all users.
3628 if (core_message\api::can_delete_message_for_all_users($USER->id, $params['messageid'])) {
3629 \core_message\api::delete_message_for_all_users($params['messageid']);
3630 } else {
3631 throw new moodle_exception('You do not have permission to delete this message for everyone.');
3634 return [];
3637 * Returns description of method result value
3639 * @return external_description
3640 * @since 3.7
3642 public static function delete_message_for_all_users_returns() {
3643 return new external_warnings();