Merge branch 'MDL-77559-311-2' of https://github.com/andrewnicols/moodle into MOODLE_...
[moodle.git] / message / externallib.php
blob84e251a60626b3afc4d360061a958e9379d53671
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * External message API
21 * @package core_message
22 * @category external
23 * @copyright 2011 Jerome Mouneyrac
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 defined('MOODLE_INTERNAL') || die();
29 require_once("$CFG->libdir/externallib.php");
30 require_once($CFG->dirroot . "/message/lib.php");
32 /**
33 * Message external functions
35 * @package core_message
36 * @category external
37 * @copyright 2011 Jerome Mouneyrac
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 * @since Moodle 2.2
41 class core_message_external extends external_api {
42 /**
43 * Returns description of method parameters
45 * @return external_function_parameters
46 * @since Moodle 3.6
48 public static function send_messages_to_conversation_parameters() {
49 return new external_function_parameters(
50 array(
51 'conversationid' => new external_value(PARAM_INT, 'id of the conversation'),
52 'messages' => new external_multiple_structure(
53 new external_single_structure(
54 array(
55 'text' => new external_value(PARAM_RAW, 'the text of the message'),
56 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
64 /**
65 * Send messages from the current USER to a conversation.
67 * This conversation may be any type of conversation, individual or group.
69 * @param int $conversationid the id of the conversation to which the messages will be sent.
70 * @param array $messages An array of message to send.
71 * @return array the array of messages which were sent (created).
72 * @since Moodle 3.6
74 public static function send_messages_to_conversation(int $conversationid, array $messages = []) {
75 global $CFG, $USER;
77 // Check if messaging is enabled.
78 if (empty($CFG->messaging)) {
79 throw new moodle_exception('disabled', 'message');
82 // Ensure the current user is allowed to run this function.
83 $context = context_system::instance();
84 self::validate_context($context);
86 $params = self::validate_parameters(self::send_messages_to_conversation_parameters(), [
87 'conversationid' => $conversationid,
88 'messages' => $messages
89 ]);
91 // Validate messages content before posting them.
92 foreach ($params['messages'] as $message) {
93 // Check message length.
94 if (strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
95 throw new moodle_exception('errormessagetoolong', 'message');
99 $messages = [];
100 foreach ($params['messages'] as $message) {
101 $createdmessage = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
102 $message['textformat']);
103 $createdmessage->text = message_format_message_text((object) [
104 'smallmessage' => $createdmessage->text,
105 'fullmessageformat' => external_validate_format($message['textformat']),
106 'fullmessagetrust' => $createdmessage->fullmessagetrust
108 $messages[] = $createdmessage;
111 return $messages;
115 * Returns description of method result value.
117 * @return external_description
118 * @since Moodle 3.6
120 public static function send_messages_to_conversation_returns() {
121 return new external_multiple_structure(
122 self::get_conversation_message_structure()
128 * Returns description of method parameters
130 * @return external_function_parameters
131 * @since Moodle 2.2
133 public static function send_instant_messages_parameters() {
134 return new external_function_parameters(
135 array(
136 'messages' => new external_multiple_structure(
137 new external_single_structure(
138 array(
139 'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
140 'text' => new external_value(PARAM_RAW, 'the text of the message'),
141 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
142 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the message. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL),
151 * Send private messages from the current USER to other users
153 * @param array $messages An array of message to send.
154 * @return array
155 * @since Moodle 2.2
157 public static function send_instant_messages($messages = array()) {
158 global $CFG, $USER, $DB;
160 // Check if messaging is enabled.
161 if (empty($CFG->messaging)) {
162 throw new moodle_exception('disabled', 'message');
165 // Ensure the current user is allowed to run this function
166 $context = context_system::instance();
167 self::validate_context($context);
168 require_capability('moodle/site:sendmessage', $context);
170 // Ensure the current user is allowed to delete message for everyone.
171 $candeletemessagesforallusers = has_capability('moodle/site:deleteanymessage', $context);
173 $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
175 //retrieve all tousers of the messages
176 $receivers = array();
177 foreach($params['messages'] as $message) {
178 $receivers[] = $message['touserid'];
180 list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
181 $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
183 $resultmessages = array();
184 $messageids = array();
185 foreach ($params['messages'] as $message) {
186 $resultmsg = array(); //the infos about the success of the operation
188 // We are going to do some checking.
189 // Code should match /messages/index.php checks.
190 $success = true;
192 // Check the user exists.
193 if (empty($tousers[$message['touserid']])) {
194 $success = false;
195 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
198 // Check message length.
199 if ($success && strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
200 $success = false;
201 $errormessage = get_string('errormessagetoolong', 'message');
204 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
205 // Check if the recipient can be messaged by the sender.
206 if ($success && !\core_message\api::can_send_message($tousers[$message['touserid']]->id, $USER->id)) {
207 $success = false;
208 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
211 // Now we can send the message (at least try).
212 if ($success) {
213 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
214 $success = message_post_message($USER, $tousers[$message['touserid']],
215 $message['text'], external_validate_format($message['textformat']));
218 // Build the resultmsg.
219 if (isset($message['clientmsgid'])) {
220 $resultmsg['clientmsgid'] = $message['clientmsgid'];
222 if ($success) {
223 $resultmsg['msgid'] = $success;
224 $resultmsg['timecreated'] = time();
225 $resultmsg['candeletemessagesforallusers'] = $candeletemessagesforallusers;
226 $messageids[] = $success;
227 } else {
228 // WARNINGS: for backward compatibility we return this errormessage.
229 // We should have thrown exceptions as these errors prevent results to be returned.
230 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
231 $resultmsg['msgid'] = -1;
232 if (!isset($errormessage)) { // Nobody has set a message error or thrown an exception, let's set it.
233 $errormessage = get_string('messageundeliveredbynotificationsettings', 'error');
235 $resultmsg['errormessage'] = $errormessage;
238 $resultmessages[] = $resultmsg;
241 if (!empty($messageids)) {
242 $messagerecords = $DB->get_records_list(
243 'messages',
244 'id',
245 $messageids,
247 'id, conversationid, smallmessage, fullmessageformat, fullmessagetrust');
248 $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) {
249 $id = $resultmessage['msgid'];
250 $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null;
251 $resultmessage['useridfrom'] = $USER->id;
252 $resultmessage['text'] = message_format_message_text((object) [
253 'smallmessage' => $messagerecords[$id]->smallmessage,
254 'fullmessageformat' => external_validate_format($messagerecords[$id]->fullmessageformat),
255 'fullmessagetrust' => $messagerecords[$id]->fullmessagetrust
257 return $resultmessage;
258 }, $resultmessages);
261 return $resultmessages;
265 * Returns description of method result value
267 * @return external_description
268 * @since Moodle 2.2
270 public static function send_instant_messages_returns() {
271 return new external_multiple_structure(
272 new external_single_structure(
273 array(
274 'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds: id of the created message if it succeeded, -1 when failed'),
275 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
276 'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL),
277 'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL),
278 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
279 'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
280 'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
281 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
282 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
289 * Delete contacts parameters description.
291 * @return external_function_parameters
292 * @since Moodle 2.5
294 public static function delete_contacts_parameters() {
295 return new external_function_parameters(
296 array(
297 'userids' => new external_multiple_structure(
298 new external_value(PARAM_INT, 'User ID'),
299 'List of user IDs'
301 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
302 current user', VALUE_DEFAULT, 0)
308 * Delete contacts.
310 * @param array $userids array of user IDs.
311 * @param int $userid The id of the user we are deleting the contacts for
312 * @return null
313 * @since Moodle 2.5
315 public static function delete_contacts($userids, $userid = 0) {
316 global $CFG, $USER;
318 // Check if messaging is enabled.
319 if (empty($CFG->messaging)) {
320 throw new moodle_exception('disabled', 'message');
323 if (empty($userid)) {
324 $userid = $USER->id;
327 // Validate context.
328 $context = context_system::instance();
329 self::validate_context($context);
331 $params = array('userids' => $userids, 'userid' => $userid);
332 $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
334 $capability = 'moodle/site:manageallmessaging';
335 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
336 throw new required_capability_exception($context, $capability, 'nopermissions', '');
339 foreach ($params['userids'] as $id) {
340 \core_message\api::remove_contact($params['userid'], $id);
343 return null;
347 * Delete contacts return description.
349 * @return external_description
350 * @since Moodle 2.5
352 public static function delete_contacts_returns() {
353 return null;
357 * Mute conversations parameters description.
359 * @return external_function_parameters
361 public static function mute_conversations_parameters() {
362 return new external_function_parameters(
364 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
365 'conversationids' => new external_multiple_structure(
366 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
373 * Mutes conversations.
375 * @param int $userid The id of the user who is blocking
376 * @param array $conversationids The list of conversations being muted
377 * @return external_description
379 public static function mute_conversations(int $userid, array $conversationids) {
380 global $CFG, $USER;
382 // Check if messaging is enabled.
383 if (empty($CFG->messaging)) {
384 throw new moodle_exception('disabled', 'message');
387 // Validate context.
388 $context = context_system::instance();
389 self::validate_context($context);
391 $params = ['userid' => $userid, 'conversationids' => $conversationids];
392 $params = self::validate_parameters(self::mute_conversations_parameters(), $params);
394 $capability = 'moodle/site:manageallmessaging';
395 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
396 throw new required_capability_exception($context, $capability, 'nopermissions', '');
399 foreach ($params['conversationids'] as $conversationid) {
400 if (!\core_message\api::is_conversation_muted($params['userid'], $conversationid)) {
401 \core_message\api::mute_conversation($params['userid'], $conversationid);
405 return [];
409 * Mute conversations return description.
411 * @return external_description
413 public static function mute_conversations_returns() {
414 return new external_warnings();
418 * Unmute conversations parameters description.
420 * @return external_function_parameters
422 public static function unmute_conversations_parameters() {
423 return new external_function_parameters(
425 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
426 'conversationids' => new external_multiple_structure(
427 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
434 * Unmute conversations.
436 * @param int $userid The id of the user who is unblocking
437 * @param array $conversationids The list of conversations being muted
439 public static function unmute_conversations(int $userid, array $conversationids) {
440 global $CFG, $USER;
442 // Check if messaging is enabled.
443 if (empty($CFG->messaging)) {
444 throw new moodle_exception('disabled', 'message');
447 // Validate context.
448 $context = context_system::instance();
449 self::validate_context($context);
451 $params = ['userid' => $userid, 'conversationids' => $conversationids];
452 $params = self::validate_parameters(self::unmute_conversations_parameters(), $params);
454 $capability = 'moodle/site:manageallmessaging';
455 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
456 throw new required_capability_exception($context, $capability, 'nopermissions', '');
459 foreach ($params['conversationids'] as $conversationid) {
460 \core_message\api::unmute_conversation($params['userid'], $conversationid);
463 return [];
467 * Unmute conversations return description.
469 * @return external_description
471 public static function unmute_conversations_returns() {
472 return new external_warnings();
476 * Block user parameters description.
478 * @return external_function_parameters
480 public static function block_user_parameters() {
481 return new external_function_parameters(
483 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
484 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
490 * Blocks a user.
492 * @param int $userid The id of the user who is blocking
493 * @param int $blockeduserid The id of the user being blocked
494 * @return external_description
496 public static function block_user(int $userid, int $blockeduserid) {
497 global $CFG, $USER;
499 // Check if messaging is enabled.
500 if (empty($CFG->messaging)) {
501 throw new moodle_exception('disabled', 'message');
504 // Validate context.
505 $context = context_system::instance();
506 self::validate_context($context);
508 $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
509 $params = self::validate_parameters(self::block_user_parameters(), $params);
511 $capability = 'moodle/site:manageallmessaging';
512 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
513 throw new required_capability_exception($context, $capability, 'nopermissions', '');
516 // If the blocking is going to be useless then don't do it.
517 if (\core_message\api::can_send_message($userid, $blockeduserid, true)) {
518 return [];
521 if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
522 \core_message\api::block_user($params['userid'], $params['blockeduserid']);
525 return [];
529 * Block user return description.
531 * @return external_description
533 public static function block_user_returns() {
534 return new external_warnings();
538 * Unblock user parameters description.
540 * @return external_function_parameters
542 public static function unblock_user_parameters() {
543 return new external_function_parameters(
545 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
546 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
552 * Unblock user.
554 * @param int $userid The id of the user who is unblocking
555 * @param int $unblockeduserid The id of the user being unblocked
557 public static function unblock_user(int $userid, int $unblockeduserid) {
558 global $CFG, $USER;
560 // Check if messaging is enabled.
561 if (empty($CFG->messaging)) {
562 throw new moodle_exception('disabled', 'message');
565 // Validate context.
566 $context = context_system::instance();
567 self::validate_context($context);
569 $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
570 $params = self::validate_parameters(self::unblock_user_parameters(), $params);
572 $capability = 'moodle/site:manageallmessaging';
573 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
574 throw new required_capability_exception($context, $capability, 'nopermissions', '');
577 \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
579 return [];
583 * Unblock user return description.
585 * @return external_description
587 public static function unblock_user_returns() {
588 return new external_warnings();
592 * Returns contact requests parameters description.
594 * @return external_function_parameters
596 public static function get_contact_requests_parameters() {
597 return new external_function_parameters(
599 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
600 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
601 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
607 * Handles returning the contact requests for a user.
609 * This also includes the user data necessary to display information
610 * about the user.
612 * It will not include blocked users.
614 * @param int $userid The id of the user we want to get the contact requests for
615 * @param int $limitfrom
616 * @param int $limitnum
618 public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
619 global $CFG, $USER;
621 // Check if messaging is enabled.
622 if (empty($CFG->messaging)) {
623 throw new moodle_exception('disabled', 'message');
626 // Validate context.
627 $context = context_system::instance();
628 self::validate_context($context);
630 $params = [
631 'userid' => $userid,
632 'limitfrom' => $limitfrom,
633 'limitnum' => $limitnum
635 $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
637 $capability = 'moodle/site:manageallmessaging';
638 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
639 throw new required_capability_exception($context, $capability, 'nopermissions', '');
642 return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
646 * Returns the contact requests return description.
648 * @return external_description
650 public static function get_contact_requests_returns() {
651 return new external_multiple_structure(
652 self::get_conversation_member_structure()
657 * Returns the number of contact requests the user has received parameters description.
659 * @return external_function_parameters
661 public static function get_received_contact_requests_count_parameters() {
662 return new external_function_parameters(
663 array(
664 'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' .
665 'received contact requests for', VALUE_REQUIRED),
671 * Returns the number of contact requests the user has received.
673 * @param int $userid The ID of the user we want to return the number of received contact requests for
674 * @return external_value
676 public static function get_received_contact_requests_count(int $userid) {
677 global $CFG, $USER;
679 // Check if messaging is enabled.
680 if (empty($CFG->messaging)) {
681 throw new moodle_exception('disabled', 'message');
684 // Validate context.
685 $context = context_system::instance();
686 self::validate_context($context);
688 $params = [
689 'userid' => $userid,
691 $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params);
693 $capability = 'moodle/site:manageallmessaging';
694 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
695 throw new required_capability_exception($context, $capability, 'nopermissions', '');
698 return \core_message\api::get_received_contact_requests_count($params['userid']);
702 * Returns the number of contact requests the user has received return description.
704 * @return external_value
706 public static function get_received_contact_requests_count_returns() {
707 return new external_value(PARAM_INT, 'The number of received contact requests');
711 * Returns get conversation members parameters description.
713 * @return external_function_parameters
715 public static function get_conversation_members_parameters() {
716 return new external_function_parameters(
718 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
719 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
720 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
721 VALUE_DEFAULT, false),
722 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?',
723 VALUE_DEFAULT, false),
724 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
725 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
731 * Returns a list of conversation members.
733 * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
734 * @param int $conversationid The id of the conversation
735 * @param bool $includecontactrequests Do we want to include contact requests with this data?
736 * @param bool $includeprivacyinfo Do we want to include privacy info?
737 * @param int $limitfrom
738 * @param int $limitnum
739 * @return array
741 public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
742 bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) {
743 global $CFG, $USER;
745 // Check if messaging is enabled.
746 if (empty($CFG->messaging)) {
747 throw new moodle_exception('disabled', 'message');
750 // Validate context.
751 $context = context_system::instance();
752 self::validate_context($context);
754 $params = [
755 'userid' => $userid,
756 'conversationid' => $conversationid,
757 'includecontactrequests' => $includecontactrequests,
758 'includeprivacyinfo' => $includeprivacyinfo,
759 'limitfrom' => $limitfrom,
760 'limitnum' => $limitnum
762 $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
764 $capability = 'moodle/site:manageallmessaging';
765 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
766 throw new required_capability_exception($context, $capability, 'nopermissions', '');
769 // The user needs to be a part of the conversation before querying who the members are.
770 if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
771 throw new moodle_exception('You are not a member of this conversation.');
774 return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
775 $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']);
779 * Returns the get conversation members return description.
781 * @return external_description
783 public static function get_conversation_members_returns() {
784 return new external_multiple_structure(
785 self::get_conversation_member_structure()
790 * Creates a contact request parameters description.
792 * @return external_function_parameters
794 public static function create_contact_request_parameters() {
795 return new external_function_parameters(
797 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
798 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
804 * Creates a contact request.
806 * @param int $userid The id of the user who is creating the contact request
807 * @param int $requesteduserid The id of the user being requested
809 public static function create_contact_request(int $userid, int $requesteduserid) {
810 global $CFG, $USER;
812 // Check if messaging is enabled.
813 if (empty($CFG->messaging)) {
814 throw new moodle_exception('disabled', 'message');
817 // Validate context.
818 $context = context_system::instance();
819 self::validate_context($context);
821 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
822 $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
824 $capability = 'moodle/site:manageallmessaging';
825 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
826 throw new required_capability_exception($context, $capability, 'nopermissions', '');
829 $result = [
830 'warnings' => []
833 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
834 $result['warnings'][] = [
835 'item' => 'user',
836 'itemid' => $params['requesteduserid'],
837 'warningcode' => 'cannotcreatecontactrequest',
838 'message' => 'You are unable to create a contact request for this user'
840 } else {
841 if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
842 // There should only ever be one but just in case there are multiple then we can return the first.
843 $result['request'] = array_shift($requests);
844 } else {
845 $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
849 return $result;
853 * Creates a contact request return description.
855 * @return external_description
857 public static function create_contact_request_returns() {
858 return new external_single_structure(
859 array(
860 'request' => new external_single_structure(
861 array(
862 'id' => new external_value(PARAM_INT, 'Message id'),
863 'userid' => new external_value(PARAM_INT, 'User from id'),
864 'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
865 'timecreated' => new external_value(PARAM_INT, 'Time created'),
867 'request record',
868 VALUE_OPTIONAL
870 'warnings' => new external_warnings()
876 * Confirm a contact request parameters description.
878 * @return external_function_parameters
880 public static function confirm_contact_request_parameters() {
881 return new external_function_parameters(
883 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
884 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
890 * Confirm a contact request.
892 * @param int $userid The id of the user who is creating the contact request
893 * @param int $requesteduserid The id of the user being requested
895 public static function confirm_contact_request(int $userid, int $requesteduserid) {
896 global $CFG, $USER;
898 // Check if messaging is enabled.
899 if (empty($CFG->messaging)) {
900 throw new moodle_exception('disabled', 'message');
903 // Validate context.
904 $context = context_system::instance();
905 self::validate_context($context);
907 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
908 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
910 $capability = 'moodle/site:manageallmessaging';
911 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
912 throw new required_capability_exception($context, $capability, 'nopermissions', '');
915 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
917 return [];
921 * Confirm a contact request return description.
923 * @return external_description
925 public static function confirm_contact_request_returns() {
926 return new external_warnings();
930 * Declines a contact request parameters description.
932 * @return external_function_parameters
934 public static function decline_contact_request_parameters() {
935 return new external_function_parameters(
937 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
938 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
944 * Declines a contact request.
946 * @param int $userid The id of the user who is creating the contact request
947 * @param int $requesteduserid The id of the user being requested
949 public static function decline_contact_request(int $userid, int $requesteduserid) {
950 global $CFG, $USER;
952 // Check if messaging is enabled.
953 if (empty($CFG->messaging)) {
954 throw new moodle_exception('disabled', 'message');
957 // Validate context.
958 $context = context_system::instance();
959 self::validate_context($context);
961 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
962 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
964 $capability = 'moodle/site:manageallmessaging';
965 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
966 throw new required_capability_exception($context, $capability, 'nopermissions', '');
969 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
971 return [];
975 * Declines a contact request return description.
977 * @return external_description
979 public static function decline_contact_request_returns() {
980 return new external_warnings();
984 * Return the structure of a message area contact.
986 * @return external_single_structure
987 * @since Moodle 3.2
989 private static function get_messagearea_contact_structure() {
990 return new external_single_structure(
991 array(
992 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
993 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
994 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
995 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
996 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
997 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
998 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
999 'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null),
1000 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
1001 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1002 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1003 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
1004 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1005 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1006 VALUE_DEFAULT, null),
1007 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null),
1013 * Return the structure of a conversation.
1015 * @return external_single_structure
1016 * @since Moodle 3.6
1018 private static function get_conversation_structure() {
1019 return new external_single_structure(
1020 array(
1021 'id' => new external_value(PARAM_INT, 'The conversation id'),
1022 'name' => new external_value(PARAM_RAW, 'The conversation name, if set', VALUE_DEFAULT, null),
1023 'subname' => new external_value(PARAM_RAW, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1024 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1025 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group,3=self)'),
1026 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1027 'ismuted' => new external_value(PARAM_BOOL, 'If the user muted this conversation'),
1028 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this conversation as a favourite'),
1029 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1030 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1031 VALUE_DEFAULT, null),
1032 'members' => new external_multiple_structure(
1033 self::get_conversation_member_structure()
1035 'messages' => new external_multiple_structure(
1036 self::get_conversation_message_structure()
1038 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
1039 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
1045 * Return the structure of a conversation member.
1047 * @return external_single_structure
1048 * @since Moodle 3.6
1050 private static function get_conversation_member_structure() {
1051 $result = [
1052 'id' => new external_value(PARAM_INT, 'The user id'),
1053 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1054 'profileurl' => new external_value(PARAM_URL, 'The link to the user\'s profile page'),
1055 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1056 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1057 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1058 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1059 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1060 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1061 'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1062 'canmessageevenifblocked' => new external_value(PARAM_BOOL,
1063 'If the user can still message even if they get blocked'),
1064 'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1065 'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1068 $result['contactrequests'] = new external_multiple_structure(
1069 new external_single_structure(
1071 'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1072 'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1073 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1074 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1076 ), 'The contact requests', VALUE_OPTIONAL
1079 $result['conversations'] = new external_multiple_structure(new external_single_structure(
1080 array(
1081 'id' => new external_value(PARAM_INT, 'Conversations id'),
1082 'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1083 'name' => new external_value(PARAM_RAW, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1084 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1085 ), 'information about conversation', VALUE_OPTIONAL),
1086 'Conversations between users', VALUE_OPTIONAL
1089 return new external_single_structure(
1090 $result
1095 * Return the structure of a message area message.
1097 * @return external_single_structure
1098 * @since Moodle 3.6
1100 private static function get_conversation_message_structure() {
1101 return new external_single_structure(
1102 array(
1103 'id' => new external_value(PARAM_INT, 'The id of the message'),
1104 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1105 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1106 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1112 * Get messagearea message search users parameters.
1114 * @return external_function_parameters
1115 * @since 3.6
1117 public static function message_search_users_parameters() {
1118 return new external_function_parameters(
1119 array(
1120 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1121 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1122 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1123 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1129 * Get search users results.
1131 * @param int $userid The id of the user who is performing the search
1132 * @param string $search The string being searched
1133 * @param int $limitfrom
1134 * @param int $limitnum
1135 * @return array
1136 * @throws moodle_exception
1137 * @since 3.6
1139 public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1140 global $USER;
1142 $systemcontext = context_system::instance();
1144 $params = array(
1145 'userid' => $userid,
1146 'search' => $search,
1147 'limitfrom' => $limitfrom,
1148 'limitnum' => $limitnum
1150 $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1151 self::validate_context($systemcontext);
1153 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1154 throw new moodle_exception('You do not have permission to perform this action.');
1157 list($contacts, $noncontacts) = \core_message\api::message_search_users(
1158 $params['userid'],
1159 $params['search'],
1160 $params['limitfrom'],
1161 $params['limitnum']);
1163 return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1167 * Get messagearea message search users returns.
1169 * @return external_single_structure
1170 * @since 3.2
1172 public static function message_search_users_returns() {
1173 return new external_single_structure(
1174 array(
1175 'contacts' => new external_multiple_structure(
1176 self::get_conversation_member_structure()
1178 'noncontacts' => new external_multiple_structure(
1179 self::get_conversation_member_structure()
1186 * Get messagearea search messages parameters.
1188 * @return external_function_parameters
1189 * @since 3.2
1191 public static function data_for_messagearea_search_messages_parameters() {
1192 return new external_function_parameters(
1193 array(
1194 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1195 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1196 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1197 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1203 * Get messagearea search messages results.
1205 * @param int $userid The id of the user who is performing the search
1206 * @param string $search The string being searched
1207 * @param int $limitfrom
1208 * @param int $limitnum
1209 * @return stdClass
1210 * @throws moodle_exception
1211 * @since 3.2
1213 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1214 global $CFG, $USER;
1216 // Check if messaging is enabled.
1217 if (empty($CFG->messaging)) {
1218 throw new moodle_exception('disabled', 'message');
1221 $systemcontext = context_system::instance();
1223 $params = array(
1224 'userid' => $userid,
1225 'search' => $search,
1226 'limitfrom' => $limitfrom,
1227 'limitnum' => $limitnum
1230 $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1231 self::validate_context($systemcontext);
1233 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1234 throw new moodle_exception('You do not have permission to perform this action.');
1237 $messages = \core_message\api::search_messages(
1238 $params['userid'],
1239 $params['search'],
1240 $params['limitfrom'],
1241 $params['limitnum']
1244 $data = new \stdClass();
1245 $data->contacts = [];
1246 foreach ($messages as $message) {
1247 $contact = new \stdClass();
1248 $contact->userid = $message->userid;
1249 $contact->fullname = $message->fullname;
1250 $contact->profileimageurl = $message->profileimageurl;
1251 $contact->profileimageurlsmall = $message->profileimageurlsmall;
1252 $contact->messageid = $message->messageid;
1253 $contact->ismessaging = $message->ismessaging;
1254 $contact->sentfromcurrentuser = false;
1255 if ($message->lastmessage) {
1256 if ($message->userid !== $message->useridfrom) {
1257 $contact->sentfromcurrentuser = true;
1259 $contact->lastmessage = shorten_text($message->lastmessage, 60);
1260 } else {
1261 $contact->lastmessage = null;
1263 $contact->lastmessagedate = $message->lastmessagedate;
1264 $contact->showonlinestatus = is_null($message->isonline) ? false : true;
1265 $contact->isonline = $message->isonline;
1266 $contact->isblocked = $message->isblocked;
1267 $contact->isread = $message->isread;
1268 $contact->unreadcount = $message->unreadcount;
1269 $contact->conversationid = $message->conversationid;
1271 $data->contacts[] = $contact;
1274 return $data;
1278 * Get messagearea search messages returns.
1280 * @return external_single_structure
1281 * @since 3.2
1283 public static function data_for_messagearea_search_messages_returns() {
1284 return new external_single_structure(
1285 array(
1286 'contacts' => new external_multiple_structure(
1287 self::get_messagearea_contact_structure()
1294 * Get conversations parameters.
1296 * @return external_function_parameters
1297 * @since 3.6
1299 public static function get_conversations_parameters() {
1300 return new external_function_parameters(
1301 array(
1302 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1303 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1304 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1305 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1306 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1307 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1308 VALUE_DEFAULT, null),
1309 'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private
1310 conversations (false) when private conversations are requested.',
1311 VALUE_DEFAULT, false),
1317 * Get the list of conversations for the user.
1319 * @param int $userid The id of the user who is performing the search
1320 * @param int $limitfrom
1321 * @param int $limitnum
1322 * @param int|null $type
1323 * @param bool|null $favourites
1324 * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false)
1325 * when private conversations are requested.
1326 * @return stdClass
1327 * @throws \moodle_exception if the messaging feature is disabled on the site.
1328 * @since 3.2
1330 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null,
1331 bool $mergeself = false) {
1332 global $CFG, $USER;
1334 // All the standard BL checks.
1335 if (empty($CFG->messaging)) {
1336 throw new moodle_exception('disabled', 'message');
1339 $params = array(
1340 'userid' => $userid,
1341 'limitfrom' => $limitfrom,
1342 'limitnum' => $limitnum,
1343 'type' => $type,
1344 'favourites' => $favourites,
1345 'mergeself' => $mergeself
1347 $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1349 $systemcontext = context_system::instance();
1350 self::validate_context($systemcontext);
1352 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1353 throw new moodle_exception('You do not have permission to perform this action.');
1356 $conversations = \core_message\api::get_conversations(
1357 $params['userid'],
1358 $params['limitfrom'],
1359 $params['limitnum'],
1360 $params['type'],
1361 $params['favourites'],
1362 $params['mergeself']
1365 return (object) ['conversations' => $conversations];
1369 * Get conversations returns.
1371 * @return external_single_structure
1372 * @since 3.6
1374 public static function get_conversations_returns() {
1375 return new external_single_structure(
1377 'conversations' => new external_multiple_structure(
1378 self::get_conversation_structure(true)
1385 * Get conversation parameters.
1387 * @return external_function_parameters
1389 public static function get_conversation_parameters() {
1390 return new external_function_parameters(
1391 array(
1392 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1393 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1394 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1395 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1396 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1397 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1398 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1399 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1400 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1406 * Get a single conversation.
1408 * @param int $userid The user id to get the conversation for
1409 * @param int $conversationid The id of the conversation to fetch
1410 * @param bool $includecontactrequests Should contact requests be included between members
1411 * @param bool $includeprivacyinfo Should privacy info be included between members
1412 * @param int $memberlimit Limit number of members to load
1413 * @param int $memberoffset Offset members by this amount
1414 * @param int $messagelimit Limit number of messages to load
1415 * @param int $messageoffset Offset the messages
1416 * @param bool $newestmessagesfirst Order messages by newest first
1417 * @return stdClass
1418 * @throws \moodle_exception if the messaging feature is disabled on the site.
1420 public static function get_conversation(
1421 int $userid,
1422 int $conversationid,
1423 bool $includecontactrequests = false,
1424 bool $includeprivacyinfo = false,
1425 int $memberlimit = 0,
1426 int $memberoffset = 0,
1427 int $messagelimit = 0,
1428 int $messageoffset = 0,
1429 bool $newestmessagesfirst = true
1431 global $CFG, $DB, $USER;
1433 // All the standard BL checks.
1434 if (empty($CFG->messaging)) {
1435 throw new moodle_exception('disabled', 'message');
1438 $params = [
1439 'userid' => $userid,
1440 'conversationid' => $conversationid,
1441 'includecontactrequests' => $includecontactrequests,
1442 'includeprivacyinfo' => $includeprivacyinfo,
1443 'memberlimit' => $memberlimit,
1444 'memberoffset' => $memberoffset,
1445 'messagelimit' => $messagelimit,
1446 'messageoffset' => $messageoffset,
1447 'newestmessagesfirst' => $newestmessagesfirst
1449 self::validate_parameters(self::get_conversation_parameters(), $params);
1451 $systemcontext = context_system::instance();
1452 self::validate_context($systemcontext);
1454 $conversation = \core_message\api::get_conversation(
1455 $params['userid'],
1456 $params['conversationid'],
1457 $params['includecontactrequests'],
1458 $params['includeprivacyinfo'],
1459 $params['memberlimit'],
1460 $params['memberoffset'],
1461 $params['messagelimit'],
1462 $params['messageoffset'],
1463 $params['newestmessagesfirst']
1466 if ($conversation) {
1467 return $conversation;
1468 } else {
1469 // We have to throw an exception here because the external functions annoyingly
1470 // don't accept null to be returned for a single structure.
1471 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1476 * Get conversation returns.
1478 * @return external_single_structure
1480 public static function get_conversation_returns() {
1481 return self::get_conversation_structure();
1485 * Get conversation parameters.
1487 * @return external_function_parameters
1489 public static function get_conversation_between_users_parameters() {
1490 return new external_function_parameters(
1491 array(
1492 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1493 'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1494 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1495 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1496 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1497 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1498 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1499 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1500 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1506 * Get a single conversation between users.
1508 * @param int $userid The user id to get the conversation for
1509 * @param int $otheruserid The other user id
1510 * @param bool $includecontactrequests Should contact requests be included between members
1511 * @param bool $includeprivacyinfo Should privacy info be included between members
1512 * @param int $memberlimit Limit number of members to load
1513 * @param int $memberoffset Offset members by this amount
1514 * @param int $messagelimit Limit number of messages to load
1515 * @param int $messageoffset Offset the messages
1516 * @param bool $newestmessagesfirst Order messages by newest first
1517 * @return stdClass
1518 * @throws \moodle_exception if the messaging feature is disabled on the site.
1520 public static function get_conversation_between_users(
1521 int $userid,
1522 int $otheruserid,
1523 bool $includecontactrequests = false,
1524 bool $includeprivacyinfo = false,
1525 int $memberlimit = 0,
1526 int $memberoffset = 0,
1527 int $messagelimit = 0,
1528 int $messageoffset = 0,
1529 bool $newestmessagesfirst = true
1531 global $CFG, $DB, $USER;
1533 // All the standard BL checks.
1534 if (empty($CFG->messaging)) {
1535 throw new moodle_exception('disabled', 'message');
1538 $params = [
1539 'userid' => $userid,
1540 'otheruserid' => $otheruserid,
1541 'includecontactrequests' => $includecontactrequests,
1542 'includeprivacyinfo' => $includeprivacyinfo,
1543 'memberlimit' => $memberlimit,
1544 'memberoffset' => $memberoffset,
1545 'messagelimit' => $messagelimit,
1546 'messageoffset' => $messageoffset,
1547 'newestmessagesfirst' => $newestmessagesfirst
1549 self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
1551 $systemcontext = context_system::instance();
1552 self::validate_context($systemcontext);
1554 $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
1555 $conversation = null;
1557 if ($conversationid) {
1558 $conversation = \core_message\api::get_conversation(
1559 $params['userid'],
1560 $conversationid,
1561 $params['includecontactrequests'],
1562 $params['includeprivacyinfo'],
1563 $params['memberlimit'],
1564 $params['memberoffset'],
1565 $params['messagelimit'],
1566 $params['messageoffset'],
1567 $params['newestmessagesfirst']
1571 if ($conversation) {
1572 return $conversation;
1573 } else {
1574 // We have to throw an exception here because the external functions annoyingly
1575 // don't accept null to be returned for a single structure.
1576 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1581 * Get conversation returns.
1583 * @return external_single_structure
1585 public static function get_conversation_between_users_returns() {
1586 return self::get_conversation_structure(true);
1590 * Get self-conversation parameters.
1592 * @return external_function_parameters
1594 public static function get_self_conversation_parameters() {
1595 return new external_function_parameters(
1596 array(
1597 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'),
1598 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1599 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1600 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1606 * Get a single self-conversation.
1608 * @param int $userid The user id to get the self-conversation for
1609 * @param int $messagelimit Limit number of messages to load
1610 * @param int $messageoffset Offset the messages
1611 * @param bool $newestmessagesfirst Order messages by newest first
1612 * @return stdClass
1613 * @throws \moodle_exception if the messaging feature is disabled on the site.
1614 * @since Moodle 3.7
1616 public static function get_self_conversation(
1617 int $userid,
1618 int $messagelimit = 0,
1619 int $messageoffset = 0,
1620 bool $newestmessagesfirst = true
1622 global $CFG;
1624 // All the standard BL checks.
1625 if (empty($CFG->messaging)) {
1626 throw new moodle_exception('disabled', 'message');
1629 $params = [
1630 'userid' => $userid,
1631 'messagelimit' => $messagelimit,
1632 'messageoffset' => $messageoffset,
1633 'newestmessagesfirst' => $newestmessagesfirst
1635 self::validate_parameters(self::get_self_conversation_parameters(), $params);
1637 $systemcontext = context_system::instance();
1638 self::validate_context($systemcontext);
1640 $conversation = \core_message\api::get_self_conversation($params['userid']);
1642 if ($conversation) {
1643 $conversation = \core_message\api::get_conversation(
1644 $params['userid'],
1645 $conversation->id,
1646 false,
1647 false,
1650 $params['messagelimit'],
1651 $params['messageoffset'],
1652 $params['newestmessagesfirst']
1656 if ($conversation) {
1657 return $conversation;
1658 } else {
1659 // We have to throw an exception here because the external functions annoyingly
1660 // don't accept null to be returned for a single structure.
1661 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1666 * Get conversation returns.
1668 * @return external_single_structure
1670 public static function get_self_conversation_returns() {
1671 return self::get_conversation_structure();
1675 * The conversation messages parameters.
1677 * @return external_function_parameters
1678 * @since 3.6
1680 public static function get_conversation_messages_parameters() {
1681 return new external_function_parameters(
1682 array(
1683 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1684 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1685 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1686 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1687 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1688 'timefrom' => new external_value(PARAM_INT,
1689 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1695 * Get conversation messages.
1697 * @param int $currentuserid The current user's id.
1698 * @param int $convid The conversation id.
1699 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1700 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1701 * @param bool $newest True for getting first newest messages, false otherwise.
1702 * @param int $timefrom The time from the conversation messages to get.
1703 * @return array The messages and members who have sent some of these messages.
1704 * @throws moodle_exception
1705 * @since 3.6
1707 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1708 bool $newest = false, int $timefrom = 0) {
1709 global $CFG, $USER;
1711 // Check if messaging is enabled.
1712 if (empty($CFG->messaging)) {
1713 throw new moodle_exception('disabled', 'message');
1716 $systemcontext = context_system::instance();
1718 $params = array(
1719 'currentuserid' => $currentuserid,
1720 'convid' => $convid,
1721 'limitfrom' => $limitfrom,
1722 'limitnum' => $limitnum,
1723 'newest' => $newest,
1724 'timefrom' => $timefrom,
1726 $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1727 self::validate_context($systemcontext);
1729 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1730 throw new moodle_exception('You do not have permission to perform this action.');
1733 // Check that the user belongs to the conversation.
1734 if (!\core_message\api::is_user_in_conversation($params['currentuserid'], $params['convid'])) {
1735 throw new moodle_exception('User is not part of conversation.');
1738 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1740 // We need to enforce a one second delay on messages to avoid race conditions of current
1741 // messages still being sent.
1743 // There is a chance that we could request messages before the current time's
1744 // second has elapsed and while other messages are being sent in that same second. In which
1745 // case those messages will be lost.
1747 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1748 $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1750 // No requesting messages from the current time, as stated above.
1751 if ($params['timefrom'] == time()) {
1752 $messages = [];
1753 } else {
1754 $messages = \core_message\api::get_conversation_messages(
1755 $params['currentuserid'],
1756 $params['convid'],
1757 $params['limitfrom'],
1758 $params['limitnum'],
1759 $sort,
1760 $params['timefrom'],
1761 $timeto);
1764 return $messages;
1768 * The messagearea messages return structure.
1770 * @return external_single_structure
1771 * @since 3.6
1773 public static function get_conversation_messages_returns() {
1774 return new external_single_structure(
1775 array(
1776 'id' => new external_value(PARAM_INT, 'The conversation id'),
1777 'members' => new external_multiple_structure(
1778 self::get_conversation_member_structure()
1780 'messages' => new external_multiple_structure(
1781 self::get_conversation_message_structure()
1788 * The user contacts return parameters.
1790 * @return external_function_parameters
1792 public static function get_user_contacts_parameters() {
1793 return new external_function_parameters(
1794 array(
1795 'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
1796 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1797 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1803 * Get user contacts.
1805 * @param int $userid The id of the user who we are viewing conversations for
1806 * @param int $limitfrom
1807 * @param int $limitnum
1808 * @return array
1809 * @throws moodle_exception
1811 public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
1812 global $CFG, $USER;
1814 // Check if messaging is enabled.
1815 if (empty($CFG->messaging)) {
1816 throw new moodle_exception('disabled', 'message');
1819 $systemcontext = context_system::instance();
1821 $params = array(
1822 'userid' => $userid,
1823 'limitfrom' => $limitfrom,
1824 'limitnum' => $limitnum
1826 $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
1827 self::validate_context($systemcontext);
1829 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1830 throw new moodle_exception('You do not have permission to perform this action.');
1833 return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1837 * The user contacts return structure.
1839 * @return external_multiple_structure
1841 public static function get_user_contacts_returns() {
1842 return new external_multiple_structure(
1843 self::get_conversation_member_structure()
1848 * Search contacts parameters description.
1850 * @return external_function_parameters
1851 * @since Moodle 2.5
1853 public static function search_contacts_parameters() {
1854 return new external_function_parameters(
1855 array(
1856 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1857 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1858 VALUE_DEFAULT, false)
1864 * Search contacts.
1866 * @param string $searchtext query string.
1867 * @param bool $onlymycourses limit the search to the user's courses only.
1868 * @return external_description
1869 * @since Moodle 2.5
1871 public static function search_contacts($searchtext, $onlymycourses = false) {
1872 global $CFG, $USER, $PAGE;
1873 require_once($CFG->dirroot . '/user/lib.php');
1875 // Check if messaging is enabled.
1876 if (empty($CFG->messaging)) {
1877 throw new moodle_exception('disabled', 'message');
1880 require_once($CFG->libdir . '/enrollib.php');
1882 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1883 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1885 // Extra validation, we do not allow empty queries.
1886 if ($params['searchtext'] === '') {
1887 throw new moodle_exception('querystringcannotbeempty');
1890 $courseids = array();
1891 if ($params['onlymycourses']) {
1892 $mycourses = enrol_get_my_courses(array('id'));
1893 foreach ($mycourses as $mycourse) {
1894 $courseids[] = $mycourse->id;
1896 } else {
1897 $courseids[] = SITEID;
1900 // Retrieving the users matching the query.
1901 $users = message_search_users($courseids, $params['searchtext']);
1902 $results = array();
1903 foreach ($users as $user) {
1904 $results[$user->id] = $user;
1907 // Reorganising information.
1908 foreach ($results as &$user) {
1909 $newuser = array(
1910 'id' => $user->id,
1911 'fullname' => fullname($user)
1914 // Avoid undefined property notice as phone not specified.
1915 $user->phone1 = null;
1916 $user->phone2 = null;
1918 $userpicture = new user_picture($user);
1919 $userpicture->size = 1; // Size f1.
1920 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1921 $userpicture->size = 0; // Size f2.
1922 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1924 $user = $newuser;
1927 return $results;
1931 * Search contacts return description.
1933 * @return external_description
1934 * @since Moodle 2.5
1936 public static function search_contacts_returns() {
1937 return new external_multiple_structure(
1938 new external_single_structure(
1939 array(
1940 'id' => new external_value(PARAM_INT, 'User ID'),
1941 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1942 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1943 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1946 'List of contacts'
1951 * Get messages parameters description.
1953 * @return external_function_parameters
1954 * @since 2.8
1956 public static function get_messages_parameters() {
1957 return new external_function_parameters(
1958 array(
1959 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1960 'useridfrom' => new external_value(
1961 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1962 VALUE_DEFAULT, 0),
1963 'type' => new external_value(
1964 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1965 VALUE_DEFAULT, 'both'),
1966 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
1967 'newestfirst' => new external_value(
1968 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1969 VALUE_DEFAULT, true),
1970 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1971 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1977 * Get messages function implementation.
1979 * @since 2.8
1980 * @throws invalid_parameter_exception
1981 * @throws moodle_exception
1982 * @param int $useridto the user id who received the message
1983 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
1984 * @param string $type type of message to return, expected values: notifications, conversations and both
1985 * @param bool $read true for retreiving read messages, false for unread
1986 * @param bool $newestfirst true for ordering by newest first, false for oldest first
1987 * @param int $limitfrom limit from
1988 * @param int $limitnum limit num
1989 * @return external_description
1991 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
1992 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
1993 global $CFG, $USER;
1995 $warnings = array();
1997 $params = array(
1998 'useridto' => $useridto,
1999 'useridfrom' => $useridfrom,
2000 'type' => $type,
2001 'read' => $read,
2002 'newestfirst' => $newestfirst,
2003 'limitfrom' => $limitfrom,
2004 'limitnum' => $limitnum
2007 $params = self::validate_parameters(self::get_messages_parameters(), $params);
2009 $context = context_system::instance();
2010 self::validate_context($context);
2012 $useridto = $params['useridto'];
2013 $useridfrom = $params['useridfrom'];
2014 $type = $params['type'];
2015 $read = $params['read'];
2016 $newestfirst = $params['newestfirst'];
2017 $limitfrom = $params['limitfrom'];
2018 $limitnum = $params['limitnum'];
2020 $allowedvalues = array('notifications', 'conversations', 'both');
2021 if (!in_array($type, $allowedvalues)) {
2022 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2023 'allowed values are: ' . implode(',', $allowedvalues));
2026 // Check if private messaging between users is allowed.
2027 if (empty($CFG->messaging)) {
2028 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2029 if ($type == "conversations") {
2030 throw new moodle_exception('disabled', 'message');
2032 if ($type == "both") {
2033 $warning = array();
2034 $warning['item'] = 'message';
2035 $warning['itemid'] = $USER->id;
2036 $warning['warningcode'] = '1';
2037 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2038 Only notifications will be returned';
2039 $warnings[] = $warning;
2043 if (!empty($useridto)) {
2044 if (core_user::is_real_user($useridto)) {
2045 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2046 } else {
2047 throw new moodle_exception('invaliduser');
2051 if (!empty($useridfrom)) {
2052 // We use get_user here because the from user can be the noreply or support user.
2053 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2056 // Check if the current user is the sender/receiver or just a privileged user.
2057 if ($useridto != $USER->id and $useridfrom != $USER->id and
2058 !has_capability('moodle/site:readallmessages', $context)) {
2059 throw new moodle_exception('accessdenied', 'admin');
2062 // Which type of messages to retrieve.
2063 $notifications = -1;
2064 if ($type != 'both') {
2065 $notifications = ($type == 'notifications') ? 1 : 0;
2068 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2069 $sort = "mr.timecreated $orderdirection";
2071 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2072 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2074 // In some cases, we don't need to get the to/from user objects from the sql query.
2075 $userfromfullname = '';
2076 $usertofullname = '';
2078 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2079 if (!empty($useridto)) {
2080 $usertofullname = fullname($userto, $canviewfullname);
2081 // The user from may or may not be filled.
2082 if (!empty($useridfrom)) {
2083 $userfromfullname = fullname($userfrom, $canviewfullname);
2085 } else {
2086 // If the useridto field is empty, the useridfrom must be filled.
2087 $userfromfullname = fullname($userfrom, $canviewfullname);
2089 foreach ($messages as $mid => $message) {
2091 // Do not return deleted messages.
2092 if (!$message->notification) {
2093 if (($useridto == $USER->id and $message->timeusertodeleted) or
2094 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2095 unset($messages[$mid]);
2096 continue;
2100 // We need to get the user from the query.
2101 if (empty($userfromfullname)) {
2102 // Check for non-reply and support users.
2103 if (core_user::is_real_user($message->useridfrom)) {
2104 $user = new stdClass();
2105 $user = username_load_fields_from_object($user, $message, 'userfrom');
2106 $message->userfromfullname = fullname($user, $canviewfullname);
2107 } else {
2108 $user = core_user::get_user($message->useridfrom);
2109 $message->userfromfullname = fullname($user, $canviewfullname);
2111 } else {
2112 $message->userfromfullname = $userfromfullname;
2115 // We need to get the user from the query.
2116 if (empty($usertofullname)) {
2117 $user = new stdClass();
2118 $user = username_load_fields_from_object($user, $message, 'userto');
2119 $message->usertofullname = fullname($user, $canviewfullname);
2120 } else {
2121 $message->usertofullname = $usertofullname;
2124 $message->text = message_format_message_text($message);
2125 $messages[$mid] = (array) $message;
2129 $results = array(
2130 'messages' => $messages,
2131 'warnings' => $warnings
2134 return $results;
2138 * Get messages return description.
2140 * @return external_single_structure
2141 * @since 2.8
2143 public static function get_messages_returns() {
2144 return new external_single_structure(
2145 array(
2146 'messages' => new external_multiple_structure(
2147 new external_single_structure(
2148 array(
2149 'id' => new external_value(PARAM_INT, 'Message id'),
2150 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2151 'useridto' => new external_value(PARAM_INT, 'User to id'),
2152 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2153 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2154 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2155 'fullmessageformat' => new external_format_value('fullmessage'),
2156 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2157 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2158 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2159 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2160 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2161 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2162 'timeread' => new external_value(PARAM_INT, 'Time read'),
2163 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2164 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
2165 'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
2166 VALUE_OPTIONAL),
2167 'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
2168 'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
2169 The data here is serialised using json_encode().', VALUE_OPTIONAL),
2170 ), 'message'
2173 'warnings' => new external_warnings()
2179 * Mark all notifications as read parameters description.
2181 * @return external_function_parameters
2182 * @since 3.2
2184 public static function mark_all_notifications_as_read_parameters() {
2185 return new external_function_parameters(
2186 array(
2187 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2188 'useridfrom' => new external_value(
2189 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2190 VALUE_DEFAULT, 0),
2191 'timecreatedto' => new external_value(
2192 PARAM_INT, 'mark messages created before this time as read, 0 for all messages',
2193 VALUE_DEFAULT, 0),
2199 * Mark all notifications as read function.
2201 * @since 3.2
2202 * @throws invalid_parameter_exception
2203 * @throws moodle_exception
2204 * @param int $useridto the user id who received the message
2205 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2206 * @param int $timecreatedto mark message created before this time as read, 0 for all messages
2207 * @return external_description
2209 public static function mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto = 0) {
2210 global $USER;
2212 $params = self::validate_parameters(
2213 self::mark_all_notifications_as_read_parameters(),
2214 array(
2215 'useridto' => $useridto,
2216 'useridfrom' => $useridfrom,
2217 'timecreatedto' => $timecreatedto,
2221 $context = context_system::instance();
2222 self::validate_context($context);
2224 $useridto = $params['useridto'];
2225 $useridfrom = $params['useridfrom'];
2226 $timecreatedto = $params['timecreatedto'];
2228 if (!empty($useridto)) {
2229 if (core_user::is_real_user($useridto)) {
2230 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2231 } else {
2232 throw new moodle_exception('invaliduser');
2236 if (!empty($useridfrom)) {
2237 // We use get_user here because the from user can be the noreply or support user.
2238 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2241 // Check if the current user is the sender/receiver or just a privileged user.
2242 if ($useridto != $USER->id and $useridfrom != $USER->id and
2243 // The deleteanymessage cap seems more reasonable here than readallmessages.
2244 !has_capability('moodle/site:deleteanymessage', $context)) {
2245 throw new moodle_exception('accessdenied', 'admin');
2248 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto);
2250 return true;
2254 * Mark all notifications as read return description.
2256 * @return external_single_structure
2257 * @since 3.2
2259 public static function mark_all_notifications_as_read_returns() {
2260 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2264 * Get unread conversations count parameters description.
2266 * @return external_function_parameters
2267 * @since 3.2
2269 public static function get_unread_conversations_count_parameters() {
2270 return new external_function_parameters(
2271 array(
2272 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2278 * Get unread messages count function.
2280 * @since 3.2
2281 * @throws invalid_parameter_exception
2282 * @throws moodle_exception
2283 * @param int $useridto the user id who received the message
2284 * @return external_description
2286 public static function get_unread_conversations_count($useridto) {
2287 global $USER, $CFG;
2289 // Check if messaging is enabled.
2290 if (empty($CFG->messaging)) {
2291 throw new moodle_exception('disabled', 'message');
2294 $params = self::validate_parameters(
2295 self::get_unread_conversations_count_parameters(),
2296 array('useridto' => $useridto)
2299 $context = context_system::instance();
2300 self::validate_context($context);
2302 $useridto = $params['useridto'];
2304 if (!empty($useridto)) {
2305 if (core_user::is_real_user($useridto)) {
2306 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2307 } else {
2308 throw new moodle_exception('invaliduser');
2310 } else {
2311 $useridto = $USER->id;
2314 // Check if the current user is the receiver or just a privileged user.
2315 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2316 throw new moodle_exception('accessdenied', 'admin');
2319 return \core_message\api::count_unread_conversations($userto);
2323 * Get unread conversations count return description.
2325 * @return external_single_structure
2326 * @since 3.2
2328 public static function get_unread_conversations_count_returns() {
2329 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2333 * Get blocked users parameters description.
2335 * @return external_function_parameters
2336 * @since 2.9
2338 public static function get_blocked_users_parameters() {
2339 return new external_function_parameters(
2340 array(
2341 'userid' => new external_value(PARAM_INT,
2342 'the user whose blocked users we want to retrieve',
2343 VALUE_REQUIRED),
2349 * Retrieve a list of users blocked
2351 * @param int $userid the user whose blocked users we want to retrieve
2352 * @return external_description
2353 * @since 2.9
2355 public static function get_blocked_users($userid) {
2356 global $CFG, $USER, $PAGE;
2358 // Warnings array, it can be empty at the end but is mandatory.
2359 $warnings = array();
2361 // Validate params.
2362 $params = array(
2363 'userid' => $userid
2365 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2366 $userid = $params['userid'];
2368 // Validate context.
2369 $context = context_system::instance();
2370 self::validate_context($context);
2372 // Check if private messaging between users is allowed.
2373 if (empty($CFG->messaging)) {
2374 throw new moodle_exception('disabled', 'message');
2377 $user = core_user::get_user($userid, '*', MUST_EXIST);
2378 core_user::require_active_user($user);
2380 // Check if we have permissions for retrieve the information.
2381 $capability = 'moodle/site:manageallmessaging';
2382 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2383 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2386 // Now, we can get safely all the blocked users.
2387 $users = \core_message\api::get_blocked_users($user->id);
2389 $blockedusers = array();
2390 foreach ($users as $user) {
2391 $newuser = array(
2392 'id' => $user->id,
2393 'fullname' => fullname($user),
2396 $userpicture = new user_picture($user);
2397 $userpicture->size = 1; // Size f1.
2398 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2400 $blockedusers[] = $newuser;
2403 $results = array(
2404 'users' => $blockedusers,
2405 'warnings' => $warnings
2407 return $results;
2411 * Get blocked users return description.
2413 * @return external_single_structure
2414 * @since 2.9
2416 public static function get_blocked_users_returns() {
2417 return new external_single_structure(
2418 array(
2419 'users' => new external_multiple_structure(
2420 new external_single_structure(
2421 array(
2422 'id' => new external_value(PARAM_INT, 'User ID'),
2423 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2424 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2427 'List of blocked users'
2429 'warnings' => new external_warnings()
2435 * Returns description of method parameters
2437 * @return external_function_parameters
2438 * @since 2.9
2440 public static function mark_message_read_parameters() {
2441 return new external_function_parameters(
2442 array(
2443 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2444 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2445 VALUE_DEFAULT, 0)
2451 * Mark a single message as read, trigger message_viewed event
2453 * @param int $messageid id of the message (in the message table)
2454 * @param int $timeread timestamp for when the message should be marked read
2455 * @return external_description
2456 * @throws invalid_parameter_exception
2457 * @throws moodle_exception
2458 * @since 2.9
2460 public static function mark_message_read($messageid, $timeread) {
2461 global $CFG, $DB, $USER;
2463 // Check if private messaging between users is allowed.
2464 if (empty($CFG->messaging)) {
2465 throw new moodle_exception('disabled', 'message');
2468 // Warnings array, it can be empty at the end but is mandatory.
2469 $warnings = array();
2471 // Validate params.
2472 $params = array(
2473 'messageid' => $messageid,
2474 'timeread' => $timeread
2476 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2478 if (empty($params['timeread'])) {
2479 $timeread = time();
2480 } else {
2481 $timeread = $params['timeread'];
2484 // Validate context.
2485 $context = context_system::instance();
2486 self::validate_context($context);
2488 $sql = "SELECT m.*, mcm.userid as useridto
2489 FROM {messages} m
2490 INNER JOIN {message_conversations} mc
2491 ON m.conversationid = mc.id
2492 INNER JOIN {message_conversation_members} mcm
2493 ON mcm.conversationid = mc.id
2494 LEFT JOIN {message_user_actions} mua
2495 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2496 WHERE mua.id is NULL
2497 AND mcm.userid != m.useridfrom
2498 AND m.id = ?";
2499 $messageparams = [];
2500 $messageparams[] = $USER->id;
2501 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2502 $messageparams[] = $params['messageid'];
2503 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2505 if ($message->useridto != $USER->id) {
2506 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2509 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2511 $results = array(
2512 'messageid' => $message->id,
2513 'warnings' => $warnings
2515 return $results;
2519 * Returns description of method result value
2521 * @return external_description
2522 * @since 2.9
2524 public static function mark_message_read_returns() {
2525 return new external_single_structure(
2526 array(
2527 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2528 'warnings' => new external_warnings()
2534 * Returns description of method parameters
2536 * @return external_function_parameters
2538 public static function mark_notification_read_parameters() {
2539 return new external_function_parameters(
2540 array(
2541 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2542 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2543 VALUE_DEFAULT, 0)
2549 * Mark a single notification as read.
2551 * This will trigger a 'notification_viewed' event.
2553 * @param int $notificationid id of the notification
2554 * @param int $timeread timestamp for when the notification should be marked read
2555 * @return external_description
2556 * @throws invalid_parameter_exception
2557 * @throws moodle_exception
2559 public static function mark_notification_read($notificationid, $timeread) {
2560 global $CFG, $DB, $USER;
2562 // Warnings array, it can be empty at the end but is mandatory.
2563 $warnings = array();
2565 // Validate params.
2566 $params = array(
2567 'notificationid' => $notificationid,
2568 'timeread' => $timeread
2570 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2572 if (empty($params['timeread'])) {
2573 $timeread = time();
2574 } else {
2575 $timeread = $params['timeread'];
2578 // Validate context.
2579 $context = context_system::instance();
2580 self::validate_context($context);
2582 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2584 if ($notification->useridto != $USER->id) {
2585 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2586 'notification as read');
2589 \core_message\api::mark_notification_as_read($notification, $timeread);
2591 $results = array(
2592 'notificationid' => $notification->id,
2593 'warnings' => $warnings
2596 return $results;
2600 * Returns description of method result value
2602 * @return external_description
2604 public static function mark_notification_read_returns() {
2605 return new external_single_structure(
2606 array(
2607 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2608 'warnings' => new external_warnings()
2614 * Mark all conversation messages as read parameters description.
2616 * @return external_function_parameters
2617 * @since 3.6
2619 public static function mark_all_conversation_messages_as_read_parameters() {
2620 return new external_function_parameters(
2621 array(
2622 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2623 'conversationid' =>
2624 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2630 * Mark all conversation messages as read function.
2632 * @param int $userid The user id of who we want to delete the conversation for
2633 * @param int $conversationid The id of the conversations
2634 * @since 3.6
2636 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2637 global $CFG;
2639 // Check if messaging is enabled.
2640 if (empty($CFG->messaging)) {
2641 throw new moodle_exception('disabled', 'message');
2644 $params = array(
2645 'userid' => $userid,
2646 'conversationid' => $conversationid,
2648 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2650 $context = context_system::instance();
2651 self::validate_context($context);
2653 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2654 core_user::require_active_user($user);
2656 if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
2657 \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
2658 } else {
2659 throw new moodle_exception('accessdenied', 'admin');
2664 * Mark all conversation messages as read return description.
2666 * @return external_warnings
2667 * @since 3.6
2669 public static function mark_all_conversation_messages_as_read_returns() {
2670 return null;
2674 * Returns description of method parameters.
2676 * @return external_function_parameters
2677 * @since 3.6
2679 public static function delete_conversations_by_id_parameters() {
2680 return new external_function_parameters(
2681 array(
2682 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2683 'conversationids' => new external_multiple_structure(
2684 new external_value(PARAM_INT, 'The id of the conversation'),
2685 'List of conversation IDs'
2692 * Deletes a conversation.
2694 * @param int $userid The user id of who we want to delete the conversation for
2695 * @param int[] $conversationids The ids of the conversations
2696 * @return array
2697 * @throws moodle_exception
2698 * @since 3.6
2700 public static function delete_conversations_by_id($userid, array $conversationids) {
2701 global $CFG;
2703 // Check if private messaging between users is allowed.
2704 if (empty($CFG->messaging)) {
2705 throw new moodle_exception('disabled', 'message');
2708 // Validate params.
2709 $params = [
2710 'userid' => $userid,
2711 'conversationids' => $conversationids,
2713 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
2715 // Validate context.
2716 $context = context_system::instance();
2717 self::validate_context($context);
2719 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2720 core_user::require_active_user($user);
2722 foreach ($params['conversationids'] as $conversationid) {
2723 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2724 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2725 } else {
2726 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2730 return [];
2734 * Returns description of method result value.
2736 * @return external_description
2737 * @since 3.6
2739 public static function delete_conversations_by_id_returns() {
2740 return new external_warnings();
2744 * Returns description of method parameters
2746 * @return external_function_parameters
2747 * @since 3.1
2749 public static function delete_message_parameters() {
2750 return new external_function_parameters(
2751 array(
2752 'messageid' => new external_value(PARAM_INT, 'The message id'),
2753 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2754 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2760 * Deletes a message
2762 * @param int $messageid the message id
2763 * @param int $userid the user id of who we want to delete the message for
2764 * @param bool $read if is a message read (default to true)
2765 * @return external_description
2766 * @throws moodle_exception
2767 * @since 3.1
2769 public static function delete_message($messageid, $userid, $read = true) {
2770 global $CFG;
2772 // Check if private messaging between users is allowed.
2773 if (empty($CFG->messaging)) {
2774 throw new moodle_exception('disabled', 'message');
2777 // Warnings array, it can be empty at the end but is mandatory.
2778 $warnings = array();
2780 // Validate params.
2781 $params = array(
2782 'messageid' => $messageid,
2783 'userid' => $userid,
2784 'read' => $read
2786 $params = self::validate_parameters(self::delete_message_parameters(), $params);
2788 // Validate context.
2789 $context = context_system::instance();
2790 self::validate_context($context);
2792 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2793 core_user::require_active_user($user);
2795 if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
2796 $status = \core_message\api::delete_message($user->id, $params['messageid']);
2797 } else {
2798 throw new moodle_exception('You do not have permission to delete this message');
2801 $results = array(
2802 'status' => $status,
2803 'warnings' => $warnings
2805 return $results;
2809 * Returns description of method result value
2811 * @return external_description
2812 * @since 3.1
2814 public static function delete_message_returns() {
2815 return new external_single_structure(
2816 array(
2817 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2818 'warnings' => new external_warnings()
2824 * Returns description of method parameters
2826 * @return external_function_parameters
2827 * @since 3.2
2829 public static function message_processor_config_form_parameters() {
2830 return new external_function_parameters(
2831 array(
2832 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2833 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
2834 'formvalues' => new external_multiple_structure(
2835 new external_single_structure(
2836 array(
2837 'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2838 'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2841 'Config form values',
2842 VALUE_REQUIRED
2849 * Processes a message processor config form.
2851 * @param int $userid the user id
2852 * @param string $name the name of the processor
2853 * @param array $formvalues the form values
2854 * @return external_description
2855 * @throws moodle_exception
2856 * @since 3.2
2858 public static function message_processor_config_form($userid, $name, $formvalues) {
2859 global $USER, $CFG;
2861 $params = self::validate_parameters(
2862 self::message_processor_config_form_parameters(),
2863 array(
2864 'userid' => $userid,
2865 'name' => $name,
2866 'formvalues' => $formvalues,
2870 $user = self::validate_preferences_permissions($params['userid']);
2872 $processor = get_message_processor($params['name']);
2873 $preferences = [];
2874 $form = new stdClass();
2876 foreach ($params['formvalues'] as $formvalue) {
2877 // Curly braces to ensure interpretation is consistent between
2878 // php 5 and php 7.
2879 $form->{$formvalue['name']} = $formvalue['value'];
2882 $processor->process_form($form, $preferences);
2884 if (!empty($preferences)) {
2885 set_user_preferences($preferences, $params['userid']);
2890 * Returns description of method result value
2892 * @return external_description
2893 * @since 3.2
2895 public static function message_processor_config_form_returns() {
2896 return null;
2900 * Returns description of method parameters
2902 * @return external_function_parameters
2903 * @since 3.2
2905 public static function get_message_processor_parameters() {
2906 return new external_function_parameters(
2907 array(
2908 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2909 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
2915 * Get a message processor.
2917 * @param int $userid
2918 * @param string $name the name of the processor
2919 * @return external_description
2920 * @throws moodle_exception
2921 * @since 3.2
2923 public static function get_message_processor($userid, $name) {
2924 global $USER, $PAGE, $CFG;
2926 // Check if messaging is enabled.
2927 if (empty($CFG->messaging)) {
2928 throw new moodle_exception('disabled', 'message');
2931 $params = self::validate_parameters(
2932 self::get_message_processor_parameters(),
2933 array(
2934 'userid' => $userid,
2935 'name' => $name,
2939 if (empty($params['userid'])) {
2940 $params['userid'] = $USER->id;
2943 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2944 core_user::require_active_user($user);
2945 self::validate_context(context_user::instance($params['userid']));
2947 $processor = get_message_processor($params['name']);
2949 $processoroutput = new \core_message\output\processor($processor, $user);
2950 $renderer = $PAGE->get_renderer('core_message');
2952 return $processoroutput->export_for_template($renderer);
2956 * Returns description of method result value
2958 * @return external_description
2959 * @since 3.2
2961 public static function get_message_processor_returns() {
2962 return new external_function_parameters(
2963 array(
2964 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2965 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2971 * Check that the user has enough permission to retrieve message or notifications preferences.
2973 * @param int $userid the user id requesting the preferences
2974 * @return stdClass full user object
2975 * @throws moodle_exception
2976 * @since Moodle 3.2
2978 protected static function validate_preferences_permissions($userid) {
2979 global $USER;
2981 if (empty($userid)) {
2982 $user = $USER;
2983 } else {
2984 $user = core_user::get_user($userid, '*', MUST_EXIST);
2985 core_user::require_active_user($user);
2988 $systemcontext = context_system::instance();
2989 self::validate_context($systemcontext);
2991 // Check access control.
2992 if ($user->id == $USER->id) {
2993 // Editing own message profile.
2994 require_capability('moodle/user:editownmessageprofile', $systemcontext);
2995 } else {
2996 // Teachers, parents, etc.
2997 $personalcontext = context_user::instance($user->id);
2998 require_capability('moodle/user:editmessageprofile', $personalcontext);
3000 return $user;
3004 * Returns a notification or message preference structure.
3006 * @return external_single_structure the structure
3007 * @since Moodle 3.2
3009 protected static function get_preferences_structure() {
3010 return new external_single_structure(
3011 array(
3012 'userid' => new external_value(PARAM_INT, 'User id'),
3013 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3014 'processors' => new external_multiple_structure(
3015 new external_single_structure(
3016 array(
3017 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3018 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3019 'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3020 'contextid' => new external_value(PARAM_INT, 'Context id'),
3021 'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3024 'Config form values'
3026 'components' => new external_multiple_structure(
3027 new external_single_structure(
3028 array(
3029 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3030 'notifications' => new external_multiple_structure(
3031 new external_single_structure(
3032 array(
3033 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3034 'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3035 'processors' => new external_multiple_structure(
3036 new external_single_structure(
3037 array(
3038 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3039 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3040 'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3041 'lockedmessage' => new external_value(PARAM_TEXT,
3042 'Text to display if locked', VALUE_OPTIONAL),
3043 'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3044 'loggedin' => new external_single_structure(
3045 array(
3046 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3047 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3048 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3051 'loggedoff' => new external_single_structure(
3052 array(
3053 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3054 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3055 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3060 'Processors values for this notification'
3064 'List of notificaitons for the component'
3068 'Available components'
3075 * Returns description of method parameters
3077 * @return external_function_parameters
3078 * @since 3.2
3080 public static function get_user_notification_preferences_parameters() {
3081 return new external_function_parameters(
3082 array(
3083 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3089 * Get the notification preferences for a given user.
3091 * @param int $userid id of the user, 0 for current user
3092 * @return external_description
3093 * @throws moodle_exception
3094 * @since 3.2
3096 public static function get_user_notification_preferences($userid = 0) {
3097 global $PAGE;
3099 $params = self::validate_parameters(
3100 self::get_user_notification_preferences_parameters(),
3101 array(
3102 'userid' => $userid,
3105 $user = self::validate_preferences_permissions($params['userid']);
3107 $processors = get_message_processors();
3108 $providers = message_get_providers_for_user($user->id);
3109 $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3110 $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3112 $renderer = $PAGE->get_renderer('core_message');
3114 $result = array(
3115 'warnings' => array(),
3116 'preferences' => $notificationlist->export_for_template($renderer)
3118 return $result;
3122 * Returns description of method result value
3124 * @return external_description
3125 * @since 3.2
3127 public static function get_user_notification_preferences_returns() {
3128 return new external_function_parameters(
3129 array(
3130 'preferences' => self::get_preferences_structure(),
3131 'warnings' => new external_warnings(),
3137 * Returns description of method parameters
3139 * @return external_function_parameters
3140 * @since 3.2
3142 public static function get_user_message_preferences_parameters() {
3143 return new external_function_parameters(
3144 array(
3145 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3151 * Get the notification preferences for a given user.
3153 * @param int $userid id of the user, 0 for current user
3154 * @return external_description
3155 * @throws moodle_exception
3156 * @since 3.2
3158 public static function get_user_message_preferences($userid = 0) {
3159 global $CFG, $PAGE;
3161 $params = self::validate_parameters(
3162 self::get_user_message_preferences_parameters(),
3163 array(
3164 'userid' => $userid,
3168 $user = self::validate_preferences_permissions($params['userid']);
3170 // Filter out enabled, available system_configured and user_configured processors only.
3171 $readyprocessors = array_filter(get_message_processors(), function($processor) {
3172 return $processor->enabled &&
3173 $processor->configured &&
3174 $processor->object->is_user_configured() &&
3175 // Filter out processors that don't have and message preferences to configure.
3176 $processor->object->has_message_preferences();
3179 $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
3180 return $provider->component === 'moodle';
3182 $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
3183 $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
3184 $providers, $preferences, $user);
3186 $renderer = $PAGE->get_renderer('core_message');
3188 $entertosend = get_user_preferences('message_entertosend', $CFG->messagingdefaultpressenter, $user);
3190 $result = array(
3191 'warnings' => array(),
3192 'preferences' => $notificationlistoutput->export_for_template($renderer),
3193 'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id),
3194 'entertosend' => $entertosend
3196 return $result;
3200 * Returns description of method result value
3202 * @return external_description
3203 * @since 3.2
3205 public static function get_user_message_preferences_returns() {
3206 return new external_function_parameters(
3207 array(
3208 'preferences' => self::get_preferences_structure(),
3209 'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'),
3210 'entertosend' => new external_value(PARAM_BOOL, 'User preference for using enter to send messages'),
3211 'warnings' => new external_warnings(),
3217 * Returns description of method parameters for the favourite_conversations() method.
3219 * @return external_function_parameters
3221 public static function set_favourite_conversations_parameters() {
3222 return new external_function_parameters(
3223 array(
3224 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3225 'conversations' => new external_multiple_structure(
3226 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3233 * Favourite a conversation, or list of conversations for a user.
3235 * @param int $userid the id of the user, or 0 for the current user.
3236 * @param array $conversationids the list of conversations ids to favourite.
3237 * @return array
3238 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3240 public static function set_favourite_conversations(int $userid, array $conversationids) {
3241 global $CFG, $USER;
3243 // All the business logic checks that really shouldn't be in here.
3244 if (empty($CFG->messaging)) {
3245 throw new moodle_exception('disabled', 'message');
3247 $params = [
3248 'userid' => $userid,
3249 'conversations' => $conversationids
3251 $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params);
3252 $systemcontext = context_system::instance();
3253 self::validate_context($systemcontext);
3255 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3256 throw new moodle_exception('You do not have permission to perform this action.');
3259 foreach ($params['conversations'] as $conversationid) {
3260 \core_message\api::set_favourite_conversation($conversationid, $params['userid']);
3263 return [];
3267 * Return a description of the returns for the create_user_favourite_conversations() method.
3269 * @return external_description
3271 public static function set_favourite_conversations_returns() {
3272 return new external_warnings();
3276 * Returns description of method parameters for unfavourite_conversations() method.
3278 * @return external_function_parameters
3280 public static function unset_favourite_conversations_parameters() {
3281 return new external_function_parameters(
3282 array(
3283 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3284 'conversations' => new external_multiple_structure(
3285 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3292 * Unfavourite a conversation, or list of conversations for a user.
3294 * @param int $userid the id of the user, or 0 for the current user.
3295 * @param array $conversationids the list of conversations ids unset as favourites.
3296 * @return array
3297 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3299 public static function unset_favourite_conversations(int $userid, array $conversationids) {
3300 global $CFG, $USER;
3302 // All the business logic checks that really shouldn't be in here.
3303 if (empty($CFG->messaging)) {
3304 throw new moodle_exception('disabled', 'message');
3306 $params = [
3307 'userid' => $userid,
3308 'conversations' => $conversationids
3310 $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params);
3311 $systemcontext = context_system::instance();
3312 self::validate_context($systemcontext);
3314 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3315 throw new moodle_exception('You do not have permission to perform this action.');
3318 foreach ($params['conversations'] as $conversationid) {
3319 \core_message\api::unset_favourite_conversation($conversationid, $params['userid']);
3322 return [];
3326 * Unset favourite conversations return description.
3328 * @return external_description
3330 public static function unset_favourite_conversations_returns() {
3331 return new external_warnings();
3335 * Returns description of method parameters for get_member_info() method.
3337 * @return external_function_parameters
3339 public static function get_member_info_parameters() {
3340 return new external_function_parameters(
3341 array(
3342 'referenceuserid' => new external_value(PARAM_INT, 'id of the user'),
3343 'userids' => new external_multiple_structure(
3344 new external_value(PARAM_INT, 'id of members to get')
3346 'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false),
3347 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'include privacy info in response', VALUE_DEFAULT, false)
3353 * Returns conversation member info for the supplied users, relative to the supplied referenceuserid.
3355 * This is the basic structure used when returning members, and includes information about the relationship between each member
3356 * and the referenceuser, such as a whether the referenceuser has marked the member as a contact, or has blocked them.
3358 * @param int $referenceuserid the id of the user which check contact and blocked status.
3359 * @param array $userids
3360 * @return array the array of objects containing member info.
3361 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3363 public static function get_member_info(
3364 int $referenceuserid,
3365 array $userids,
3366 bool $includecontactrequests = false,
3367 bool $includeprivacyinfo = false
3369 global $CFG, $USER;
3371 // All the business logic checks that really shouldn't be in here.
3372 if (empty($CFG->messaging)) {
3373 throw new moodle_exception('disabled', 'message');
3375 $params = [
3376 'referenceuserid' => $referenceuserid,
3377 'userids' => $userids,
3378 'includecontactrequests' => $includecontactrequests,
3379 'includeprivacyinfo' => $includeprivacyinfo
3381 $params = self::validate_parameters(self::get_member_info_parameters(), $params);
3382 $systemcontext = context_system::instance();
3383 self::validate_context($systemcontext);
3385 if (($USER->id != $referenceuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3386 throw new moodle_exception('You do not have permission to perform this action.');
3389 return \core_message\helper::get_member_info(
3390 $params['referenceuserid'],
3391 $params['userids'],
3392 $params['includecontactrequests'],
3393 $params['includeprivacyinfo']
3398 * Get member info return description.
3400 * @return external_description
3402 public static function get_member_info_returns() {
3403 return new external_multiple_structure(
3404 self::get_conversation_member_structure()
3409 * Returns description of method parameters for get_conversation_counts() method.
3411 * @return external_function_parameters
3413 public static function get_conversation_counts_parameters() {
3414 return new external_function_parameters(
3416 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3422 * Returns an array of conversation counts for the various types of conversations, including favourites.
3424 * Return format:
3426 * 'favourites' => 0,
3427 * 'types' => [
3428 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3429 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3433 * @param int $userid the id of the user whose counts we are fetching.
3434 * @return array the array of conversation counts, indexed by type.
3435 * @throws moodle_exception if the current user cannot perform this action.
3437 public static function get_conversation_counts(int $userid) {
3438 global $CFG, $USER;
3440 // All the business logic checks that really shouldn't be in here.
3441 if (empty($CFG->messaging)) {
3442 throw new moodle_exception('disabled', 'message');
3445 if (empty($userid)) {
3446 $userid = $USER->id;
3449 $params = ['userid' => $userid];
3450 $params = self::validate_parameters(self::get_conversation_counts_parameters(), $params);
3452 $systemcontext = context_system::instance();
3453 self::validate_context($systemcontext);
3455 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3456 throw new moodle_exception('You do not have permission to perform this action.');
3459 return \core_message\api::get_conversation_counts($params['userid']);
3463 * Get conversation counts return description.
3465 * @return external_description
3467 public static function get_conversation_counts_returns() {
3468 return new external_single_structure(
3470 'favourites' => new external_value(PARAM_INT, 'Total number of favourite conversations'),
3471 'types' => new external_single_structure(
3473 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3474 'Total number of individual conversations'),
3475 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3476 'Total number of group conversations'),
3477 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3478 'Total number of self conversations'),
3486 * Returns description of method parameters for get_unread_conversation_counts() method.
3488 * @return external_function_parameters
3490 public static function get_unread_conversation_counts_parameters() {
3491 return new external_function_parameters(
3493 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3499 * Returns an array of unread conversation counts for the various types of conversations, including favourites.
3501 * Return format:
3503 * 'favourites' => 0,
3504 * 'types' => [
3505 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3506 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3510 * @param int $userid the id of the user whose counts we are fetching.
3511 * @return array the array of unread conversation counts, indexed by type.
3512 * @throws moodle_exception if the current user cannot perform this action.
3514 public static function get_unread_conversation_counts(int $userid) {
3515 global $CFG, $USER;
3517 // All the business logic checks that really shouldn't be in here.
3518 if (empty($CFG->messaging)) {
3519 throw new moodle_exception('disabled', 'message');
3522 if (empty($userid)) {
3523 $userid = $USER->id;
3526 $params = ['userid' => $userid];
3527 $params = self::validate_parameters(self::get_unread_conversation_counts_parameters(), $params);
3529 $systemcontext = context_system::instance();
3530 self::validate_context($systemcontext);
3532 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3533 throw new moodle_exception('You do not have permission to perform this action.');
3536 return \core_message\api::get_unread_conversation_counts($params['userid']);
3540 * Get unread conversation counts return description.
3542 * @return external_description
3544 public static function get_unread_conversation_counts_returns() {
3545 return new external_single_structure(
3547 'favourites' => new external_value(PARAM_INT, 'Total number of unread favourite conversations'),
3548 'types' => new external_single_structure(
3550 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3551 'Total number of unread individual conversations'),
3552 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3553 'Total number of unread group conversations'),
3554 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3555 'Total number of unread self conversations'),
3563 * Returns description of method parameters
3565 * @return external_function_parameters
3566 * @since 3.7
3568 public static function delete_message_for_all_users_parameters() {
3569 return new external_function_parameters(
3570 array(
3571 'messageid' => new external_value(PARAM_INT, 'The message id'),
3572 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users')
3577 * Deletes a message for all users
3579 * @param int $messageid the message id
3580 * @param int $userid the user id of who we want to delete the message for all users, is no longer used.
3581 * @return external_description
3582 * @throws moodle_exception
3583 * @since 3.7
3585 public static function delete_message_for_all_users(int $messageid, int $userid) {
3586 global $CFG, $USER;
3588 // Check if private messaging between users is allowed.
3589 if (empty($CFG->messaging)) {
3590 throw new moodle_exception('disabled', 'message');
3593 // Validate params.
3594 $params = array(
3595 'messageid' => $messageid,
3596 'userid' => $userid
3598 $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params);
3600 // Validate context.
3601 $context = context_system::instance();
3602 self::validate_context($context);
3604 core_user::require_active_user($USER);
3606 // Checks if a user can delete a message for all users.
3607 if (core_message\api::can_delete_message_for_all_users($USER->id, $params['messageid'])) {
3608 \core_message\api::delete_message_for_all_users($params['messageid']);
3609 } else {
3610 throw new moodle_exception('You do not have permission to delete this message for everyone.');
3613 return [];
3616 * Returns description of method result value
3618 * @return external_description
3619 * @since 3.7
3621 public static function delete_message_for_all_users_returns() {
3622 return new external_warnings();