Merge branch 'MDL-79015-402' of https://github.com/andelacruz/moodle into MOODLE_402_...
[moodle.git] / message / externallib.php
bloba7a599d82f65eca05c9551d91dc48b6e74e86116
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/>.
17 /**
18 * External message API
20 * @package core_message
21 * @category external
22 * @copyright 2011 Jerome Mouneyrac
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 use core_external\external_api;
27 use core_external\external_format_value;
28 use core_external\external_function_parameters;
29 use core_external\external_multiple_structure;
30 use core_external\external_single_structure;
31 use core_external\external_value;
32 use core_external\external_warnings;
33 use core_external\util;
35 defined('MOODLE_INTERNAL') || die();
37 require_once($CFG->dirroot . "/message/lib.php");
39 /**
40 * Message external functions
42 * @package core_message
43 * @category external
44 * @copyright 2011 Jerome Mouneyrac
45 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46 * @since Moodle 2.2
48 class core_message_external extends external_api {
49 /**
50 * Returns description of method parameters
52 * @return external_function_parameters
53 * @since Moodle 3.6
55 public static function send_messages_to_conversation_parameters() {
56 return new external_function_parameters(
57 array(
58 'conversationid' => new external_value(PARAM_INT, 'id of the conversation'),
59 'messages' => new external_multiple_structure(
60 new external_single_structure(
61 array(
62 'text' => new external_value(PARAM_RAW, 'the text of the message'),
63 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
71 /**
72 * Send messages from the current USER to a conversation.
74 * This conversation may be any type of conversation, individual or group.
76 * @param int $conversationid the id of the conversation to which the messages will be sent.
77 * @param array $messages An array of message to send.
78 * @return array the array of messages which were sent (created).
79 * @since Moodle 3.6
81 public static function send_messages_to_conversation(int $conversationid, array $messages = []) {
82 global $CFG, $USER;
84 // Check if messaging is enabled.
85 if (empty($CFG->messaging)) {
86 throw new moodle_exception('disabled', 'message');
89 // Ensure the current user is allowed to run this function.
90 $context = context_system::instance();
91 self::validate_context($context);
93 $params = self::validate_parameters(self::send_messages_to_conversation_parameters(), [
94 'conversationid' => $conversationid,
95 'messages' => $messages
96 ]);
98 // Validate messages content before posting them.
99 foreach ($params['messages'] as $message) {
100 // Check message length.
101 if (strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
102 throw new moodle_exception('errormessagetoolong', 'message');
106 $messages = [];
107 foreach ($params['messages'] as $message) {
108 $createdmessage = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
109 $message['textformat']);
110 $createdmessage->text = message_format_message_text((object) [
111 'smallmessage' => $createdmessage->text,
112 'fullmessageformat' => util::validate_format($message['textformat']),
113 'fullmessagetrust' => $createdmessage->fullmessagetrust
115 $messages[] = $createdmessage;
118 return $messages;
122 * Returns description of method result value.
124 * @return \core_external\external_description
125 * @since Moodle 3.6
127 public static function send_messages_to_conversation_returns() {
128 return new external_multiple_structure(
129 self::get_conversation_message_structure()
135 * Returns description of method parameters
137 * @return external_function_parameters
138 * @since Moodle 2.2
140 public static function send_instant_messages_parameters() {
141 return new external_function_parameters(
142 array(
143 'messages' => new external_multiple_structure(
144 new external_single_structure(
145 array(
146 'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
147 'text' => new external_value(PARAM_RAW, 'the text of the message'),
148 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
149 '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),
158 * Send private messages from the current USER to other users
160 * @param array $messages An array of message to send.
161 * @return array
162 * @since Moodle 2.2
164 public static function send_instant_messages($messages = array()) {
165 global $CFG, $USER, $DB;
167 // Check if messaging is enabled.
168 if (empty($CFG->messaging)) {
169 throw new moodle_exception('disabled', 'message');
172 // Ensure the current user is allowed to run this function
173 $context = context_system::instance();
174 self::validate_context($context);
175 require_capability('moodle/site:sendmessage', $context);
177 // Ensure the current user is allowed to delete message for everyone.
178 $candeletemessagesforallusers = has_capability('moodle/site:deleteanymessage', $context);
180 $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
182 //retrieve all tousers of the messages
183 $receivers = array();
184 foreach($params['messages'] as $message) {
185 $receivers[] = $message['touserid'];
187 list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
188 $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
190 $resultmessages = array();
191 $messageids = array();
192 foreach ($params['messages'] as $message) {
193 $resultmsg = array(); //the infos about the success of the operation
195 // We are going to do some checking.
196 // Code should match /messages/index.php checks.
197 $success = true;
199 // Check the user exists.
200 if (empty($tousers[$message['touserid']])) {
201 $success = false;
202 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
205 // Check message length.
206 if ($success && strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
207 $success = false;
208 $errormessage = get_string('errormessagetoolong', 'message');
211 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
212 // Check if the recipient can be messaged by the sender.
213 if ($success && !\core_message\api::can_send_message($tousers[$message['touserid']]->id, $USER->id)) {
214 $success = false;
215 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
218 // Now we can send the message (at least try).
219 if ($success) {
220 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
221 $success = message_post_message($USER, $tousers[$message['touserid']],
222 $message['text'], util::validate_format($message['textformat']));
225 // Build the resultmsg.
226 if (isset($message['clientmsgid'])) {
227 $resultmsg['clientmsgid'] = $message['clientmsgid'];
229 if ($success) {
230 $resultmsg['msgid'] = $success;
231 $resultmsg['timecreated'] = time();
232 $resultmsg['candeletemessagesforallusers'] = $candeletemessagesforallusers;
233 $messageids[] = $success;
234 } else {
235 // WARNINGS: for backward compatibility we return this errormessage.
236 // We should have thrown exceptions as these errors prevent results to be returned.
237 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
238 $resultmsg['msgid'] = -1;
239 if (!isset($errormessage)) { // Nobody has set a message error or thrown an exception, let's set it.
240 $errormessage = get_string('messageundeliveredbynotificationsettings', 'error');
242 $resultmsg['errormessage'] = $errormessage;
245 $resultmessages[] = $resultmsg;
248 if (!empty($messageids)) {
249 $messagerecords = $DB->get_records_list(
250 'messages',
251 'id',
252 $messageids,
254 'id, conversationid, smallmessage, fullmessageformat, fullmessagetrust');
255 $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) {
256 $id = $resultmessage['msgid'];
257 $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null;
258 $resultmessage['useridfrom'] = $USER->id;
259 $resultmessage['text'] = message_format_message_text((object) [
260 'smallmessage' => $messagerecords[$id]->smallmessage,
261 'fullmessageformat' => util::validate_format($messagerecords[$id]->fullmessageformat),
262 'fullmessagetrust' => $messagerecords[$id]->fullmessagetrust
264 return $resultmessage;
265 }, $resultmessages);
268 return $resultmessages;
272 * Returns description of method result value
274 * @return \core_external\external_description
275 * @since Moodle 2.2
277 public static function send_instant_messages_returns() {
278 return new external_multiple_structure(
279 new external_single_structure(
280 array(
281 'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds: id of the created message if it succeeded, -1 when failed'),
282 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
283 'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL),
284 'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL),
285 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
286 'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
287 'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
288 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
289 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
296 * Delete contacts parameters description.
298 * @return external_function_parameters
299 * @since Moodle 2.5
301 public static function delete_contacts_parameters() {
302 return new external_function_parameters(
303 array(
304 'userids' => new external_multiple_structure(
305 new external_value(PARAM_INT, 'User ID'),
306 'List of user IDs'
308 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
309 current user', VALUE_DEFAULT, 0)
315 * Delete contacts.
317 * @param array $userids array of user IDs.
318 * @param int $userid The id of the user we are deleting the contacts for
319 * @return null
320 * @since Moodle 2.5
322 public static function delete_contacts($userids, $userid = 0) {
323 global $CFG, $USER;
325 // Check if messaging is enabled.
326 if (empty($CFG->messaging)) {
327 throw new moodle_exception('disabled', 'message');
330 if (empty($userid)) {
331 $userid = $USER->id;
334 // Validate context.
335 $context = context_system::instance();
336 self::validate_context($context);
338 $params = array('userids' => $userids, 'userid' => $userid);
339 $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
341 $capability = 'moodle/site:manageallmessaging';
342 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
343 throw new required_capability_exception($context, $capability, 'nopermissions', '');
346 foreach ($params['userids'] as $id) {
347 \core_message\api::remove_contact($params['userid'], $id);
350 return null;
354 * Delete contacts return description.
356 * @return \core_external\external_description
357 * @since Moodle 2.5
359 public static function delete_contacts_returns() {
360 return null;
364 * Mute conversations parameters description.
366 * @return external_function_parameters
368 public static function mute_conversations_parameters() {
369 return new external_function_parameters(
371 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
372 'conversationids' => new external_multiple_structure(
373 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
380 * Mutes conversations.
382 * @param int $userid The id of the user who is blocking
383 * @param array $conversationids The list of conversations being muted
384 * @return \core_external\external_description
386 public static function mute_conversations(int $userid, array $conversationids) {
387 global $CFG, $USER;
389 // Check if messaging is enabled.
390 if (empty($CFG->messaging)) {
391 throw new moodle_exception('disabled', 'message');
394 // Validate context.
395 $context = context_system::instance();
396 self::validate_context($context);
398 $params = ['userid' => $userid, 'conversationids' => $conversationids];
399 $params = self::validate_parameters(self::mute_conversations_parameters(), $params);
401 $capability = 'moodle/site:manageallmessaging';
402 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
403 throw new required_capability_exception($context, $capability, 'nopermissions', '');
406 foreach ($params['conversationids'] as $conversationid) {
407 if (!\core_message\api::is_conversation_muted($params['userid'], $conversationid)) {
408 \core_message\api::mute_conversation($params['userid'], $conversationid);
412 return [];
416 * Mute conversations return description.
418 * @return \core_external\external_description
420 public static function mute_conversations_returns() {
421 return new external_warnings();
425 * Unmute conversations parameters description.
427 * @return external_function_parameters
429 public static function unmute_conversations_parameters() {
430 return new external_function_parameters(
432 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
433 'conversationids' => new external_multiple_structure(
434 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
441 * Unmute conversations.
443 * @param int $userid The id of the user who is unblocking
444 * @param array $conversationids The list of conversations being muted
446 public static function unmute_conversations(int $userid, array $conversationids) {
447 global $CFG, $USER;
449 // Check if messaging is enabled.
450 if (empty($CFG->messaging)) {
451 throw new moodle_exception('disabled', 'message');
454 // Validate context.
455 $context = context_system::instance();
456 self::validate_context($context);
458 $params = ['userid' => $userid, 'conversationids' => $conversationids];
459 $params = self::validate_parameters(self::unmute_conversations_parameters(), $params);
461 $capability = 'moodle/site:manageallmessaging';
462 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
463 throw new required_capability_exception($context, $capability, 'nopermissions', '');
466 foreach ($params['conversationids'] as $conversationid) {
467 \core_message\api::unmute_conversation($params['userid'], $conversationid);
470 return [];
474 * Unmute conversations return description.
476 * @return \core_external\external_description
478 public static function unmute_conversations_returns() {
479 return new external_warnings();
483 * Block user parameters description.
485 * @return external_function_parameters
487 public static function block_user_parameters() {
488 return new external_function_parameters(
490 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
491 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
497 * Blocks a user.
499 * @param int $userid The id of the user who is blocking
500 * @param int $blockeduserid The id of the user being blocked
501 * @return \core_external\external_description
503 public static function block_user(int $userid, int $blockeduserid) {
504 global $CFG, $USER;
506 // Check if messaging is enabled.
507 if (empty($CFG->messaging)) {
508 throw new moodle_exception('disabled', 'message');
511 // Validate context.
512 $context = context_system::instance();
513 self::validate_context($context);
515 $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
516 $params = self::validate_parameters(self::block_user_parameters(), $params);
518 $capability = 'moodle/site:manageallmessaging';
519 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
520 throw new required_capability_exception($context, $capability, 'nopermissions', '');
523 // If the blocking is going to be useless then don't do it.
524 if (\core_message\api::can_send_message($userid, $blockeduserid, true)) {
525 return [];
528 if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
529 \core_message\api::block_user($params['userid'], $params['blockeduserid']);
532 return [];
536 * Block user return description.
538 * @return \core_external\external_description
540 public static function block_user_returns() {
541 return new external_warnings();
545 * Unblock user parameters description.
547 * @return external_function_parameters
549 public static function unblock_user_parameters() {
550 return new external_function_parameters(
552 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
553 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
559 * Unblock user.
561 * @param int $userid The id of the user who is unblocking
562 * @param int $unblockeduserid The id of the user being unblocked
564 public static function unblock_user(int $userid, int $unblockeduserid) {
565 global $CFG, $USER;
567 // Check if messaging is enabled.
568 if (empty($CFG->messaging)) {
569 throw new moodle_exception('disabled', 'message');
572 // Validate context.
573 $context = context_system::instance();
574 self::validate_context($context);
576 $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
577 $params = self::validate_parameters(self::unblock_user_parameters(), $params);
579 $capability = 'moodle/site:manageallmessaging';
580 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
581 throw new required_capability_exception($context, $capability, 'nopermissions', '');
584 \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
586 return [];
590 * Unblock user return description.
592 * @return \core_external\external_description
594 public static function unblock_user_returns() {
595 return new external_warnings();
599 * Returns contact requests parameters description.
601 * @return external_function_parameters
603 public static function get_contact_requests_parameters() {
604 return new external_function_parameters(
606 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
607 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
608 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
614 * Handles returning the contact requests for a user.
616 * This also includes the user data necessary to display information
617 * about the user.
619 * It will not include blocked users.
621 * @param int $userid The id of the user we want to get the contact requests for
622 * @param int $limitfrom
623 * @param int $limitnum
625 public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
626 global $CFG, $USER;
628 // Check if messaging is enabled.
629 if (empty($CFG->messaging)) {
630 throw new moodle_exception('disabled', 'message');
633 // Validate context.
634 $context = context_system::instance();
635 self::validate_context($context);
637 $params = [
638 'userid' => $userid,
639 'limitfrom' => $limitfrom,
640 'limitnum' => $limitnum
642 $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
644 $capability = 'moodle/site:manageallmessaging';
645 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
646 throw new required_capability_exception($context, $capability, 'nopermissions', '');
649 return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
653 * Returns the contact requests return description.
655 * @return \core_external\external_description
657 public static function get_contact_requests_returns() {
658 return new external_multiple_structure(
659 self::get_conversation_member_structure()
664 * Returns the number of contact requests the user has received parameters description.
666 * @return external_function_parameters
668 public static function get_received_contact_requests_count_parameters() {
669 return new external_function_parameters(
670 array(
671 'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' .
672 'received contact requests for', VALUE_REQUIRED),
678 * Returns the number of contact requests the user has received.
680 * @param int $userid The ID of the user we want to return the number of received contact requests for
681 * @return external_value
683 public static function get_received_contact_requests_count(int $userid) {
684 global $CFG, $USER;
686 // Check if messaging is enabled.
687 if (empty($CFG->messaging)) {
688 throw new moodle_exception('disabled', 'message');
691 // Validate context.
692 $context = context_system::instance();
693 self::validate_context($context);
695 $params = [
696 'userid' => $userid,
698 $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params);
700 $capability = 'moodle/site:manageallmessaging';
701 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
702 throw new required_capability_exception($context, $capability, 'nopermissions', '');
705 return \core_message\api::get_received_contact_requests_count($params['userid']);
709 * Returns the number of contact requests the user has received return description.
711 * @return external_value
713 public static function get_received_contact_requests_count_returns() {
714 return new external_value(PARAM_INT, 'The number of received contact requests');
718 * Returns get conversation members parameters description.
720 * @return external_function_parameters
722 public static function get_conversation_members_parameters() {
723 return new external_function_parameters(
725 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
726 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
727 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
728 VALUE_DEFAULT, false),
729 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?',
730 VALUE_DEFAULT, false),
731 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
732 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
738 * Returns a list of conversation members.
740 * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
741 * @param int $conversationid The id of the conversation
742 * @param bool $includecontactrequests Do we want to include contact requests with this data?
743 * @param bool $includeprivacyinfo Do we want to include privacy info?
744 * @param int $limitfrom
745 * @param int $limitnum
746 * @return array
748 public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
749 bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) {
750 global $CFG, $USER;
752 // Check if messaging is enabled.
753 if (empty($CFG->messaging)) {
754 throw new moodle_exception('disabled', 'message');
757 // Validate context.
758 $context = context_system::instance();
759 self::validate_context($context);
761 $params = [
762 'userid' => $userid,
763 'conversationid' => $conversationid,
764 'includecontactrequests' => $includecontactrequests,
765 'includeprivacyinfo' => $includeprivacyinfo,
766 'limitfrom' => $limitfrom,
767 'limitnum' => $limitnum
769 $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
771 $capability = 'moodle/site:manageallmessaging';
772 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
773 throw new required_capability_exception($context, $capability, 'nopermissions', '');
776 // The user needs to be a part of the conversation before querying who the members are.
777 if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
778 throw new moodle_exception('You are not a member of this conversation.');
781 return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
782 $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']);
786 * Returns the get conversation members return description.
788 * @return \core_external\external_description
790 public static function get_conversation_members_returns() {
791 return new external_multiple_structure(
792 self::get_conversation_member_structure()
797 * Creates a contact request parameters description.
799 * @return external_function_parameters
801 public static function create_contact_request_parameters() {
802 return new external_function_parameters(
804 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
805 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
811 * Creates a contact request.
813 * @param int $userid The id of the user who is creating the contact request
814 * @param int $requesteduserid The id of the user being requested
816 public static function create_contact_request(int $userid, int $requesteduserid) {
817 global $CFG, $USER;
819 // Check if messaging is enabled.
820 if (empty($CFG->messaging)) {
821 throw new moodle_exception('disabled', 'message');
824 // Validate context.
825 $context = context_system::instance();
826 self::validate_context($context);
828 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
829 $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
831 $capability = 'moodle/site:manageallmessaging';
832 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
833 throw new required_capability_exception($context, $capability, 'nopermissions', '');
836 $result = [
837 'warnings' => []
840 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
841 $result['warnings'][] = [
842 'item' => 'user',
843 'itemid' => $params['requesteduserid'],
844 'warningcode' => 'cannotcreatecontactrequest',
845 'message' => 'You are unable to create a contact request for this user'
847 } else {
848 if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
849 // There should only ever be one but just in case there are multiple then we can return the first.
850 $result['request'] = array_shift($requests);
851 } else {
852 $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
856 return $result;
860 * Creates a contact request return description.
862 * @return \core_external\external_description
864 public static function create_contact_request_returns() {
865 return new external_single_structure(
866 array(
867 'request' => new external_single_structure(
868 array(
869 'id' => new external_value(PARAM_INT, 'Message id'),
870 'userid' => new external_value(PARAM_INT, 'User from id'),
871 'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
872 'timecreated' => new external_value(PARAM_INT, 'Time created'),
874 'request record',
875 VALUE_OPTIONAL
877 'warnings' => new external_warnings()
883 * Confirm a contact request parameters description.
885 * @return external_function_parameters
887 public static function confirm_contact_request_parameters() {
888 return new external_function_parameters(
890 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
891 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
897 * Confirm a contact request.
899 * @param int $userid The id of the user who is creating the contact request
900 * @param int $requesteduserid The id of the user being requested
902 public static function confirm_contact_request(int $userid, int $requesteduserid) {
903 global $CFG, $USER;
905 // Check if messaging is enabled.
906 if (empty($CFG->messaging)) {
907 throw new moodle_exception('disabled', 'message');
910 // Validate context.
911 $context = context_system::instance();
912 self::validate_context($context);
914 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
915 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
917 $capability = 'moodle/site:manageallmessaging';
918 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
919 throw new required_capability_exception($context, $capability, 'nopermissions', '');
922 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
924 return [];
928 * Confirm a contact request return description.
930 * @return \core_external\external_description
932 public static function confirm_contact_request_returns() {
933 return new external_warnings();
937 * Declines a contact request parameters description.
939 * @return external_function_parameters
941 public static function decline_contact_request_parameters() {
942 return new external_function_parameters(
944 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
945 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
951 * Declines a contact request.
953 * @param int $userid The id of the user who is creating the contact request
954 * @param int $requesteduserid The id of the user being requested
956 public static function decline_contact_request(int $userid, int $requesteduserid) {
957 global $CFG, $USER;
959 // Check if messaging is enabled.
960 if (empty($CFG->messaging)) {
961 throw new moodle_exception('disabled', 'message');
964 // Validate context.
965 $context = context_system::instance();
966 self::validate_context($context);
968 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
969 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
971 $capability = 'moodle/site:manageallmessaging';
972 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
973 throw new required_capability_exception($context, $capability, 'nopermissions', '');
976 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
978 return [];
982 * Declines a contact request return description.
984 * @return \core_external\external_description
986 public static function decline_contact_request_returns() {
987 return new external_warnings();
991 * Return the structure of a message area contact.
993 * @return external_single_structure
994 * @since Moodle 3.2
996 private static function get_messagearea_contact_structure() {
997 return new external_single_structure(
998 array(
999 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
1000 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1001 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1002 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1003 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
1004 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
1005 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
1006 'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null),
1007 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
1008 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1009 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1010 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
1011 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1012 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1013 VALUE_DEFAULT, null),
1014 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null),
1020 * Return the structure of a conversation.
1022 * @return external_single_structure
1023 * @since Moodle 3.6
1025 private static function get_conversation_structure() {
1026 return new external_single_structure(
1027 array(
1028 'id' => new external_value(PARAM_INT, 'The conversation id'),
1029 'name' => new external_value(PARAM_RAW, 'The conversation name, if set', VALUE_DEFAULT, null),
1030 'subname' => new external_value(PARAM_RAW, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1031 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1032 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group,3=self)'),
1033 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1034 'ismuted' => new external_value(PARAM_BOOL, 'If the user muted this conversation'),
1035 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this conversation as a favourite'),
1036 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1037 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1038 VALUE_DEFAULT, null),
1039 'members' => new external_multiple_structure(
1040 self::get_conversation_member_structure()
1042 'messages' => new external_multiple_structure(
1043 self::get_conversation_message_structure()
1045 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
1046 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
1052 * Return the structure of a conversation member.
1054 * @return external_single_structure
1055 * @since Moodle 3.6
1057 private static function get_conversation_member_structure() {
1058 $result = [
1059 'id' => new external_value(PARAM_INT, 'The user id'),
1060 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1061 'profileurl' => new external_value(PARAM_URL, 'The link to the user\'s profile page'),
1062 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1063 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1064 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1065 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1066 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1067 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1068 'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1069 'canmessageevenifblocked' => new external_value(PARAM_BOOL,
1070 'If the user can still message even if they get blocked'),
1071 'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1072 'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1075 $result['contactrequests'] = new external_multiple_structure(
1076 new external_single_structure(
1078 'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1079 'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1080 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1081 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1083 ), 'The contact requests', VALUE_OPTIONAL
1086 $result['conversations'] = new external_multiple_structure(new external_single_structure(
1087 array(
1088 'id' => new external_value(PARAM_INT, 'Conversations id'),
1089 'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1090 'name' => new external_value(PARAM_RAW, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1091 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1092 ), 'information about conversation', VALUE_OPTIONAL),
1093 'Conversations between users', VALUE_OPTIONAL
1096 return new external_single_structure(
1097 $result
1102 * Return the structure of a message area message.
1104 * @return external_single_structure
1105 * @since Moodle 3.6
1107 private static function get_conversation_message_structure() {
1108 return new external_single_structure(
1109 array(
1110 'id' => new external_value(PARAM_INT, 'The id of the message'),
1111 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1112 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1113 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1119 * Get messagearea message search users parameters.
1121 * @return external_function_parameters
1122 * @since 3.6
1124 public static function message_search_users_parameters() {
1125 return new external_function_parameters(
1126 array(
1127 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1128 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1129 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1130 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1136 * Get search users results.
1138 * @param int $userid The id of the user who is performing the search
1139 * @param string $search The string being searched
1140 * @param int $limitfrom
1141 * @param int $limitnum
1142 * @return array
1143 * @throws moodle_exception
1144 * @since 3.6
1146 public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1147 global $USER;
1149 $systemcontext = context_system::instance();
1151 $params = array(
1152 'userid' => $userid,
1153 'search' => $search,
1154 'limitfrom' => $limitfrom,
1155 'limitnum' => $limitnum
1157 $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1158 self::validate_context($systemcontext);
1160 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1161 throw new moodle_exception('You do not have permission to perform this action.');
1164 list($contacts, $noncontacts) = \core_message\api::message_search_users(
1165 $params['userid'],
1166 $params['search'],
1167 $params['limitfrom'],
1168 $params['limitnum']);
1170 return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1174 * Get messagearea message search users returns.
1176 * @return external_single_structure
1177 * @since 3.2
1179 public static function message_search_users_returns() {
1180 return new external_single_structure(
1181 array(
1182 'contacts' => new external_multiple_structure(
1183 self::get_conversation_member_structure()
1185 'noncontacts' => new external_multiple_structure(
1186 self::get_conversation_member_structure()
1193 * Get messagearea search messages parameters.
1195 * @return external_function_parameters
1196 * @since 3.2
1198 public static function data_for_messagearea_search_messages_parameters() {
1199 return new external_function_parameters(
1200 array(
1201 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1202 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1203 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1204 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1210 * Get messagearea search messages results.
1212 * @param int $userid The id of the user who is performing the search
1213 * @param string $search The string being searched
1214 * @param int $limitfrom
1215 * @param int $limitnum
1216 * @return stdClass
1217 * @throws moodle_exception
1218 * @since 3.2
1220 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1221 global $CFG, $USER;
1223 // Check if messaging is enabled.
1224 if (empty($CFG->messaging)) {
1225 throw new moodle_exception('disabled', 'message');
1228 $systemcontext = context_system::instance();
1230 $params = array(
1231 'userid' => $userid,
1232 'search' => $search,
1233 'limitfrom' => $limitfrom,
1234 'limitnum' => $limitnum
1237 $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1238 self::validate_context($systemcontext);
1240 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1241 throw new moodle_exception('You do not have permission to perform this action.');
1244 $messages = \core_message\api::search_messages(
1245 $params['userid'],
1246 $params['search'],
1247 $params['limitfrom'],
1248 $params['limitnum']
1251 $data = new \stdClass();
1252 $data->contacts = [];
1253 foreach ($messages as $message) {
1254 $contact = new \stdClass();
1255 $contact->userid = $message->userid;
1256 $contact->fullname = $message->fullname;
1257 $contact->profileimageurl = $message->profileimageurl;
1258 $contact->profileimageurlsmall = $message->profileimageurlsmall;
1259 $contact->messageid = $message->messageid;
1260 $contact->ismessaging = $message->ismessaging;
1261 $contact->sentfromcurrentuser = false;
1262 if ($message->lastmessage) {
1263 if ($message->userid !== $message->useridfrom) {
1264 $contact->sentfromcurrentuser = true;
1266 $contact->lastmessage = shorten_text($message->lastmessage, 60);
1267 } else {
1268 $contact->lastmessage = null;
1270 $contact->lastmessagedate = $message->lastmessagedate;
1271 $contact->showonlinestatus = is_null($message->isonline) ? false : true;
1272 $contact->isonline = $message->isonline;
1273 $contact->isblocked = $message->isblocked;
1274 $contact->isread = $message->isread;
1275 $contact->unreadcount = $message->unreadcount;
1276 $contact->conversationid = $message->conversationid;
1278 $data->contacts[] = $contact;
1281 return $data;
1285 * Get messagearea search messages returns.
1287 * @return external_single_structure
1288 * @since 3.2
1290 public static function data_for_messagearea_search_messages_returns() {
1291 return new external_single_structure(
1292 array(
1293 'contacts' => new external_multiple_structure(
1294 self::get_messagearea_contact_structure()
1301 * Get conversations parameters.
1303 * @return external_function_parameters
1304 * @since 3.6
1306 public static function get_conversations_parameters() {
1307 return new external_function_parameters(
1308 array(
1309 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1310 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1311 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1312 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1313 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1314 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1315 VALUE_DEFAULT, null),
1316 'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private
1317 conversations (false) when private conversations are requested.',
1318 VALUE_DEFAULT, false),
1324 * Get the list of conversations for the user.
1326 * @param int $userid The id of the user who is performing the search
1327 * @param int $limitfrom
1328 * @param int $limitnum
1329 * @param int|null $type
1330 * @param bool|null $favourites
1331 * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false)
1332 * when private conversations are requested.
1333 * @return stdClass
1334 * @throws \moodle_exception if the messaging feature is disabled on the site.
1335 * @since 3.2
1337 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null,
1338 bool $mergeself = false) {
1339 global $CFG, $USER;
1341 // All the standard BL checks.
1342 if (empty($CFG->messaging)) {
1343 throw new moodle_exception('disabled', 'message');
1346 $params = array(
1347 'userid' => $userid,
1348 'limitfrom' => $limitfrom,
1349 'limitnum' => $limitnum,
1350 'type' => $type,
1351 'favourites' => $favourites,
1352 'mergeself' => $mergeself
1354 $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1356 $systemcontext = context_system::instance();
1357 self::validate_context($systemcontext);
1359 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1360 throw new moodle_exception('You do not have permission to perform this action.');
1363 $conversations = \core_message\api::get_conversations(
1364 $params['userid'],
1365 $params['limitfrom'],
1366 $params['limitnum'],
1367 $params['type'],
1368 $params['favourites'],
1369 $params['mergeself']
1372 return (object) ['conversations' => $conversations];
1376 * Get conversations returns.
1378 * @return external_single_structure
1379 * @since 3.6
1381 public static function get_conversations_returns() {
1382 return new external_single_structure(
1384 'conversations' => new external_multiple_structure(
1385 self::get_conversation_structure(true)
1392 * Get conversation parameters.
1394 * @return external_function_parameters
1396 public static function get_conversation_parameters() {
1397 return new external_function_parameters(
1398 array(
1399 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1400 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1401 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1402 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1403 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1404 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1405 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1406 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1407 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1413 * Get a single conversation.
1415 * @param int $userid The user id to get the conversation for
1416 * @param int $conversationid The id of the conversation to fetch
1417 * @param bool $includecontactrequests Should contact requests be included between members
1418 * @param bool $includeprivacyinfo Should privacy info be included between members
1419 * @param int $memberlimit Limit number of members to load
1420 * @param int $memberoffset Offset members by this amount
1421 * @param int $messagelimit Limit number of messages to load
1422 * @param int $messageoffset Offset the messages
1423 * @param bool $newestmessagesfirst Order messages by newest first
1424 * @return stdClass
1425 * @throws \moodle_exception if the messaging feature is disabled on the site.
1427 public static function get_conversation(
1428 int $userid,
1429 int $conversationid,
1430 bool $includecontactrequests = false,
1431 bool $includeprivacyinfo = false,
1432 int $memberlimit = 0,
1433 int $memberoffset = 0,
1434 int $messagelimit = 0,
1435 int $messageoffset = 0,
1436 bool $newestmessagesfirst = true
1438 global $CFG, $DB, $USER;
1440 // All the standard BL checks.
1441 if (empty($CFG->messaging)) {
1442 throw new moodle_exception('disabled', 'message');
1445 $params = [
1446 'userid' => $userid,
1447 'conversationid' => $conversationid,
1448 'includecontactrequests' => $includecontactrequests,
1449 'includeprivacyinfo' => $includeprivacyinfo,
1450 'memberlimit' => $memberlimit,
1451 'memberoffset' => $memberoffset,
1452 'messagelimit' => $messagelimit,
1453 'messageoffset' => $messageoffset,
1454 'newestmessagesfirst' => $newestmessagesfirst
1456 self::validate_parameters(self::get_conversation_parameters(), $params);
1458 $systemcontext = context_system::instance();
1459 self::validate_context($systemcontext);
1461 $conversation = \core_message\api::get_conversation(
1462 $params['userid'],
1463 $params['conversationid'],
1464 $params['includecontactrequests'],
1465 $params['includeprivacyinfo'],
1466 $params['memberlimit'],
1467 $params['memberoffset'],
1468 $params['messagelimit'],
1469 $params['messageoffset'],
1470 $params['newestmessagesfirst']
1473 if ($conversation) {
1474 return $conversation;
1475 } else {
1476 // We have to throw an exception here because the external functions annoyingly
1477 // don't accept null to be returned for a single structure.
1478 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1483 * Get conversation returns.
1485 * @return external_single_structure
1487 public static function get_conversation_returns() {
1488 return self::get_conversation_structure();
1492 * Get conversation parameters.
1494 * @return external_function_parameters
1496 public static function get_conversation_between_users_parameters() {
1497 return new external_function_parameters(
1498 array(
1499 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1500 'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1501 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1502 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1503 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1504 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1505 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1506 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1507 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1513 * Get a single conversation between users.
1515 * @param int $userid The user id to get the conversation for
1516 * @param int $otheruserid The other user id
1517 * @param bool $includecontactrequests Should contact requests be included between members
1518 * @param bool $includeprivacyinfo Should privacy info be included between members
1519 * @param int $memberlimit Limit number of members to load
1520 * @param int $memberoffset Offset members by this amount
1521 * @param int $messagelimit Limit number of messages to load
1522 * @param int $messageoffset Offset the messages
1523 * @param bool $newestmessagesfirst Order messages by newest first
1524 * @return stdClass
1525 * @throws \moodle_exception if the messaging feature is disabled on the site.
1527 public static function get_conversation_between_users(
1528 int $userid,
1529 int $otheruserid,
1530 bool $includecontactrequests = false,
1531 bool $includeprivacyinfo = false,
1532 int $memberlimit = 0,
1533 int $memberoffset = 0,
1534 int $messagelimit = 0,
1535 int $messageoffset = 0,
1536 bool $newestmessagesfirst = true
1538 global $CFG, $DB, $USER;
1540 // All the standard BL checks.
1541 if (empty($CFG->messaging)) {
1542 throw new moodle_exception('disabled', 'message');
1545 $params = [
1546 'userid' => $userid,
1547 'otheruserid' => $otheruserid,
1548 'includecontactrequests' => $includecontactrequests,
1549 'includeprivacyinfo' => $includeprivacyinfo,
1550 'memberlimit' => $memberlimit,
1551 'memberoffset' => $memberoffset,
1552 'messagelimit' => $messagelimit,
1553 'messageoffset' => $messageoffset,
1554 'newestmessagesfirst' => $newestmessagesfirst
1556 self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
1558 $systemcontext = context_system::instance();
1559 self::validate_context($systemcontext);
1561 $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
1562 $conversation = null;
1564 if ($conversationid) {
1565 $conversation = \core_message\api::get_conversation(
1566 $params['userid'],
1567 $conversationid,
1568 $params['includecontactrequests'],
1569 $params['includeprivacyinfo'],
1570 $params['memberlimit'],
1571 $params['memberoffset'],
1572 $params['messagelimit'],
1573 $params['messageoffset'],
1574 $params['newestmessagesfirst']
1578 if ($conversation) {
1579 return $conversation;
1580 } else {
1581 // We have to throw an exception here because the external functions annoyingly
1582 // don't accept null to be returned for a single structure.
1583 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1588 * Get conversation returns.
1590 * @return external_single_structure
1592 public static function get_conversation_between_users_returns() {
1593 return self::get_conversation_structure(true);
1597 * Get self-conversation parameters.
1599 * @return external_function_parameters
1601 public static function get_self_conversation_parameters() {
1602 return new external_function_parameters(
1603 array(
1604 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'),
1605 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1606 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1607 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1613 * Get a single self-conversation.
1615 * @param int $userid The user id to get the self-conversation for
1616 * @param int $messagelimit Limit number of messages to load
1617 * @param int $messageoffset Offset the messages
1618 * @param bool $newestmessagesfirst Order messages by newest first
1619 * @return stdClass
1620 * @throws \moodle_exception if the messaging feature is disabled on the site.
1621 * @since Moodle 3.7
1623 public static function get_self_conversation(
1624 int $userid,
1625 int $messagelimit = 0,
1626 int $messageoffset = 0,
1627 bool $newestmessagesfirst = true
1629 global $CFG;
1631 // All the standard BL checks.
1632 if (empty($CFG->messaging)) {
1633 throw new moodle_exception('disabled', 'message');
1636 $params = [
1637 'userid' => $userid,
1638 'messagelimit' => $messagelimit,
1639 'messageoffset' => $messageoffset,
1640 'newestmessagesfirst' => $newestmessagesfirst
1642 self::validate_parameters(self::get_self_conversation_parameters(), $params);
1644 $systemcontext = context_system::instance();
1645 self::validate_context($systemcontext);
1647 $conversation = \core_message\api::get_self_conversation($params['userid']);
1649 if ($conversation) {
1650 $conversation = \core_message\api::get_conversation(
1651 $params['userid'],
1652 $conversation->id,
1653 false,
1654 false,
1657 $params['messagelimit'],
1658 $params['messageoffset'],
1659 $params['newestmessagesfirst']
1663 if ($conversation) {
1664 return $conversation;
1665 } else {
1666 // We have to throw an exception here because the external functions annoyingly
1667 // don't accept null to be returned for a single structure.
1668 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1673 * Get conversation returns.
1675 * @return external_single_structure
1677 public static function get_self_conversation_returns() {
1678 return self::get_conversation_structure();
1682 * The conversation messages parameters.
1684 * @return external_function_parameters
1685 * @since 3.6
1687 public static function get_conversation_messages_parameters() {
1688 return new external_function_parameters(
1689 array(
1690 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1691 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1692 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1693 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1694 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1695 'timefrom' => new external_value(PARAM_INT,
1696 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1702 * Get conversation messages.
1704 * @param int $currentuserid The current user's id.
1705 * @param int $convid The conversation id.
1706 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1707 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1708 * @param bool $newest True for getting first newest messages, false otherwise.
1709 * @param int $timefrom The time from the conversation messages to get.
1710 * @return array The messages and members who have sent some of these messages.
1711 * @throws moodle_exception
1712 * @since 3.6
1714 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1715 bool $newest = false, int $timefrom = 0) {
1716 global $CFG, $USER;
1718 // Check if messaging is enabled.
1719 if (empty($CFG->messaging)) {
1720 throw new moodle_exception('disabled', 'message');
1723 $systemcontext = context_system::instance();
1725 $params = array(
1726 'currentuserid' => $currentuserid,
1727 'convid' => $convid,
1728 'limitfrom' => $limitfrom,
1729 'limitnum' => $limitnum,
1730 'newest' => $newest,
1731 'timefrom' => $timefrom,
1733 $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1734 self::validate_context($systemcontext);
1736 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1737 throw new moodle_exception('You do not have permission to perform this action.');
1740 // Check that the user belongs to the conversation.
1741 if (!\core_message\api::is_user_in_conversation($params['currentuserid'], $params['convid'])) {
1742 throw new moodle_exception('User is not part of conversation.');
1745 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1747 // We need to enforce a one second delay on messages to avoid race conditions of current
1748 // messages still being sent.
1750 // There is a chance that we could request messages before the current time's
1751 // second has elapsed and while other messages are being sent in that same second. In which
1752 // case those messages will be lost.
1754 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1755 $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1757 // No requesting messages from the current time, as stated above.
1758 if ($params['timefrom'] == time()) {
1759 $messages = [];
1760 } else {
1761 $messages = \core_message\api::get_conversation_messages(
1762 $params['currentuserid'],
1763 $params['convid'],
1764 $params['limitfrom'],
1765 $params['limitnum'],
1766 $sort,
1767 $params['timefrom'],
1768 $timeto);
1771 return $messages;
1775 * The messagearea messages return structure.
1777 * @return external_single_structure
1778 * @since 3.6
1780 public static function get_conversation_messages_returns() {
1781 return new external_single_structure(
1782 array(
1783 'id' => new external_value(PARAM_INT, 'The conversation id'),
1784 'members' => new external_multiple_structure(
1785 self::get_conversation_member_structure()
1787 'messages' => new external_multiple_structure(
1788 self::get_conversation_message_structure()
1795 * The user contacts return parameters.
1797 * @return external_function_parameters
1799 public static function get_user_contacts_parameters() {
1800 return new external_function_parameters(
1801 array(
1802 'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
1803 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1804 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1810 * Get user contacts.
1812 * @param int $userid The id of the user who we are viewing conversations for
1813 * @param int $limitfrom
1814 * @param int $limitnum
1815 * @return array
1816 * @throws moodle_exception
1818 public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
1819 global $CFG, $USER;
1821 // Check if messaging is enabled.
1822 if (empty($CFG->messaging)) {
1823 throw new moodle_exception('disabled', 'message');
1826 $systemcontext = context_system::instance();
1828 $params = array(
1829 'userid' => $userid,
1830 'limitfrom' => $limitfrom,
1831 'limitnum' => $limitnum
1833 $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
1834 self::validate_context($systemcontext);
1836 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1837 throw new moodle_exception('You do not have permission to perform this action.');
1840 return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1844 * The user contacts return structure.
1846 * @return external_multiple_structure
1848 public static function get_user_contacts_returns() {
1849 return new external_multiple_structure(
1850 self::get_conversation_member_structure()
1855 * Search contacts parameters description.
1857 * @return external_function_parameters
1858 * @since Moodle 2.5
1860 public static function search_contacts_parameters() {
1861 return new external_function_parameters(
1862 array(
1863 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1864 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1865 VALUE_DEFAULT, false)
1871 * Search contacts.
1873 * @param string $searchtext query string.
1874 * @param bool $onlymycourses limit the search to the user's courses only.
1875 * @return \core_external\external_description
1876 * @since Moodle 2.5
1878 public static function search_contacts($searchtext, $onlymycourses = false) {
1879 global $CFG, $USER, $PAGE;
1880 require_once($CFG->dirroot . '/user/lib.php');
1882 // Check if messaging is enabled.
1883 if (empty($CFG->messaging)) {
1884 throw new moodle_exception('disabled', 'message');
1887 require_once($CFG->libdir . '/enrollib.php');
1889 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1890 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1892 // Extra validation, we do not allow empty queries.
1893 if ($params['searchtext'] === '') {
1894 throw new moodle_exception('querystringcannotbeempty');
1897 $courseids = array();
1898 if ($params['onlymycourses']) {
1899 $mycourses = enrol_get_my_courses(array('id'));
1900 foreach ($mycourses as $mycourse) {
1901 $courseids[] = $mycourse->id;
1903 } else {
1904 $courseids[] = SITEID;
1907 // Retrieving the users matching the query.
1908 $users = message_search_users($courseids, $params['searchtext']);
1909 $results = array();
1910 foreach ($users as $user) {
1911 $results[$user->id] = $user;
1914 // Reorganising information.
1915 foreach ($results as &$user) {
1916 $newuser = array(
1917 'id' => $user->id,
1918 'fullname' => fullname($user)
1921 // Avoid undefined property notice as phone not specified.
1922 $user->phone1 = null;
1923 $user->phone2 = null;
1925 $userpicture = new user_picture($user);
1926 $userpicture->size = 1; // Size f1.
1927 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1928 $userpicture->size = 0; // Size f2.
1929 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1931 $user = $newuser;
1934 return $results;
1938 * Search contacts return description.
1940 * @return \core_external\external_description
1941 * @since Moodle 2.5
1943 public static function search_contacts_returns() {
1944 return new external_multiple_structure(
1945 new external_single_structure(
1946 array(
1947 'id' => new external_value(PARAM_INT, 'User ID'),
1948 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1949 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1950 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1953 'List of contacts'
1958 * Get messages parameters description.
1960 * @return external_function_parameters
1961 * @since 2.8
1963 public static function get_messages_parameters() {
1964 return new external_function_parameters(
1965 array(
1966 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1967 'useridfrom' => new external_value(
1968 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1969 VALUE_DEFAULT, 0),
1970 'type' => new external_value(
1971 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1972 VALUE_DEFAULT, 'both'),
1973 'read' => new external_value(PARAM_INT, '1 for getting read messages, 0 for unread, 2 for both',
1974 VALUE_DEFAULT, 1),
1975 'newestfirst' => new external_value(
1976 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1977 VALUE_DEFAULT, true),
1978 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1979 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1985 * Get messages function implementation.
1987 * @since 2.8
1988 * @throws invalid_parameter_exception
1989 * @throws moodle_exception
1990 * @param int $useridto the user id who received the message
1991 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
1992 * @param string $type type of message to return, expected values: notifications, conversations and both
1993 * @param int $read 1 for getting read messages, 0 for unread, 2 for both
1994 * @param bool $newestfirst true for ordering by newest first, false for oldest first
1995 * @param int $limitfrom limit from
1996 * @param int $limitnum limit num
1997 * @return \core_external\external_description
1999 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = MESSAGE_GET_READ,
2000 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2001 global $CFG, $USER, $PAGE;
2003 $warnings = array();
2005 $params = array(
2006 'useridto' => $useridto,
2007 'useridfrom' => $useridfrom,
2008 'type' => $type,
2009 'read' => $read,
2010 'newestfirst' => $newestfirst,
2011 'limitfrom' => $limitfrom,
2012 'limitnum' => $limitnum
2015 $params = self::validate_parameters(self::get_messages_parameters(), $params);
2017 $context = context_system::instance();
2018 self::validate_context($context);
2020 $useridto = $params['useridto'];
2021 $useridfrom = $params['useridfrom'];
2022 $type = $params['type'];
2023 $read = $params['read'];
2024 $newestfirst = $params['newestfirst'];
2025 $limitfrom = $params['limitfrom'];
2026 $limitnum = $params['limitnum'];
2028 $allowedvalues = array('notifications', 'conversations', 'both');
2029 if (!in_array($type, $allowedvalues)) {
2030 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2031 'allowed values are: ' . implode(',', $allowedvalues));
2034 // Check if private messaging between users is allowed.
2035 if (empty($CFG->messaging)) {
2036 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2037 if ($type == "conversations") {
2038 throw new moodle_exception('disabled', 'message');
2040 if ($type == "both") {
2041 $warning = array();
2042 $warning['item'] = 'message';
2043 $warning['itemid'] = $USER->id;
2044 $warning['warningcode'] = '1';
2045 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2046 Only notifications will be returned';
2047 $warnings[] = $warning;
2051 if (!empty($useridto)) {
2052 if (core_user::is_real_user($useridto)) {
2053 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2054 } else {
2055 throw new moodle_exception('invaliduser');
2059 if (!empty($useridfrom)) {
2060 // We use get_user here because the from user can be the noreply or support user.
2061 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2064 // Check if the current user is the sender/receiver or just a privileged user.
2065 if ($useridto != $USER->id and $useridfrom != $USER->id and
2066 !has_capability('moodle/site:readallmessages', $context)) {
2067 throw new moodle_exception('accessdenied', 'admin');
2070 // Which type of messages to retrieve.
2071 $notifications = -1;
2072 if ($type != 'both') {
2073 $notifications = ($type == 'notifications') ? 1 : 0;
2076 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2077 $sort = "mr.timecreated $orderdirection";
2079 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2080 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2082 // In some cases, we don't need to get the to/from user objects from the sql query.
2083 $userfromfullname = '';
2084 $usertofullname = '';
2086 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2087 if (!empty($useridto)) {
2088 $usertofullname = fullname($userto, $canviewfullname);
2089 // The user from may or may not be filled.
2090 if (!empty($useridfrom)) {
2091 $userfromfullname = fullname($userfrom, $canviewfullname);
2093 } else {
2094 // If the useridto field is empty, the useridfrom must be filled.
2095 $userfromfullname = fullname($userfrom, $canviewfullname);
2097 foreach ($messages as $mid => $message) {
2099 if (!$message->notification) {
2100 // Do not return deleted messages.
2101 if (($useridto == $USER->id and $message->timeusertodeleted) or
2102 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2103 unset($messages[$mid]);
2104 continue;
2106 } else {
2107 // Return iconurl for notifications.
2108 if (!isset($output)) {
2109 $output = $PAGE->get_renderer('core');
2112 if (!empty($message->component) && substr($message->component, 0, 4) == 'mod_') {
2113 $iconurl = $output->image_url('monologo', $message->component);
2114 } else {
2115 $iconurl = $output->image_url('i/marker', 'core');
2118 $message->iconurl = clean_param($iconurl->out(), PARAM_URL);
2121 // We need to get the user from the query.
2122 if (empty($userfromfullname)) {
2123 // Check for non-reply and support users.
2124 if (core_user::is_real_user($message->useridfrom)) {
2125 $user = new stdClass();
2126 $user = username_load_fields_from_object($user, $message, 'userfrom');
2127 $message->userfromfullname = fullname($user, $canviewfullname);
2128 } else {
2129 $user = core_user::get_user($message->useridfrom);
2130 $message->userfromfullname = fullname($user, $canviewfullname);
2132 } else {
2133 $message->userfromfullname = $userfromfullname;
2136 // We need to get the user from the query.
2137 if (empty($usertofullname)) {
2138 $user = new stdClass();
2139 $user = username_load_fields_from_object($user, $message, 'userto');
2140 $message->usertofullname = fullname($user, $canviewfullname);
2141 } else {
2142 $message->usertofullname = $usertofullname;
2145 $message->text = message_format_message_text($message);
2146 $messages[$mid] = (array) $message;
2150 $results = array(
2151 'messages' => $messages,
2152 'warnings' => $warnings
2155 return $results;
2159 * Get messages return description.
2161 * @return external_single_structure
2162 * @since 2.8
2164 public static function get_messages_returns() {
2165 return new external_single_structure(
2166 array(
2167 'messages' => new external_multiple_structure(
2168 new external_single_structure(
2169 array(
2170 'id' => new external_value(PARAM_INT, 'Message id'),
2171 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2172 'useridto' => new external_value(PARAM_INT, 'User to id'),
2173 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2174 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2175 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2176 'fullmessageformat' => new external_format_value('fullmessage'),
2177 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2178 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2179 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2180 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2181 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2182 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2183 'timeread' => new external_value(PARAM_INT, 'Time read'),
2184 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2185 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
2186 'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
2187 VALUE_OPTIONAL),
2188 'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
2189 'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
2190 The data here is serialised using json_encode().', VALUE_OPTIONAL),
2191 'iconurl' => new external_value(PARAM_URL, 'URL for icon, only for notifications.', VALUE_OPTIONAL),
2192 ), 'message'
2195 'warnings' => new external_warnings()
2201 * Mark all notifications as read parameters description.
2203 * @return external_function_parameters
2204 * @since 3.2
2206 public static function mark_all_notifications_as_read_parameters() {
2207 return new external_function_parameters(
2208 array(
2209 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2210 'useridfrom' => new external_value(
2211 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2212 VALUE_DEFAULT, 0),
2213 'timecreatedto' => new external_value(
2214 PARAM_INT, 'mark messages created before this time as read, 0 for all messages',
2215 VALUE_DEFAULT, 0),
2221 * Mark all notifications as read function.
2223 * @since 3.2
2224 * @throws invalid_parameter_exception
2225 * @throws moodle_exception
2226 * @param int $useridto the user id who received the message
2227 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2228 * @param int $timecreatedto mark message created before this time as read, 0 for all messages
2229 * @return \core_external\external_description
2231 public static function mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto = 0) {
2232 global $USER;
2234 $params = self::validate_parameters(
2235 self::mark_all_notifications_as_read_parameters(),
2236 array(
2237 'useridto' => $useridto,
2238 'useridfrom' => $useridfrom,
2239 'timecreatedto' => $timecreatedto,
2243 $context = context_system::instance();
2244 self::validate_context($context);
2246 $useridto = $params['useridto'];
2247 $useridfrom = $params['useridfrom'];
2248 $timecreatedto = $params['timecreatedto'];
2250 if (!empty($useridto)) {
2251 if (core_user::is_real_user($useridto)) {
2252 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2253 } else {
2254 throw new moodle_exception('invaliduser');
2258 if (!empty($useridfrom)) {
2259 // We use get_user here because the from user can be the noreply or support user.
2260 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2263 // Check if the current user is the sender/receiver or just a privileged user.
2264 if ($useridto != $USER->id and $useridfrom != $USER->id and
2265 // The deleteanymessage cap seems more reasonable here than readallmessages.
2266 !has_capability('moodle/site:deleteanymessage', $context)) {
2267 throw new moodle_exception('accessdenied', 'admin');
2270 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto);
2272 return true;
2276 * Mark all notifications as read return description.
2278 * @return external_single_structure
2279 * @since 3.2
2281 public static function mark_all_notifications_as_read_returns() {
2282 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2286 * Get unread conversations count parameters description.
2288 * @return external_function_parameters
2289 * @since 3.2
2291 public static function get_unread_conversations_count_parameters() {
2292 return new external_function_parameters(
2293 array(
2294 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2300 * Get unread messages count function.
2302 * @since 3.2
2303 * @throws invalid_parameter_exception
2304 * @throws moodle_exception
2305 * @param int $useridto the user id who received the message
2306 * @return \core_external\external_description
2308 public static function get_unread_conversations_count($useridto) {
2309 global $USER, $CFG;
2311 // Check if messaging is enabled.
2312 if (empty($CFG->messaging)) {
2313 throw new moodle_exception('disabled', 'message');
2316 $params = self::validate_parameters(
2317 self::get_unread_conversations_count_parameters(),
2318 array('useridto' => $useridto)
2321 $context = context_system::instance();
2322 self::validate_context($context);
2324 $useridto = $params['useridto'];
2326 if (!empty($useridto)) {
2327 if (core_user::is_real_user($useridto)) {
2328 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2329 } else {
2330 throw new moodle_exception('invaliduser');
2332 } else {
2333 $useridto = $USER->id;
2336 // Check if the current user is the receiver or just a privileged user.
2337 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2338 throw new moodle_exception('accessdenied', 'admin');
2341 return \core_message\api::count_unread_conversations($userto);
2345 * Get unread conversations count return description.
2347 * @return external_single_structure
2348 * @since 3.2
2350 public static function get_unread_conversations_count_returns() {
2351 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2355 * Get blocked users parameters description.
2357 * @return external_function_parameters
2358 * @since 2.9
2360 public static function get_blocked_users_parameters() {
2361 return new external_function_parameters(
2362 array(
2363 'userid' => new external_value(PARAM_INT,
2364 'the user whose blocked users we want to retrieve',
2365 VALUE_REQUIRED),
2371 * Retrieve a list of users blocked
2373 * @param int $userid the user whose blocked users we want to retrieve
2374 * @return \core_external\external_description
2375 * @since 2.9
2377 public static function get_blocked_users($userid) {
2378 global $CFG, $USER, $PAGE;
2380 // Warnings array, it can be empty at the end but is mandatory.
2381 $warnings = array();
2383 // Validate params.
2384 $params = array(
2385 'userid' => $userid
2387 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2388 $userid = $params['userid'];
2390 // Validate context.
2391 $context = context_system::instance();
2392 self::validate_context($context);
2394 // Check if private messaging between users is allowed.
2395 if (empty($CFG->messaging)) {
2396 throw new moodle_exception('disabled', 'message');
2399 $user = core_user::get_user($userid, '*', MUST_EXIST);
2400 core_user::require_active_user($user);
2402 // Check if we have permissions for retrieve the information.
2403 $capability = 'moodle/site:manageallmessaging';
2404 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2405 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2408 // Now, we can get safely all the blocked users.
2409 $users = \core_message\api::get_blocked_users($user->id);
2411 $blockedusers = array();
2412 foreach ($users as $user) {
2413 $newuser = array(
2414 'id' => $user->id,
2415 'fullname' => fullname($user),
2418 $userpicture = new user_picture($user);
2419 $userpicture->size = 1; // Size f1.
2420 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2422 $blockedusers[] = $newuser;
2425 $results = array(
2426 'users' => $blockedusers,
2427 'warnings' => $warnings
2429 return $results;
2433 * Get blocked users return description.
2435 * @return external_single_structure
2436 * @since 2.9
2438 public static function get_blocked_users_returns() {
2439 return new external_single_structure(
2440 array(
2441 'users' => new external_multiple_structure(
2442 new external_single_structure(
2443 array(
2444 'id' => new external_value(PARAM_INT, 'User ID'),
2445 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2446 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2449 'List of blocked users'
2451 'warnings' => new external_warnings()
2457 * Returns description of method parameters
2459 * @return external_function_parameters
2460 * @since 2.9
2462 public static function mark_message_read_parameters() {
2463 return new external_function_parameters(
2464 array(
2465 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2466 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2467 VALUE_DEFAULT, 0)
2473 * Mark a single message as read, trigger message_viewed event
2475 * @param int $messageid id of the message (in the message table)
2476 * @param int $timeread timestamp for when the message should be marked read
2477 * @return \core_external\external_description
2478 * @throws invalid_parameter_exception
2479 * @throws moodle_exception
2480 * @since 2.9
2482 public static function mark_message_read($messageid, $timeread) {
2483 global $CFG, $DB, $USER;
2485 // Check if private messaging between users is allowed.
2486 if (empty($CFG->messaging)) {
2487 throw new moodle_exception('disabled', 'message');
2490 // Warnings array, it can be empty at the end but is mandatory.
2491 $warnings = array();
2493 // Validate params.
2494 $params = array(
2495 'messageid' => $messageid,
2496 'timeread' => $timeread
2498 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2500 if (empty($params['timeread'])) {
2501 $timeread = time();
2502 } else {
2503 $timeread = $params['timeread'];
2506 // Validate context.
2507 $context = context_system::instance();
2508 self::validate_context($context);
2510 $sql = "SELECT m.*, mcm.userid as useridto
2511 FROM {messages} m
2512 INNER JOIN {message_conversations} mc
2513 ON m.conversationid = mc.id
2514 INNER JOIN {message_conversation_members} mcm
2515 ON mcm.conversationid = mc.id
2516 LEFT JOIN {message_user_actions} mua
2517 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2518 WHERE mua.id is NULL
2519 AND mcm.userid != m.useridfrom
2520 AND m.id = ?";
2521 $messageparams = [];
2522 $messageparams[] = $USER->id;
2523 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2524 $messageparams[] = $params['messageid'];
2525 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2527 if ($message->useridto != $USER->id) {
2528 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2531 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2533 $results = array(
2534 'messageid' => $message->id,
2535 'warnings' => $warnings
2537 return $results;
2541 * Returns description of method result value
2543 * @return \core_external\external_description
2544 * @since 2.9
2546 public static function mark_message_read_returns() {
2547 return new external_single_structure(
2548 array(
2549 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2550 'warnings' => new external_warnings()
2556 * Returns description of method parameters
2558 * @return external_function_parameters
2560 public static function mark_notification_read_parameters() {
2561 return new external_function_parameters(
2562 array(
2563 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2564 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2565 VALUE_DEFAULT, 0)
2571 * Mark a single notification as read.
2573 * This will trigger a 'notification_viewed' event.
2575 * @param int $notificationid id of the notification
2576 * @param int $timeread timestamp for when the notification should be marked read
2577 * @return \core_external\external_description
2578 * @throws invalid_parameter_exception
2579 * @throws moodle_exception
2581 public static function mark_notification_read($notificationid, $timeread) {
2582 global $CFG, $DB, $USER;
2584 // Warnings array, it can be empty at the end but is mandatory.
2585 $warnings = array();
2587 // Validate params.
2588 $params = array(
2589 'notificationid' => $notificationid,
2590 'timeread' => $timeread
2592 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2594 if (empty($params['timeread'])) {
2595 $timeread = time();
2596 } else {
2597 $timeread = $params['timeread'];
2600 // Validate context.
2601 $context = context_system::instance();
2602 self::validate_context($context);
2604 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2606 if ($notification->useridto != $USER->id) {
2607 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2608 'notification as read');
2611 \core_message\api::mark_notification_as_read($notification, $timeread);
2613 $results = array(
2614 'notificationid' => $notification->id,
2615 'warnings' => $warnings
2618 return $results;
2622 * Returns description of method result value
2624 * @return \core_external\external_description
2626 public static function mark_notification_read_returns() {
2627 return new external_single_structure(
2628 array(
2629 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2630 'warnings' => new external_warnings()
2636 * Mark all conversation messages as read parameters description.
2638 * @return external_function_parameters
2639 * @since 3.6
2641 public static function mark_all_conversation_messages_as_read_parameters() {
2642 return new external_function_parameters(
2643 array(
2644 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2645 'conversationid' =>
2646 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2652 * Mark all conversation messages as read function.
2654 * @param int $userid The user id of who we want to delete the conversation for
2655 * @param int $conversationid The id of the conversations
2656 * @since 3.6
2658 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2659 global $CFG;
2661 // Check if messaging is enabled.
2662 if (empty($CFG->messaging)) {
2663 throw new moodle_exception('disabled', 'message');
2666 $params = array(
2667 'userid' => $userid,
2668 'conversationid' => $conversationid,
2670 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2672 $context = context_system::instance();
2673 self::validate_context($context);
2675 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2676 core_user::require_active_user($user);
2678 if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
2679 \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
2680 } else {
2681 throw new moodle_exception('accessdenied', 'admin');
2686 * Mark all conversation messages as read return description.
2688 * @return external_warnings
2689 * @since 3.6
2691 public static function mark_all_conversation_messages_as_read_returns() {
2692 return null;
2696 * Returns description of method parameters.
2698 * @return external_function_parameters
2699 * @since 3.6
2701 public static function delete_conversations_by_id_parameters() {
2702 return new external_function_parameters(
2703 array(
2704 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2705 'conversationids' => new external_multiple_structure(
2706 new external_value(PARAM_INT, 'The id of the conversation'),
2707 'List of conversation IDs'
2714 * Deletes a conversation.
2716 * @param int $userid The user id of who we want to delete the conversation for
2717 * @param int[] $conversationids The ids of the conversations
2718 * @return array
2719 * @throws moodle_exception
2720 * @since 3.6
2722 public static function delete_conversations_by_id($userid, array $conversationids) {
2723 global $CFG;
2725 // Check if private messaging between users is allowed.
2726 if (empty($CFG->messaging)) {
2727 throw new moodle_exception('disabled', 'message');
2730 // Validate params.
2731 $params = [
2732 'userid' => $userid,
2733 'conversationids' => $conversationids,
2735 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
2737 // Validate context.
2738 $context = context_system::instance();
2739 self::validate_context($context);
2741 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2742 core_user::require_active_user($user);
2744 foreach ($params['conversationids'] as $conversationid) {
2745 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2746 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2747 } else {
2748 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2752 return [];
2756 * Returns description of method result value.
2758 * @return \core_external\external_description
2759 * @since 3.6
2761 public static function delete_conversations_by_id_returns() {
2762 return new external_warnings();
2766 * Returns description of method parameters
2768 * @return external_function_parameters
2769 * @since 3.1
2771 public static function delete_message_parameters() {
2772 return new external_function_parameters(
2773 array(
2774 'messageid' => new external_value(PARAM_INT, 'The message id'),
2775 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2776 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2782 * Deletes a message
2784 * @param int $messageid the message id
2785 * @param int $userid the user id of who we want to delete the message for
2786 * @param bool $read if is a message read (default to true)
2787 * @return \core_external\external_description
2788 * @throws moodle_exception
2789 * @since 3.1
2791 public static function delete_message($messageid, $userid, $read = true) {
2792 global $CFG;
2794 // Check if private messaging between users is allowed.
2795 if (empty($CFG->messaging)) {
2796 throw new moodle_exception('disabled', 'message');
2799 // Warnings array, it can be empty at the end but is mandatory.
2800 $warnings = array();
2802 // Validate params.
2803 $params = array(
2804 'messageid' => $messageid,
2805 'userid' => $userid,
2806 'read' => $read
2808 $params = self::validate_parameters(self::delete_message_parameters(), $params);
2810 // Validate context.
2811 $context = context_system::instance();
2812 self::validate_context($context);
2814 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2815 core_user::require_active_user($user);
2817 if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
2818 $status = \core_message\api::delete_message($user->id, $params['messageid']);
2819 } else {
2820 throw new moodle_exception('You do not have permission to delete this message');
2823 $results = array(
2824 'status' => $status,
2825 'warnings' => $warnings
2827 return $results;
2831 * Returns description of method result value
2833 * @return \core_external\external_description
2834 * @since 3.1
2836 public static function delete_message_returns() {
2837 return new external_single_structure(
2838 array(
2839 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2840 'warnings' => new external_warnings()
2846 * Returns description of method parameters
2848 * @return external_function_parameters
2849 * @since 3.2
2851 public static function message_processor_config_form_parameters() {
2852 return new external_function_parameters(
2853 array(
2854 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2855 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
2856 'formvalues' => new external_multiple_structure(
2857 new external_single_structure(
2858 array(
2859 'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2860 'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2863 'Config form values',
2864 VALUE_REQUIRED
2871 * Processes a message processor config form.
2873 * @param int $userid the user id
2874 * @param string $name the name of the processor
2875 * @param array $formvalues the form values
2876 * @return \core_external\external_description
2877 * @throws moodle_exception
2878 * @since 3.2
2880 public static function message_processor_config_form($userid, $name, $formvalues) {
2881 global $USER, $CFG;
2883 $params = self::validate_parameters(
2884 self::message_processor_config_form_parameters(),
2885 array(
2886 'userid' => $userid,
2887 'name' => $name,
2888 'formvalues' => $formvalues,
2892 $user = self::validate_preferences_permissions($params['userid']);
2894 $processor = get_message_processor($params['name']);
2895 $preferences = [];
2896 $form = new stdClass();
2898 foreach ($params['formvalues'] as $formvalue) {
2899 // Curly braces to ensure interpretation is consistent between
2900 // php 5 and php 7.
2901 $form->{$formvalue['name']} = $formvalue['value'];
2904 $processor->process_form($form, $preferences);
2906 if (!empty($preferences)) {
2907 set_user_preferences($preferences, $params['userid']);
2912 * Returns description of method result value
2914 * @return \core_external\external_description
2915 * @since 3.2
2917 public static function message_processor_config_form_returns() {
2918 return null;
2922 * Returns description of method parameters
2924 * @return external_function_parameters
2925 * @since 3.2
2927 public static function get_message_processor_parameters() {
2928 return new external_function_parameters(
2929 array(
2930 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2931 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
2937 * Get a message processor.
2939 * @param int $userid
2940 * @param string $name the name of the processor
2941 * @return \core_external\external_description
2942 * @throws moodle_exception
2943 * @since 3.2
2945 public static function get_message_processor($userid, $name) {
2946 global $USER, $PAGE, $CFG;
2948 // Check if messaging is enabled.
2949 if (empty($CFG->messaging)) {
2950 throw new moodle_exception('disabled', 'message');
2953 $params = self::validate_parameters(
2954 self::get_message_processor_parameters(),
2955 array(
2956 'userid' => $userid,
2957 'name' => $name,
2961 if (empty($params['userid'])) {
2962 $params['userid'] = $USER->id;
2965 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2966 core_user::require_active_user($user);
2967 self::validate_context(context_user::instance($params['userid']));
2969 $processor = get_message_processor($params['name']);
2971 $processoroutput = new \core_message\output\processor($processor, $user);
2972 $renderer = $PAGE->get_renderer('core_message');
2974 return $processoroutput->export_for_template($renderer);
2978 * Returns description of method result value
2980 * @return \core_external\external_description
2981 * @since 3.2
2983 public static function get_message_processor_returns() {
2984 return new external_function_parameters(
2985 array(
2986 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2987 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2993 * Check that the user has enough permission to retrieve message or notifications preferences.
2995 * @param int $userid the user id requesting the preferences
2996 * @return stdClass full user object
2997 * @throws moodle_exception
2998 * @since Moodle 3.2
3000 protected static function validate_preferences_permissions($userid) {
3001 global $USER;
3003 if (empty($userid)) {
3004 $user = $USER;
3005 } else {
3006 $user = core_user::get_user($userid, '*', MUST_EXIST);
3007 core_user::require_active_user($user);
3010 $systemcontext = context_system::instance();
3011 self::validate_context($systemcontext);
3013 // Check access control.
3014 if ($user->id == $USER->id) {
3015 // Editing own message profile.
3016 require_capability('moodle/user:editownmessageprofile', $systemcontext);
3017 } else {
3018 // Teachers, parents, etc.
3019 $personalcontext = context_user::instance($user->id);
3020 require_capability('moodle/user:editmessageprofile', $personalcontext);
3022 return $user;
3026 * Returns a notification or message preference structure.
3028 * @return external_single_structure the structure
3029 * @since Moodle 3.2
3030 * @todo Remove loggedin and loggedoff from processors structure on MDL-73284.
3032 protected static function get_preferences_structure() {
3033 return new external_single_structure(
3034 array(
3035 'userid' => new external_value(PARAM_INT, 'User id'),
3036 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3037 'processors' => new external_multiple_structure(
3038 new external_single_structure(
3039 array(
3040 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3041 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3042 'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3043 'contextid' => new external_value(PARAM_INT, 'Context id'),
3044 'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3047 'Config form values'
3049 'components' => new external_multiple_structure(
3050 new external_single_structure(
3051 array(
3052 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3053 'notifications' => new external_multiple_structure(
3054 new external_single_structure(
3055 array(
3056 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3057 'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3058 'processors' => new external_multiple_structure(
3059 new external_single_structure(
3060 array(
3061 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3062 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3063 'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3064 'lockedmessage' => new external_value(PARAM_TEXT,
3065 'Text to display if locked', VALUE_OPTIONAL),
3066 'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3067 'loggedin' => new external_single_structure(
3068 array(
3069 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3070 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3071 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3073 'DEPRECATED ATTRIBUTE -
3074 Kept for backward compatibility, use enabled instead.',
3076 'loggedoff' => new external_single_structure(
3077 array(
3078 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3079 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3080 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3082 'DEPRECATED ATTRIBUTE -
3083 Kept for backward compatibility, use enabled instead.',
3085 'enabled' => new external_value(PARAM_BOOL, 'Is enabled?'),
3088 'Processors values for this notification'
3092 'List of notificaitons for the component'
3096 'Available components'
3103 * Returns description of method parameters
3105 * @return external_function_parameters
3106 * @since 3.2
3108 public static function get_user_notification_preferences_parameters() {
3109 return new external_function_parameters(
3110 array(
3111 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3117 * Get the notification preferences for a given user.
3119 * @param int $userid id of the user, 0 for current user
3120 * @return \core_external\external_description
3121 * @throws moodle_exception
3122 * @since 3.2
3124 public static function get_user_notification_preferences($userid = 0) {
3125 global $PAGE;
3127 $params = self::validate_parameters(
3128 self::get_user_notification_preferences_parameters(),
3129 array(
3130 'userid' => $userid,
3133 $user = self::validate_preferences_permissions($params['userid']);
3135 $processors = get_message_processors();
3136 $providers = message_get_providers_for_user($user->id);
3137 $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3138 $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3140 $renderer = $PAGE->get_renderer('core_message');
3142 $result = array(
3143 'warnings' => array(),
3144 'preferences' => $notificationlist->export_for_template($renderer)
3146 return $result;
3150 * Returns description of method result value
3152 * @return \core_external\external_description
3153 * @since 3.2
3155 public static function get_user_notification_preferences_returns() {
3156 return new external_function_parameters(
3157 array(
3158 'preferences' => self::get_preferences_structure(),
3159 'warnings' => new external_warnings(),
3165 * Returns description of method parameters
3167 * @return external_function_parameters
3168 * @since 3.2
3170 public static function get_user_message_preferences_parameters() {
3171 return new external_function_parameters(
3172 array(
3173 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3179 * Get the notification preferences for a given user.
3181 * @param int $userid id of the user, 0 for current user
3182 * @return \core_external\external_description
3183 * @throws moodle_exception
3184 * @since 3.2
3186 public static function get_user_message_preferences($userid = 0) {
3187 global $CFG, $PAGE;
3189 $params = self::validate_parameters(
3190 self::get_user_message_preferences_parameters(),
3191 array(
3192 'userid' => $userid,
3196 $user = self::validate_preferences_permissions($params['userid']);
3198 // Filter out enabled, available system_configured and user_configured processors only.
3199 $readyprocessors = array_filter(get_message_processors(), function($processor) {
3200 return $processor->enabled &&
3201 $processor->configured &&
3202 $processor->object->is_user_configured() &&
3203 // Filter out processors that don't have and message preferences to configure.
3204 $processor->object->has_message_preferences();
3207 $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
3208 return $provider->component === 'moodle';
3210 $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
3211 $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
3212 $providers, $preferences, $user);
3214 $renderer = $PAGE->get_renderer('core_message');
3216 $entertosend = get_user_preferences('message_entertosend', $CFG->messagingdefaultpressenter, $user);
3218 $result = array(
3219 'warnings' => array(),
3220 'preferences' => $notificationlistoutput->export_for_template($renderer),
3221 'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id),
3222 'entertosend' => $entertosend
3224 return $result;
3228 * Returns description of method result value
3230 * @return \core_external\external_description
3231 * @since 3.2
3233 public static function get_user_message_preferences_returns() {
3234 return new external_function_parameters(
3235 array(
3236 'preferences' => self::get_preferences_structure(),
3237 'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'),
3238 'entertosend' => new external_value(PARAM_BOOL, 'User preference for using enter to send messages'),
3239 'warnings' => new external_warnings(),
3245 * Returns description of method parameters for the favourite_conversations() method.
3247 * @return external_function_parameters
3249 public static function set_favourite_conversations_parameters() {
3250 return new external_function_parameters(
3251 array(
3252 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3253 'conversations' => new external_multiple_structure(
3254 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3261 * Favourite a conversation, or list of conversations for a user.
3263 * @param int $userid the id of the user, or 0 for the current user.
3264 * @param array $conversationids the list of conversations ids to favourite.
3265 * @return array
3266 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3268 public static function set_favourite_conversations(int $userid, array $conversationids) {
3269 global $CFG, $USER;
3271 // All the business logic checks that really shouldn't be in here.
3272 if (empty($CFG->messaging)) {
3273 throw new moodle_exception('disabled', 'message');
3275 $params = [
3276 'userid' => $userid,
3277 'conversations' => $conversationids
3279 $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params);
3280 $systemcontext = context_system::instance();
3281 self::validate_context($systemcontext);
3283 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3284 throw new moodle_exception('You do not have permission to perform this action.');
3287 foreach ($params['conversations'] as $conversationid) {
3288 \core_message\api::set_favourite_conversation($conversationid, $params['userid']);
3291 return [];
3295 * Return a description of the returns for the create_user_favourite_conversations() method.
3297 * @return \core_external\external_description
3299 public static function set_favourite_conversations_returns() {
3300 return new external_warnings();
3304 * Returns description of method parameters for unfavourite_conversations() method.
3306 * @return external_function_parameters
3308 public static function unset_favourite_conversations_parameters() {
3309 return new external_function_parameters(
3310 array(
3311 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3312 'conversations' => new external_multiple_structure(
3313 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3320 * Unfavourite a conversation, or list of conversations for a user.
3322 * @param int $userid the id of the user, or 0 for the current user.
3323 * @param array $conversationids the list of conversations ids unset as favourites.
3324 * @return array
3325 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3327 public static function unset_favourite_conversations(int $userid, array $conversationids) {
3328 global $CFG, $USER;
3330 // All the business logic checks that really shouldn't be in here.
3331 if (empty($CFG->messaging)) {
3332 throw new moodle_exception('disabled', 'message');
3334 $params = [
3335 'userid' => $userid,
3336 'conversations' => $conversationids
3338 $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params);
3339 $systemcontext = context_system::instance();
3340 self::validate_context($systemcontext);
3342 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3343 throw new moodle_exception('You do not have permission to perform this action.');
3346 foreach ($params['conversations'] as $conversationid) {
3347 \core_message\api::unset_favourite_conversation($conversationid, $params['userid']);
3350 return [];
3354 * Unset favourite conversations return description.
3356 * @return \core_external\external_description
3358 public static function unset_favourite_conversations_returns() {
3359 return new external_warnings();
3363 * Returns description of method parameters for get_member_info() method.
3365 * @return external_function_parameters
3367 public static function get_member_info_parameters() {
3368 return new external_function_parameters(
3369 array(
3370 'referenceuserid' => new external_value(PARAM_INT, 'id of the user'),
3371 'userids' => new external_multiple_structure(
3372 new external_value(PARAM_INT, 'id of members to get')
3374 'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false),
3375 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'include privacy info in response', VALUE_DEFAULT, false)
3381 * Returns conversation member info for the supplied users, relative to the supplied referenceuserid.
3383 * This is the basic structure used when returning members, and includes information about the relationship between each member
3384 * and the referenceuser, such as a whether the referenceuser has marked the member as a contact, or has blocked them.
3386 * @param int $referenceuserid the id of the user which check contact and blocked status.
3387 * @param array $userids
3388 * @return array the array of objects containing member info.
3389 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3391 public static function get_member_info(
3392 int $referenceuserid,
3393 array $userids,
3394 bool $includecontactrequests = false,
3395 bool $includeprivacyinfo = false
3397 global $CFG, $USER;
3399 // All the business logic checks that really shouldn't be in here.
3400 if (empty($CFG->messaging)) {
3401 throw new moodle_exception('disabled', 'message');
3403 $params = [
3404 'referenceuserid' => $referenceuserid,
3405 'userids' => $userids,
3406 'includecontactrequests' => $includecontactrequests,
3407 'includeprivacyinfo' => $includeprivacyinfo
3409 $params = self::validate_parameters(self::get_member_info_parameters(), $params);
3410 $systemcontext = context_system::instance();
3411 self::validate_context($systemcontext);
3413 if (($USER->id != $referenceuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3414 throw new moodle_exception('You do not have permission to perform this action.');
3417 return \core_message\helper::get_member_info(
3418 $params['referenceuserid'],
3419 $params['userids'],
3420 $params['includecontactrequests'],
3421 $params['includeprivacyinfo']
3426 * Get member info return description.
3428 * @return \core_external\external_description
3430 public static function get_member_info_returns() {
3431 return new external_multiple_structure(
3432 self::get_conversation_member_structure()
3437 * Returns description of method parameters for get_conversation_counts() method.
3439 * @return external_function_parameters
3441 public static function get_conversation_counts_parameters() {
3442 return new external_function_parameters(
3444 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3450 * Returns an array of conversation counts for the various types of conversations, including favourites.
3452 * Return format:
3454 * 'favourites' => 0,
3455 * 'types' => [
3456 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3457 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3461 * @param int $userid the id of the user whose counts we are fetching.
3462 * @return array the array of conversation counts, indexed by type.
3463 * @throws moodle_exception if the current user cannot perform this action.
3465 public static function get_conversation_counts(int $userid) {
3466 global $CFG, $USER;
3468 // All the business logic checks that really shouldn't be in here.
3469 if (empty($CFG->messaging)) {
3470 throw new moodle_exception('disabled', 'message');
3473 if (empty($userid)) {
3474 $userid = $USER->id;
3477 $params = ['userid' => $userid];
3478 $params = self::validate_parameters(self::get_conversation_counts_parameters(), $params);
3480 $systemcontext = context_system::instance();
3481 self::validate_context($systemcontext);
3483 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3484 throw new moodle_exception('You do not have permission to perform this action.');
3487 return \core_message\api::get_conversation_counts($params['userid']);
3491 * Get conversation counts return description.
3493 * @return \core_external\external_description
3495 public static function get_conversation_counts_returns() {
3496 return new external_single_structure(
3498 'favourites' => new external_value(PARAM_INT, 'Total number of favourite conversations'),
3499 'types' => new external_single_structure(
3501 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3502 'Total number of individual conversations'),
3503 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3504 'Total number of group conversations'),
3505 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3506 'Total number of self conversations'),
3514 * Returns description of method parameters for get_unread_conversation_counts() method.
3516 * @return external_function_parameters
3518 public static function get_unread_conversation_counts_parameters() {
3519 return new external_function_parameters(
3521 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3527 * Returns an array of unread conversation counts for the various types of conversations, including favourites.
3529 * Return format:
3531 * 'favourites' => 0,
3532 * 'types' => [
3533 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3534 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3538 * @param int $userid the id of the user whose counts we are fetching.
3539 * @return array the array of unread conversation counts, indexed by type.
3540 * @throws moodle_exception if the current user cannot perform this action.
3542 public static function get_unread_conversation_counts(int $userid) {
3543 global $CFG, $USER;
3545 // All the business logic checks that really shouldn't be in here.
3546 if (empty($CFG->messaging)) {
3547 throw new moodle_exception('disabled', 'message');
3550 if (empty($userid)) {
3551 $userid = $USER->id;
3554 $params = ['userid' => $userid];
3555 $params = self::validate_parameters(self::get_unread_conversation_counts_parameters(), $params);
3557 $systemcontext = context_system::instance();
3558 self::validate_context($systemcontext);
3560 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3561 throw new moodle_exception('You do not have permission to perform this action.');
3564 return \core_message\api::get_unread_conversation_counts($params['userid']);
3568 * Get unread conversation counts return description.
3570 * @return \core_external\external_description
3572 public static function get_unread_conversation_counts_returns() {
3573 return new external_single_structure(
3575 'favourites' => new external_value(PARAM_INT, 'Total number of unread favourite conversations'),
3576 'types' => new external_single_structure(
3578 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3579 'Total number of unread individual conversations'),
3580 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3581 'Total number of unread group conversations'),
3582 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3583 'Total number of unread self conversations'),
3591 * Returns description of method parameters
3593 * @return external_function_parameters
3594 * @since 3.7
3596 public static function delete_message_for_all_users_parameters() {
3597 return new external_function_parameters(
3598 array(
3599 'messageid' => new external_value(PARAM_INT, 'The message id'),
3600 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users')
3605 * Deletes a message for all users
3607 * @param int $messageid the message id
3608 * @param int $userid the user id of who we want to delete the message for all users, is no longer used.
3609 * @return \core_external\external_description
3610 * @throws moodle_exception
3611 * @since 3.7
3613 public static function delete_message_for_all_users(int $messageid, int $userid) {
3614 global $CFG, $USER;
3616 // Check if private messaging between users is allowed.
3617 if (empty($CFG->messaging)) {
3618 throw new moodle_exception('disabled', 'message');
3621 // Validate params.
3622 $params = array(
3623 'messageid' => $messageid,
3624 'userid' => $userid
3626 $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params);
3628 // Validate context.
3629 $context = context_system::instance();
3630 self::validate_context($context);
3632 core_user::require_active_user($USER);
3634 // Checks if a user can delete a message for all users.
3635 if (core_message\api::can_delete_message_for_all_users($USER->id, $params['messageid'])) {
3636 \core_message\api::delete_message_for_all_users($params['messageid']);
3637 } else {
3638 throw new moodle_exception('You do not have permission to delete this message for everyone.');
3641 return [];
3644 * Returns description of method result value
3646 * @return \core_external\external_description
3647 * @since 3.7
3649 public static function delete_message_for_all_users_returns() {
3650 return new external_warnings();