2 // This file is part of Moodle - http://moodle.org/
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.
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/>.
19 * External message API
21 * @package core_message
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");
33 * Message external functions
35 * @package core_message
37 * @copyright 2011 Jerome Mouneyrac
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 class core_message_external extends external_api {
43 * Returns description of method parameters
45 * @return external_function_parameters
48 public static function send_messages_to_conversation_parameters() {
49 return new external_function_parameters(
51 'conversationid' => new external_value(PARAM_INT, 'id of the conversation'),
52 'messages' => new external_multiple_structure(
53 new external_single_structure(
55 'text' => new external_value(PARAM_RAW, 'the text of the message'),
56 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
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).
74 public static function send_messages_to_conversation(int $conversationid, array $messages = []) {
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
92 foreach ($params['messages'] as $message) {
93 $messages[] = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
94 $message['textformat']);
101 * Returns description of method result value.
103 * @return external_description
106 public static function send_messages_to_conversation_returns() {
107 return new external_multiple_structure(
108 self::get_conversation_message_structure()
114 * Returns description of method parameters
116 * @return external_function_parameters
119 public static function send_instant_messages_parameters() {
120 return new external_function_parameters(
122 'messages' => new external_multiple_structure(
123 new external_single_structure(
125 'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
126 'text' => new external_value(PARAM_RAW, 'the text of the message'),
127 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
128 '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),
137 * Send private messages from the current USER to other users
139 * @param array $messages An array of message to send.
143 public static function send_instant_messages($messages = array()) {
144 global $CFG, $USER, $DB;
146 // Check if messaging is enabled.
147 if (empty($CFG->messaging)) {
148 throw new moodle_exception('disabled', 'message');
151 // Ensure the current user is allowed to run this function
152 $context = context_system::instance();
153 self::validate_context($context);
154 require_capability('moodle/site:sendmessage', $context);
156 $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
158 //retrieve all tousers of the messages
159 $receivers = array();
160 foreach($params['messages'] as $message) {
161 $receivers[] = $message['touserid'];
163 list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
164 $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
166 $resultmessages = array();
167 foreach ($params['messages'] as $message) {
168 $resultmsg = array(); //the infos about the success of the operation
170 // We are going to do some checking.
171 // Code should match /messages/index.php checks.
174 // Check the user exists.
175 if (empty($tousers[$message['touserid']])) {
177 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
180 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
181 // Check if the recipient can be messaged by the sender.
182 if ($success && !\core_message\api::can_post_message($tousers[$message['touserid']], $USER)) {
184 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
187 // Now we can send the message (at least try).
189 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
190 $success = message_post_message($USER, $tousers[$message['touserid']],
191 $message['text'], external_validate_format($message['textformat']));
194 // Build the resultmsg.
195 if (isset($message['clientmsgid'])) {
196 $resultmsg['clientmsgid'] = $message['clientmsgid'];
199 $resultmsg['msgid'] = $success;
201 // WARNINGS: for backward compatibility we return this errormessage.
202 // We should have thrown exceptions as these errors prevent results to be returned.
203 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
204 $resultmsg['msgid'] = -1;
205 $resultmsg['errormessage'] = $errormessage;
208 $resultmessages[] = $resultmsg;
211 return $resultmessages;
215 * Returns description of method result value
217 * @return external_description
220 public static function send_instant_messages_returns() {
221 return new external_multiple_structure(
222 new external_single_structure(
224 'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds: id of the created message if it succeeded, -1 when failed'),
225 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
226 'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
233 * Create contacts parameters description.
235 * @deprecated since Moodle 3.6
236 * @return external_function_parameters
239 public static function create_contacts_parameters() {
240 return new external_function_parameters(
242 'userids' => new external_multiple_structure(
243 new external_value(PARAM_INT, 'User ID'),
246 'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
247 current user', VALUE_DEFAULT, 0)
255 * @deprecated since Moodle 3.6
256 * @param array $userids array of user IDs.
257 * @param int $userid The id of the user we are creating the contacts for
258 * @return external_description
261 public static function create_contacts($userids, $userid = 0) {
264 // Check if messaging is enabled.
265 if (empty($CFG->messaging)) {
266 throw new moodle_exception('disabled', 'message');
269 if (empty($userid)) {
274 $context = context_system::instance();
275 self::validate_context($context);
277 $params = array('userids' => $userids, 'userid' => $userid);
278 $params = self::validate_parameters(self::create_contacts_parameters(), $params);
280 $capability = 'moodle/site:manageallmessaging';
281 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
282 throw new required_capability_exception($context, $capability, 'nopermissions', '');
286 foreach ($params['userids'] as $id) {
287 if (!message_add_contact($id, 0, $params['userid'])) {
291 'warningcode' => 'contactnotcreated',
292 'message' => 'The contact could not be created'
300 * Create contacts return description.
302 * @deprecated since Moodle 3.6
303 * @return external_description
306 public static function create_contacts_returns() {
307 return new external_warnings();
311 * Marking the method as deprecated.
315 public static function create_contacts_is_deprecated() {
320 * Delete contacts parameters description.
322 * @return external_function_parameters
325 public static function delete_contacts_parameters() {
326 return new external_function_parameters(
328 'userids' => new external_multiple_structure(
329 new external_value(PARAM_INT, 'User ID'),
332 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
333 current user', VALUE_DEFAULT, 0)
341 * @param array $userids array of user IDs.
342 * @param int $userid The id of the user we are deleting the contacts for
346 public static function delete_contacts($userids, $userid = 0) {
349 // Check if messaging is enabled.
350 if (empty($CFG->messaging)) {
351 throw new moodle_exception('disabled', 'message');
354 if (empty($userid)) {
359 $context = context_system::instance();
360 self::validate_context($context);
362 $params = array('userids' => $userids, 'userid' => $userid);
363 $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
365 $capability = 'moodle/site:manageallmessaging';
366 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
367 throw new required_capability_exception($context, $capability, 'nopermissions', '');
370 foreach ($params['userids'] as $id) {
371 \core_message\api::remove_contact($params['userid'], $id);
378 * Delete contacts return description.
380 * @return external_description
383 public static function delete_contacts_returns() {
388 * Block user parameters description.
390 * @return external_function_parameters
392 public static function block_user_parameters() {
393 return new external_function_parameters(
395 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
396 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
404 * @param int $userid The id of the user who is blocking
405 * @param int $blockeduserid The id of the user being blocked
406 * @return external_description
408 public static function block_user(int $userid, int $blockeduserid) {
411 // Check if messaging is enabled.
412 if (empty($CFG->messaging)) {
413 throw new moodle_exception('disabled', 'message');
417 $context = context_system::instance();
418 self::validate_context($context);
420 $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
421 $params = self::validate_parameters(self::block_user_parameters(), $params);
423 $capability = 'moodle/site:manageallmessaging';
424 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
425 throw new required_capability_exception($context, $capability, 'nopermissions', '');
428 if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
429 \core_message\api::block_user($params['userid'], $params['blockeduserid']);
436 * Block user return description.
438 * @return external_description
440 public static function block_user_returns() {
441 return new external_warnings();
445 * Unblock user parameters description.
447 * @return external_function_parameters
449 public static function unblock_user_parameters() {
450 return new external_function_parameters(
452 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
453 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
461 * @param int $userid The id of the user who is unblocking
462 * @param int $unblockeduserid The id of the user being unblocked
464 public static function unblock_user(int $userid, int $unblockeduserid) {
467 // Check if messaging is enabled.
468 if (empty($CFG->messaging)) {
469 throw new moodle_exception('disabled', 'message');
473 $context = context_system::instance();
474 self::validate_context($context);
476 $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
477 $params = self::validate_parameters(self::unblock_user_parameters(), $params);
479 $capability = 'moodle/site:manageallmessaging';
480 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
481 throw new required_capability_exception($context, $capability, 'nopermissions', '');
484 \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
490 * Unblock user return description.
492 * @return external_description
494 public static function unblock_user_returns() {
495 return new external_warnings();
499 * Block contacts parameters description.
501 * @deprecated since Moodle 3.6
502 * @return external_function_parameters
505 public static function block_contacts_parameters() {
506 return new external_function_parameters(
508 'userids' => new external_multiple_structure(
509 new external_value(PARAM_INT, 'User ID'),
512 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
513 current user', VALUE_DEFAULT, 0)
521 * @deprecated since Moodle 3.6
522 * @param array $userids array of user IDs.
523 * @param int $userid The id of the user we are blocking the contacts for
524 * @return external_description
527 public static function block_contacts($userids, $userid = 0) {
530 // Check if messaging is enabled.
531 if (empty($CFG->messaging)) {
532 throw new moodle_exception('disabled', 'message');
535 if (empty($userid)) {
540 $context = context_system::instance();
541 self::validate_context($context);
543 $params = array('userids' => $userids, 'userid' => $userid);
544 $params = self::validate_parameters(self::block_contacts_parameters(), $params);
546 $capability = 'moodle/site:manageallmessaging';
547 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
548 throw new required_capability_exception($context, $capability, 'nopermissions', '');
552 foreach ($params['userids'] as $id) {
553 if (!message_block_contact($id, $params['userid'])) {
557 'warningcode' => 'contactnotblocked',
558 'message' => 'The contact could not be blocked'
566 * Block contacts return description.
568 * @deprecated since Moodle 3.6
569 * @return external_description
572 public static function block_contacts_returns() {
573 return new external_warnings();
577 * Marking the method as deprecated.
581 public static function block_contacts_is_deprecated() {
586 * Unblock contacts parameters description.
588 * @deprecated since Moodle 3.6
589 * @return external_function_parameters
592 public static function unblock_contacts_parameters() {
593 return new external_function_parameters(
595 'userids' => new external_multiple_structure(
596 new external_value(PARAM_INT, 'User ID'),
599 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
600 current user', VALUE_DEFAULT, 0)
608 * @param array $userids array of user IDs.
609 * @param int $userid The id of the user we are unblocking the contacts for
613 public static function unblock_contacts($userids, $userid = 0) {
616 // Check if messaging is enabled.
617 if (empty($CFG->messaging)) {
618 throw new moodle_exception('disabled', 'message');
621 if (empty($userid)) {
626 $context = context_system::instance();
627 self::validate_context($context);
629 $params = array('userids' => $userids, 'userid' => $userid);
630 $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
632 $capability = 'moodle/site:manageallmessaging';
633 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
634 throw new required_capability_exception($context, $capability, 'nopermissions', '');
637 foreach ($params['userids'] as $id) {
638 message_unblock_contact($id, $params['userid']);
645 * Unblock contacts return description.
647 * @deprecated since Moodle 3.6
648 * @return external_description
651 public static function unblock_contacts_returns() {
656 * Marking the method as deprecated.
660 public static function unblock_contacts_is_deprecated() {
665 * Returns contact requests parameters description.
667 * @return external_function_parameters
669 public static function get_contact_requests_parameters() {
670 return new external_function_parameters(
672 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
673 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
674 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
680 * Handles returning the contact requests for a user.
682 * This also includes the user data necessary to display information
685 * It will not include blocked users.
687 * @param int $userid The id of the user we want to get the contact requests for
688 * @param int $limitfrom
689 * @param int $limitnum
691 public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
694 // Check if messaging is enabled.
695 if (empty($CFG->messaging)) {
696 throw new moodle_exception('disabled', 'message');
700 $context = context_system::instance();
701 self::validate_context($context);
705 'limitfrom' => $limitfrom,
706 'limitnum' => $limitnum
708 $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
710 $capability = 'moodle/site:manageallmessaging';
711 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
712 throw new required_capability_exception($context, $capability, 'nopermissions', '');
715 return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
719 * Returns the contact requests return description.
721 * @return external_description
723 public static function get_contact_requests_returns() {
724 return new external_multiple_structure(
725 self::get_conversation_member_structure()
730 * Returns get conversation members parameters description.
732 * @return external_function_parameters
734 public static function get_conversation_members_parameters() {
735 return new external_function_parameters(
737 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
738 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
739 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
740 VALUE_DEFAULT, false),
741 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
742 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
748 * Returns a list of conversation members.
750 * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
751 * @param int $conversationid The id of the conversation
752 * @param bool $includecontactrequests Do we want to include contact requests with this data?
753 * @param int $limitfrom
754 * @param int $limitnum
757 public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
758 int $limitfrom = 0, int $limitnum = 0) {
761 // Check if messaging is enabled.
762 if (empty($CFG->messaging)) {
763 throw new moodle_exception('disabled', 'message');
767 $context = context_system::instance();
768 self::validate_context($context);
772 'conversationid' => $conversationid,
773 'includecontactrequests' => $includecontactrequests,
774 'limitfrom' => $limitfrom,
775 'limitnum' => $limitnum
777 $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
779 $capability = 'moodle/site:manageallmessaging';
780 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
781 throw new required_capability_exception($context, $capability, 'nopermissions', '');
784 // The user needs to be a part of the conversation before querying who the members are.
785 if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
786 throw new moodle_exception('You are not a member of this conversation.');
790 return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
791 $params['limitfrom'], $params['limitnum']);
795 * Returns the get conversation members return description.
797 * @return external_description
799 public static function get_conversation_members_returns() {
800 return new external_multiple_structure(
801 self::get_conversation_member_structure(true)
806 * Creates a contact request parameters description.
808 * @return external_function_parameters
810 public static function create_contact_request_parameters() {
811 return new external_function_parameters(
813 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
814 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
820 * Creates a contact request.
822 * @param int $userid The id of the user who is creating the contact request
823 * @param int $requesteduserid The id of the user being requested
825 public static function create_contact_request(int $userid, int $requesteduserid) {
828 // Check if messaging is enabled.
829 if (empty($CFG->messaging)) {
830 throw new moodle_exception('disabled', 'message');
834 $context = context_system::instance();
835 self::validate_context($context);
837 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
838 $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
840 $capability = 'moodle/site:manageallmessaging';
841 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
842 throw new required_capability_exception($context, $capability, 'nopermissions', '');
845 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
848 'itemid' => $params['requesteduserid'],
849 'warningcode' => 'cannotcreatecontactrequest',
850 'message' => 'You are unable to create a contact request for this user'
855 if (!\core_message\api::does_contact_request_exist($params['userid'], $params['requesteduserid'])) {
856 \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
863 * Creates a contact request return description.
865 * @return external_description
867 public static function create_contact_request_returns() {
868 return new external_warnings();
872 * Confirm a contact request parameters description.
874 * @return external_function_parameters
876 public static function confirm_contact_request_parameters() {
877 return new external_function_parameters(
879 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
880 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
886 * Confirm a contact request.
888 * @param int $userid The id of the user who is creating the contact request
889 * @param int $requesteduserid The id of the user being requested
891 public static function confirm_contact_request(int $userid, int $requesteduserid) {
894 // Check if messaging is enabled.
895 if (empty($CFG->messaging)) {
896 throw new moodle_exception('disabled', 'message');
900 $context = context_system::instance();
901 self::validate_context($context);
903 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
904 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
906 $capability = 'moodle/site:manageallmessaging';
907 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
908 throw new required_capability_exception($context, $capability, 'nopermissions', '');
911 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
917 * Confirm a contact request return description.
919 * @return external_description
921 public static function confirm_contact_request_returns() {
922 return new external_warnings();
926 * Declines a contact request parameters description.
928 * @return external_function_parameters
930 public static function decline_contact_request_parameters() {
931 return new external_function_parameters(
933 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
934 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
940 * Declines a contact request.
942 * @param int $userid The id of the user who is creating the contact request
943 * @param int $requesteduserid The id of the user being requested
945 public static function decline_contact_request(int $userid, int $requesteduserid) {
948 // Check if messaging is enabled.
949 if (empty($CFG->messaging)) {
950 throw new moodle_exception('disabled', 'message');
954 $context = context_system::instance();
955 self::validate_context($context);
957 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
958 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
960 $capability = 'moodle/site:manageallmessaging';
961 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
962 throw new required_capability_exception($context, $capability, 'nopermissions', '');
965 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
971 * Declines a contact request return description.
973 * @return external_description
975 public static function decline_contact_request_returns() {
976 return new external_warnings();
980 * Return the structure of a message area contact.
982 * @return external_single_structure
985 private static function get_messagearea_contact_structure() {
986 return new external_single_structure(
988 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
989 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
990 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
991 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
992 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
993 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
994 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
995 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
996 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
997 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
998 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
999 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1000 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1001 VALUE_DEFAULT, null),
1007 * Return the structure of a conversation.
1009 * @return external_single_structure
1013 private static function get_conversation_structure() {
1014 return new external_single_structure(
1016 'id' => new external_value(PARAM_INT, 'The conversation id'),
1017 'name' => new external_value(PARAM_NOTAGS, 'The conversation name, if set', VALUE_DEFAULT, null),
1018 'subname' => new external_value(PARAM_NOTAGS, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1019 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1020 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group)'),
1021 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1022 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked conversation this conversation as a favourite'),
1023 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1024 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1025 VALUE_DEFAULT, null),
1026 'members' => new external_multiple_structure(
1027 self::get_conversation_member_structure(true)
1029 'messages' => new external_multiple_structure(
1030 self::get_conversation_message_structure()
1037 * Return the structure of a conversation member.
1039 * @param bool $includecontactrequests Are we including contact requests?
1040 * @param bool $includeconversations Are we including conversations?
1041 * @return external_single_structure
1044 private static function get_conversation_member_structure(bool $includecontactrequests = false,
1045 bool $includeconversations = false) {
1047 'id' => new external_value(PARAM_INT, 'The user id'),
1048 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1049 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1050 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1051 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1052 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1053 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1054 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1055 'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1056 'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1057 'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1060 if ($includecontactrequests) {
1061 $result['contactrequests'] = new external_multiple_structure(
1062 new external_single_structure(
1064 'id' => new external_value(PARAM_INT, 'The id of the message'),
1065 'userid' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1066 'requesteduserid' => new external_value(PARAM_RAW, 'The text of the message'),
1067 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1069 ), 'The contact requests', VALUE_OPTIONAL
1073 if ($includeconversations) {
1074 $result['conversations'] = new external_multiple_structure(new external_single_structure(
1076 'id' => new external_value(PARAM_INT, 'Conversations id'),
1077 'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1078 'name' => new external_value(PARAM_TEXT, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1079 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1080 ), 'information about conversation', VALUE_OPTIONAL),
1081 'Conversations between users', VALUE_OPTIONAL
1085 return new external_single_structure(
1091 * Return the structure of a message area message.
1093 * @return external_single_structure
1096 private static function get_conversation_message_structure() {
1097 return new external_single_structure(
1099 'id' => new external_value(PARAM_INT, 'The id of the message'),
1100 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1101 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1102 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1108 * Return the structure of a message area message.
1110 * @return external_single_structure
1113 private static function get_messagearea_message_structure() {
1114 return new external_single_structure(
1116 'id' => new external_value(PARAM_INT, 'The id of the message'),
1117 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1118 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1119 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1120 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1121 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1122 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1123 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1124 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1125 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1131 * Get messagearea search users in course parameters.
1133 * @deprecated since 3.6
1135 * @return external_function_parameters
1138 public static function data_for_messagearea_search_users_in_course_parameters() {
1139 return new external_function_parameters(
1141 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1142 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1143 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1144 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1145 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1151 * Get messagearea search users in course results.
1153 * @deprecated since 3.6
1155 * NOTE: We are deprecating this function but not search_users_in_course API function for backwards compatibility
1156 * with messaging UI. But should be removed once new group messaging UI is in place and old messaging UI is removed.
1157 * Followup: MDL-63915
1159 * @param int $userid The id of the user who is performing the search
1160 * @param int $courseid The id of the course
1161 * @param string $search The string being searched
1162 * @param int $limitfrom
1163 * @param int $limitnum
1165 * @throws moodle_exception
1168 public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1170 global $CFG, $PAGE, $USER;
1172 // Check if messaging is enabled.
1173 if (empty($CFG->messaging)) {
1174 throw new moodle_exception('disabled', 'message');
1177 $systemcontext = context_system::instance();
1180 'userid' => $userid,
1181 'courseid' => $courseid,
1182 'search' => $search,
1183 'limitfrom' => $limitfrom,
1184 'limitnum' => $limitnum
1186 $params = self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1187 self::validate_context($systemcontext);
1189 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1190 throw new moodle_exception('You do not have permission to perform this action.');
1193 $users = \core_message\api::search_users_in_course(
1195 $params['courseid'],
1197 $params['limitfrom'],
1200 $results = new \core_message\output\messagearea\user_search_results($users);
1202 $renderer = $PAGE->get_renderer('core_message');
1203 return $results->export_for_template($renderer);
1207 * Get messagearea search users in course returns.
1209 * @deprecated since 3.6
1211 * @return external_single_structure
1214 public static function data_for_messagearea_search_users_in_course_returns() {
1215 return new external_single_structure(
1217 'contacts' => new external_multiple_structure(
1218 self::get_messagearea_contact_structure()
1225 * Marking the method as deprecated.
1229 public static function data_for_messagearea_search_users_in_course_is_deprecated() {
1234 * Get messagearea search users parameters.
1236 * @deprecated since 3.6
1238 * @return external_function_parameters
1241 public static function data_for_messagearea_search_users_parameters() {
1242 return new external_function_parameters(
1244 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1245 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1246 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1252 * Get messagearea search users results.
1254 * @deprecated since 3.6
1256 * NOTE: We are deprecating this function but not search_users API function for backwards compatibility
1257 * with messaging UI. But should be removed once new group messaging UI is in place and old messaging UI is removed.
1258 * Followup: MDL-63915
1260 * @param int $userid The id of the user who is performing the search
1261 * @param string $search The string being searched
1262 * @param int $limitnum
1264 * @throws moodle_exception
1267 public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1268 global $CFG, $PAGE, $USER;
1270 // Check if messaging is enabled.
1271 if (empty($CFG->messaging)) {
1272 throw new moodle_exception('disabled', 'message');
1275 $systemcontext = context_system::instance();
1278 'userid' => $userid,
1279 'search' => $search,
1280 'limitnum' => $limitnum
1282 $params = self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1283 self::validate_context($systemcontext);
1285 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1286 throw new moodle_exception('You do not have permission to perform this action.');
1289 list($contacts, $courses, $noncontacts) = \core_message\api::search_users(
1295 $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1297 $renderer = $PAGE->get_renderer('core_message');
1298 return $search->export_for_template($renderer);
1302 * Get messagearea search users returns.
1304 * @deprecated since 3.6
1306 * @return external_single_structure
1309 public static function data_for_messagearea_search_users_returns() {
1310 return new external_single_structure(
1312 'contacts' => new external_multiple_structure(
1313 self::get_messagearea_contact_structure()
1315 'courses' => new external_multiple_structure(
1316 new external_single_structure(
1318 'id' => new external_value(PARAM_INT, 'The course id'),
1319 'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1320 'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1324 'noncontacts' => new external_multiple_structure(
1325 self::get_messagearea_contact_structure()
1332 * Marking the method as deprecated.
1336 public static function data_for_messagearea_search_users_is_deprecated() {
1341 * Get messagearea message search users parameters.
1343 * @return external_function_parameters
1346 public static function message_search_users_parameters() {
1347 return new external_function_parameters(
1349 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1350 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1351 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1352 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1358 * Get search users results.
1360 * @param int $userid The id of the user who is performing the search
1361 * @param string $search The string being searched
1362 * @param int $limitfrom
1363 * @param int $limitnum
1365 * @throws moodle_exception
1368 public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1371 // Check if messaging is enabled.
1372 if (empty($CFG->messaging)) {
1373 throw new moodle_exception('disabled', 'message');
1376 $systemcontext = context_system::instance();
1379 'userid' => $userid,
1380 'search' => $search,
1381 'limitfrom' => $limitfrom,
1382 'limitnum' => $limitnum
1384 $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1385 self::validate_context($systemcontext);
1387 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1388 throw new moodle_exception('You do not have permission to perform this action.');
1391 list($contacts, $noncontacts) = \core_message\api::message_search_users(
1394 $params['limitfrom'],
1395 $params['limitnum']);
1397 return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1401 * Get messagearea message search users returns.
1403 * @return external_single_structure
1406 public static function message_search_users_returns() {
1407 return new external_single_structure(
1409 'contacts' => new external_multiple_structure(
1410 self::get_conversation_member_structure(false, true)
1412 'noncontacts' => new external_multiple_structure(
1413 self::get_conversation_member_structure(false, true)
1420 * Get messagearea search messages parameters.
1422 * @return external_function_parameters
1425 public static function data_for_messagearea_search_messages_parameters() {
1426 return new external_function_parameters(
1428 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1429 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1430 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1431 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1437 * Get messagearea search messages results.
1439 * @param int $userid The id of the user who is performing the search
1440 * @param string $search The string being searched
1441 * @param int $limitfrom
1442 * @param int $limitnum
1444 * @throws moodle_exception
1447 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1448 global $CFG, $PAGE, $USER;
1450 // Check if messaging is enabled.
1451 if (empty($CFG->messaging)) {
1452 throw new moodle_exception('disabled', 'message');
1455 $systemcontext = context_system::instance();
1458 'userid' => $userid,
1459 'search' => $search,
1460 'limitfrom' => $limitfrom,
1461 'limitnum' => $limitnum
1464 $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1465 self::validate_context($systemcontext);
1467 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1468 throw new moodle_exception('You do not have permission to perform this action.');
1471 $messages = \core_message\api::search_messages(
1474 $params['limitfrom'],
1477 $results = new \core_message\output\messagearea\message_search_results($messages);
1479 $renderer = $PAGE->get_renderer('core_message');
1480 return $results->export_for_template($renderer);
1484 * Get messagearea search messages returns.
1486 * @return external_single_structure
1489 public static function data_for_messagearea_search_messages_returns() {
1490 return new external_single_structure(
1492 'contacts' => new external_multiple_structure(
1493 self::get_messagearea_contact_structure()
1500 * Get conversations parameters.
1502 * @return external_function_parameters
1505 public static function get_conversations_parameters() {
1506 return new external_function_parameters(
1508 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1509 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1510 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1511 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1512 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1513 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1514 VALUE_DEFAULT, null),
1521 * Get the list of conversations for the user.
1523 * @param int $userid The id of the user who is performing the search
1524 * @param int $limitfrom
1525 * @param int $limitnum
1526 * @param int|null $type
1527 * @param bool|null $favourites
1529 * @throws \moodle_exception if the messaging feature is disabled on the site.
1532 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null) {
1535 // All the standard BL checks.
1536 if (empty($CFG->messaging)) {
1537 throw new moodle_exception('disabled', 'message');
1541 'userid' => $userid,
1542 'limitfrom' => $limitfrom,
1543 'limitnum' => $limitnum,
1545 'favourites' => $favourites
1547 $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1549 $systemcontext = context_system::instance();
1550 self::validate_context($systemcontext);
1552 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1553 throw new moodle_exception('You do not have permission to perform this action.');
1556 $conversations = \core_message\api::get_conversations(
1558 $params['limitfrom'],
1559 $params['limitnum'],
1561 $params['favourites']
1564 return (object) ['conversations' => $conversations];
1568 * Get conversations returns.
1570 * @return external_single_structure
1573 public static function get_conversations_returns() {
1574 return new external_single_structure(
1576 'conversations' => new external_multiple_structure(
1577 self::get_conversation_structure()
1584 * The messagearea conversations parameters.
1586 * @deprecated since 3.6
1587 * @return external_function_parameters
1590 public static function data_for_messagearea_conversations_parameters() {
1591 return new external_function_parameters(
1593 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1594 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1595 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1601 * Get messagearea conversations.
1603 * NOTE FOR FINAL DEPRECATION:
1604 * When removing this method, please also consider removal of get_conversations_legacy_formatter()
1605 * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
1606 * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
1609 * @deprecated since 3.6
1610 * @param int $userid The id of the user who we are viewing conversations for
1611 * @param int $limitfrom
1612 * @param int $limitnum
1614 * @throws moodle_exception
1617 public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1618 global $CFG, $PAGE, $USER;
1620 // Check if messaging is enabled.
1621 if (empty($CFG->messaging)) {
1622 throw new moodle_exception('disabled', 'message');
1625 $systemcontext = context_system::instance();
1628 'userid' => $userid,
1629 'limitfrom' => $limitfrom,
1630 'limitnum' => $limitnum
1632 $params = self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1633 self::validate_context($systemcontext);
1635 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1636 throw new moodle_exception('You do not have permission to perform this action.');
1639 $conversations = \core_message\api::get_conversations($params['userid'], $params['limitfrom'], $params['limitnum']);
1641 // Format the conversations in the legacy style, as the get_conversations method has since been changed.
1642 $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
1644 $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1646 $renderer = $PAGE->get_renderer('core_message');
1647 return $conversations->export_for_template($renderer);
1651 * The messagearea conversations return structure.
1653 * @deprecated since 3.6
1654 * @return external_single_structure
1657 public static function data_for_messagearea_conversations_returns() {
1658 return new external_single_structure(
1660 'contacts' => new external_multiple_structure(
1661 self::get_messagearea_contact_structure()
1668 * Marking the method as deprecated.
1672 public static function data_for_messagearea_conversations_is_deprecated() {
1677 * The messagearea contacts return parameters.
1679 * @deprecated since 3.6
1680 * @return external_function_parameters
1683 public static function data_for_messagearea_contacts_parameters() {
1684 return self::data_for_messagearea_conversations_parameters();
1688 * Get messagearea contacts parameters.
1690 * @deprecated since 3.6
1691 * @param int $userid The id of the user who we are viewing conversations for
1692 * @param int $limitfrom
1693 * @param int $limitnum
1695 * @throws moodle_exception
1698 public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1699 global $CFG, $PAGE, $USER;
1701 // Check if messaging is enabled.
1702 if (empty($CFG->messaging)) {
1703 throw new moodle_exception('disabled', 'message');
1706 $systemcontext = context_system::instance();
1709 'userid' => $userid,
1710 'limitfrom' => $limitfrom,
1711 'limitnum' => $limitnum
1713 $params = self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1714 self::validate_context($systemcontext);
1716 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1717 throw new moodle_exception('You do not have permission to perform this action.');
1720 $contacts = \core_message\api::get_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1721 $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1723 $renderer = $PAGE->get_renderer('core_message');
1724 return $contacts->export_for_template($renderer);
1728 * The messagearea contacts return structure.
1730 * @deprecated since 3.6
1731 * @return external_single_structure
1734 public static function data_for_messagearea_contacts_returns() {
1735 return self::data_for_messagearea_conversations_returns();
1739 * Marking the method as deprecated.
1743 public static function data_for_messagearea_contacts_is_deprecated() {
1748 * The messagearea messages parameters.
1750 * @deprecated since 3.6
1751 * @return external_function_parameters
1754 public static function data_for_messagearea_messages_parameters() {
1755 return new external_function_parameters(
1757 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1758 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1759 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1760 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1761 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1762 'timefrom' => new external_value(PARAM_INT,
1763 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1769 * Get messagearea messages.
1771 * @deprecated since 3.6
1772 * @param int $currentuserid The current user's id
1773 * @param int $otheruserid The other user's id
1774 * @param int $limitfrom
1775 * @param int $limitnum
1776 * @param boolean $newest
1778 * @throws moodle_exception
1781 public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1782 $newest = false, $timefrom = 0) {
1783 global $CFG, $PAGE, $USER;
1785 // Check if messaging is enabled.
1786 if (empty($CFG->messaging)) {
1787 throw new moodle_exception('disabled', 'message');
1790 $systemcontext = context_system::instance();
1793 'currentuserid' => $currentuserid,
1794 'otheruserid' => $otheruserid,
1795 'limitfrom' => $limitfrom,
1796 'limitnum' => $limitnum,
1797 'newest' => $newest,
1798 'timefrom' => $timefrom,
1800 $params = self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1801 self::validate_context($systemcontext);
1803 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1804 throw new moodle_exception('You do not have permission to perform this action.');
1807 if ($params['newest']) {
1808 $sort = 'timecreated DESC';
1810 $sort = 'timecreated ASC';
1813 // We need to enforce a one second delay on messages to avoid race conditions of current
1814 // messages still being sent.
1816 // There is a chance that we could request messages before the current time's
1817 // second has elapsed and while other messages are being sent in that same second. In which
1818 // case those messages will be lost.
1820 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1821 if (!empty($params['timefrom'])) {
1822 $timeto = time() - 1;
1827 // No requesting messages from the current time, as stated above.
1828 if ($params['timefrom'] == time()) {
1831 $messages = \core_message\api::get_messages($params['currentuserid'], $params['otheruserid'], $params['limitfrom'],
1832 $params['limitnum'], $sort, $params['timefrom'], $timeto);
1835 $messages = new \core_message\output\messagearea\messages($params['currentuserid'], $params['otheruserid'], $messages);
1837 $renderer = $PAGE->get_renderer('core_message');
1838 return $messages->export_for_template($renderer);
1842 * The messagearea messages return structure.
1844 * @deprecated since 3.6
1845 * @return external_single_structure
1848 public static function data_for_messagearea_messages_returns() {
1849 return new external_single_structure(
1851 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1852 the messages on behalf of?'),
1853 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1854 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1855 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1856 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1857 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1858 'messages' => new external_multiple_structure(
1859 self::get_messagearea_message_structure()
1861 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1867 * Marking the method as deprecated.
1871 public static function data_for_messagearea_messages_is_deprecated() {
1876 * The conversation messages parameters.
1878 * @return external_function_parameters
1881 public static function get_conversation_messages_parameters() {
1882 return new external_function_parameters(
1884 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1885 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1886 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1887 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1888 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1889 'timefrom' => new external_value(PARAM_INT,
1890 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1896 * Get conversation messages.
1898 * @param int $currentuserid The current user's id.
1899 * @param int $convid The conversation id.
1900 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1901 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1902 * @param bool $newest True for getting first newest messages, false otherwise.
1903 * @param int $timefrom The time from the conversation messages to get.
1904 * @return stdClass The messages and members who have sent some of these messages.
1905 * @throws moodle_exception
1908 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1909 bool $newest = false, int $timefrom = 0) {
1910 global $CFG, $PAGE, $USER;
1912 // Check if messaging is enabled.
1913 if (empty($CFG->messaging)) {
1914 throw new moodle_exception('disabled', 'message');
1917 $systemcontext = context_system::instance();
1920 'currentuserid' => $currentuserid,
1921 'convid' => $convid,
1922 'limitfrom' => $limitfrom,
1923 'limitnum' => $limitnum,
1924 'newest' => $newest,
1925 'timefrom' => $timefrom,
1927 $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1928 self::validate_context($systemcontext);
1930 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1931 throw new moodle_exception('You do not have permission to perform this action.');
1934 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1936 // We need to enforce a one second delay on messages to avoid race conditions of current
1937 // messages still being sent.
1939 // There is a chance that we could request messages before the current time's
1940 // second has elapsed and while other messages are being sent in that same second. In which
1941 // case those messages will be lost.
1943 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1944 $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1946 // No requesting messages from the current time, as stated above.
1947 if ($params['timefrom'] == time()) {
1950 $messages = \core_message\api::get_conversation_messages(
1951 $params['currentuserid'],
1953 $params['limitfrom'],
1954 $params['limitnum'],
1956 $params['timefrom'],
1964 * The messagearea messages return structure.
1966 * @return external_single_structure
1969 public static function get_conversation_messages_returns() {
1970 return new external_single_structure(
1972 'id' => new external_value(PARAM_INT, 'The conversation id'),
1973 'members' => new external_multiple_structure(
1974 self::get_conversation_member_structure()
1976 'messages' => new external_multiple_structure(
1977 self::get_conversation_message_structure()
1984 * The get most recent message return parameters.
1986 * @deprecated since 3.6
1987 * @return external_function_parameters
1990 public static function data_for_messagearea_get_most_recent_message_parameters() {
1991 return new external_function_parameters(
1993 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1994 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2000 * Get the most recent message in a conversation.
2002 * @deprecated since 3.6
2003 * @param int $currentuserid The current user's id
2004 * @param int $otheruserid The other user's id
2006 * @throws moodle_exception
2009 public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
2010 global $CFG, $PAGE, $USER;
2012 // Check if messaging is enabled.
2013 if (empty($CFG->messaging)) {
2014 throw new moodle_exception('disabled', 'message');
2017 $systemcontext = context_system::instance();
2020 'currentuserid' => $currentuserid,
2021 'otheruserid' => $otheruserid
2023 $params = self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
2024 self::validate_context($systemcontext);
2026 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2027 throw new moodle_exception('You do not have permission to perform this action.');
2030 $message = \core_message\api::get_most_recent_message($params['currentuserid'], $params['otheruserid']);
2031 $message = new \core_message\output\messagearea\message($message);
2033 $renderer = $PAGE->get_renderer('core_message');
2034 return $message->export_for_template($renderer);
2038 * The get most recent message return structure.
2040 * @deprecated since 3.6
2041 * @return external_single_structure
2044 public static function data_for_messagearea_get_most_recent_message_returns() {
2045 return self::get_messagearea_message_structure();
2049 * Marking the method as deprecated.
2053 public static function data_for_messagearea_get_most_recent_message_is_deprecated() {
2058 * The get profile parameters.
2060 * @deprecated since 3.6
2061 * @return external_function_parameters
2064 public static function data_for_messagearea_get_profile_parameters() {
2065 return new external_function_parameters(
2067 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2068 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
2074 * Get the profile information for a contact.
2076 * @deprecated since 3.6
2077 * @param int $currentuserid The current user's id
2078 * @param int $otheruserid The id of the user whose profile we are viewing
2080 * @throws moodle_exception
2083 public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
2084 global $CFG, $PAGE, $USER;
2086 // Check if messaging is enabled.
2087 if (empty($CFG->messaging)) {
2088 throw new moodle_exception('disabled', 'message');
2091 $systemcontext = context_system::instance();
2094 'currentuserid' => $currentuserid,
2095 'otheruserid' => $otheruserid
2097 $params = self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
2098 self::validate_context($systemcontext);
2100 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2101 throw new moodle_exception('You do not have permission to perform this action.');
2104 $profile = \core_message\api::get_profile($params['currentuserid'], $params['otheruserid']);
2105 $profile = new \core_message\output\messagearea\profile($profile);
2107 $renderer = $PAGE->get_renderer('core_message');
2108 return $profile->export_for_template($renderer);
2112 * The get profile return structure.
2114 * @deprecated since 3.6
2115 * @return external_single_structure
2118 public static function data_for_messagearea_get_profile_returns() {
2119 return new external_single_structure(
2121 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
2122 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
2123 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
2124 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
2125 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
2126 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
2127 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
2128 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2129 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2130 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
2131 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
2137 * Marking the method as deprecated.
2141 public static function data_for_messagearea_get_profile_is_deprecated() {
2146 * Get contacts parameters description.
2148 * @return external_function_parameters
2151 public static function get_contacts_parameters() {
2152 return new external_function_parameters(array());
2158 * @return external_description
2161 public static function get_contacts() {
2162 global $CFG, $PAGE, $USER;
2164 // Check if messaging is enabled.
2165 if (empty($CFG->messaging)) {
2166 throw new moodle_exception('disabled', 'message');
2169 require_once($CFG->dirroot . '/user/lib.php');
2171 $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
2172 $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
2173 foreach ($contacts as $contact) {
2176 if (\core_message\helper::is_online($contact->lastaccess)) {
2180 $newcontact = array(
2181 'id' => $contact->id,
2182 'fullname' => fullname($contact),
2183 'unread' => $contact->messagecount
2186 $userpicture = new user_picture($contact);
2187 $userpicture->size = 1; // Size f1.
2188 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2189 $userpicture->size = 0; // Size f2.
2190 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2192 $allcontacts[$mode][$contact->id] = $newcontact;
2195 $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
2196 foreach ($strangers as $contact) {
2197 $newcontact = array(
2198 'id' => $contact->id,
2199 'fullname' => fullname($contact),
2200 'unread' => $contact->messagecount
2203 $userpicture = new user_picture($contact);
2204 $userpicture->size = 1; // Size f1.
2205 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2206 $userpicture->size = 0; // Size f2.
2207 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2209 $allcontacts['strangers'][$contact->id] = $newcontact;
2212 // Add noreply user and support user to the list, if they don't exist.
2213 $supportuser = core_user::get_support_user();
2214 if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
2215 $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
2216 if ($supportuser->messagecount > 0) {
2217 $supportuser->fullname = fullname($supportuser);
2218 $supportuser->unread = $supportuser->messagecount;
2219 $allcontacts['strangers'][$supportuser->id] = $supportuser;
2223 $noreplyuser = core_user::get_noreply_user();
2224 if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
2225 $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
2226 if ($noreplyuser->messagecount > 0) {
2227 $noreplyuser->fullname = fullname($noreplyuser);
2228 $noreplyuser->unread = $noreplyuser->messagecount;
2229 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
2233 return $allcontacts;
2237 * Get contacts return description.
2239 * @return external_description
2242 public static function get_contacts_returns() {
2243 return new external_single_structure(
2245 'online' => new external_multiple_structure(
2246 new external_single_structure(
2248 'id' => new external_value(PARAM_INT, 'User ID'),
2249 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2250 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2251 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2252 'unread' => new external_value(PARAM_INT, 'Unread message count')
2255 'List of online contacts'
2257 'offline' => new external_multiple_structure(
2258 new external_single_structure(
2260 'id' => new external_value(PARAM_INT, 'User ID'),
2261 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2262 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2263 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2264 'unread' => new external_value(PARAM_INT, 'Unread message count')
2267 'List of offline contacts'
2269 'strangers' => new external_multiple_structure(
2270 new external_single_structure(
2272 'id' => new external_value(PARAM_INT, 'User ID'),
2273 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2274 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2275 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2276 'unread' => new external_value(PARAM_INT, 'Unread message count')
2279 'List of users that are not in the user\'s contact list but have sent a message'
2286 * Search contacts parameters description.
2288 * @return external_function_parameters
2291 public static function search_contacts_parameters() {
2292 return new external_function_parameters(
2294 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2295 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2296 VALUE_DEFAULT, false)
2304 * @param string $searchtext query string.
2305 * @param bool $onlymycourses limit the search to the user's courses only.
2306 * @return external_description
2309 public static function search_contacts($searchtext, $onlymycourses = false) {
2310 global $CFG, $USER, $PAGE;
2311 require_once($CFG->dirroot . '/user/lib.php');
2313 // Check if messaging is enabled.
2314 if (empty($CFG->messaging)) {
2315 throw new moodle_exception('disabled', 'message');
2318 require_once($CFG->libdir . '/enrollib.php');
2320 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2321 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2323 // Extra validation, we do not allow empty queries.
2324 if ($params['searchtext'] === '') {
2325 throw new moodle_exception('querystringcannotbeempty');
2328 $courseids = array();
2329 if ($params['onlymycourses']) {
2330 $mycourses = enrol_get_my_courses(array('id'));
2331 foreach ($mycourses as $mycourse) {
2332 $courseids[] = $mycourse->id;
2335 $courseids[] = SITEID;
2338 // Retrieving the users matching the query.
2339 $users = message_search_users($courseids, $params['searchtext']);
2341 foreach ($users as $user) {
2342 $results[$user->id] = $user;
2345 // Reorganising information.
2346 foreach ($results as &$user) {
2349 'fullname' => fullname($user)
2352 // Avoid undefined property notice as phone not specified.
2353 $user->phone1 = null;
2354 $user->phone2 = null;
2356 $userpicture = new user_picture($user);
2357 $userpicture->size = 1; // Size f1.
2358 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2359 $userpicture->size = 0; // Size f2.
2360 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2369 * Search contacts return description.
2371 * @return external_description
2374 public static function search_contacts_returns() {
2375 return new external_multiple_structure(
2376 new external_single_structure(
2378 'id' => new external_value(PARAM_INT, 'User ID'),
2379 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2380 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2381 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
2389 * Get messages parameters description.
2391 * @return external_function_parameters
2394 public static function get_messages_parameters() {
2395 return new external_function_parameters(
2397 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2398 'useridfrom' => new external_value(
2399 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2401 'type' => new external_value(
2402 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2403 VALUE_DEFAULT, 'both'),
2404 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2405 'newestfirst' => new external_value(
2406 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2407 VALUE_DEFAULT, true),
2408 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2409 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2415 * Get messages function implementation.
2418 * @throws invalid_parameter_exception
2419 * @throws moodle_exception
2420 * @param int $useridto the user id who received the message
2421 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2422 * @param string $type type of message to return, expected values: notifications, conversations and both
2423 * @param bool $read true for retreiving read messages, false for unread
2424 * @param bool $newestfirst true for ordering by newest first, false for oldest first
2425 * @param int $limitfrom limit from
2426 * @param int $limitnum limit num
2427 * @return external_description
2429 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2430 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2433 $warnings = array();
2436 'useridto' => $useridto,
2437 'useridfrom' => $useridfrom,
2440 'newestfirst' => $newestfirst,
2441 'limitfrom' => $limitfrom,
2442 'limitnum' => $limitnum
2445 $params = self::validate_parameters(self::get_messages_parameters(), $params);
2447 $context = context_system::instance();
2448 self::validate_context($context);
2450 $useridto = $params['useridto'];
2451 $useridfrom = $params['useridfrom'];
2452 $type = $params['type'];
2453 $read = $params['read'];
2454 $newestfirst = $params['newestfirst'];
2455 $limitfrom = $params['limitfrom'];
2456 $limitnum = $params['limitnum'];
2458 $allowedvalues = array('notifications', 'conversations', 'both');
2459 if (!in_array($type, $allowedvalues)) {
2460 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2461 'allowed values are: ' . implode(',', $allowedvalues));
2464 // Check if private messaging between users is allowed.
2465 if (empty($CFG->messaging)) {
2466 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2467 if ($type == "conversations") {
2468 throw new moodle_exception('disabled', 'message');
2470 if ($type == "both") {
2472 $warning['item'] = 'message';
2473 $warning['itemid'] = $USER->id;
2474 $warning['warningcode'] = '1';
2475 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2476 Only notifications will be returned';
2477 $warnings[] = $warning;
2481 if (!empty($useridto)) {
2482 if (core_user::is_real_user($useridto)) {
2483 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2485 throw new moodle_exception('invaliduser');
2489 if (!empty($useridfrom)) {
2490 // We use get_user here because the from user can be the noreply or support user.
2491 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2494 // Check if the current user is the sender/receiver or just a privileged user.
2495 if ($useridto != $USER->id and $useridfrom != $USER->id and
2496 !has_capability('moodle/site:readallmessages', $context)) {
2497 throw new moodle_exception('accessdenied', 'admin');
2500 // Which type of messages to retrieve.
2501 $notifications = -1;
2502 if ($type != 'both') {
2503 $notifications = ($type == 'notifications') ? 1 : 0;
2506 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2507 $sort = "mr.timecreated $orderdirection";
2509 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2510 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2512 // In some cases, we don't need to get the to/from user objects from the sql query.
2513 $userfromfullname = '';
2514 $usertofullname = '';
2516 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2517 if (!empty($useridto)) {
2518 $usertofullname = fullname($userto, $canviewfullname);
2519 // The user from may or may not be filled.
2520 if (!empty($useridfrom)) {
2521 $userfromfullname = fullname($userfrom, $canviewfullname);
2524 // If the useridto field is empty, the useridfrom must be filled.
2525 $userfromfullname = fullname($userfrom, $canviewfullname);
2527 foreach ($messages as $mid => $message) {
2529 // Do not return deleted messages.
2530 if (!$message->notification) {
2531 if (($useridto == $USER->id and $message->timeusertodeleted) or
2532 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2533 unset($messages[$mid]);
2538 // We need to get the user from the query.
2539 if (empty($userfromfullname)) {
2540 // Check for non-reply and support users.
2541 if (core_user::is_real_user($message->useridfrom)) {
2542 $user = new stdClass();
2543 $user = username_load_fields_from_object($user, $message, 'userfrom');
2544 $message->userfromfullname = fullname($user, $canviewfullname);
2546 $user = core_user::get_user($message->useridfrom);
2547 $message->userfromfullname = fullname($user, $canviewfullname);
2550 $message->userfromfullname = $userfromfullname;
2553 // We need to get the user from the query.
2554 if (empty($usertofullname)) {
2555 $user = new stdClass();
2556 $user = username_load_fields_from_object($user, $message, 'userto');
2557 $message->usertofullname = fullname($user, $canviewfullname);
2559 $message->usertofullname = $usertofullname;
2562 $message->text = message_format_message_text($message);
2563 $messages[$mid] = (array) $message;
2568 'messages' => $messages,
2569 'warnings' => $warnings
2576 * Get messages return description.
2578 * @return external_single_structure
2581 public static function get_messages_returns() {
2582 return new external_single_structure(
2584 'messages' => new external_multiple_structure(
2585 new external_single_structure(
2587 'id' => new external_value(PARAM_INT, 'Message id'),
2588 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2589 'useridto' => new external_value(PARAM_INT, 'User to id'),
2590 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2591 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2592 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2593 'fullmessageformat' => new external_format_value('fullmessage'),
2594 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2595 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2596 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2597 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2598 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2599 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2600 'timeread' => new external_value(PARAM_INT, 'Time read'),
2601 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2602 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2606 'warnings' => new external_warnings()
2612 * Mark all notifications as read parameters description.
2614 * @return external_function_parameters
2617 public static function mark_all_notifications_as_read_parameters() {
2618 return new external_function_parameters(
2620 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2621 'useridfrom' => new external_value(
2622 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2629 * Mark all notifications as read function.
2632 * @throws invalid_parameter_exception
2633 * @throws moodle_exception
2634 * @param int $useridto the user id who received the message
2635 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2636 * @return external_description
2638 public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2641 $params = self::validate_parameters(
2642 self::mark_all_notifications_as_read_parameters(),
2644 'useridto' => $useridto,
2645 'useridfrom' => $useridfrom,
2649 $context = context_system::instance();
2650 self::validate_context($context);
2652 $useridto = $params['useridto'];
2653 $useridfrom = $params['useridfrom'];
2655 if (!empty($useridto)) {
2656 if (core_user::is_real_user($useridto)) {
2657 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2659 throw new moodle_exception('invaliduser');
2663 if (!empty($useridfrom)) {
2664 // We use get_user here because the from user can be the noreply or support user.
2665 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2668 // Check if the current user is the sender/receiver or just a privileged user.
2669 if ($useridto != $USER->id and $useridfrom != $USER->id and
2670 // The deleteanymessage cap seems more reasonable here than readallmessages.
2671 !has_capability('moodle/site:deleteanymessage', $context)) {
2672 throw new moodle_exception('accessdenied', 'admin');
2675 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2681 * Mark all notifications as read return description.
2683 * @return external_single_structure
2686 public static function mark_all_notifications_as_read_returns() {
2687 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2691 * Get unread conversations count parameters description.
2693 * @return external_function_parameters
2696 public static function get_unread_conversations_count_parameters() {
2697 return new external_function_parameters(
2699 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2705 * Get unread messages count function.
2708 * @throws invalid_parameter_exception
2709 * @throws moodle_exception
2710 * @param int $useridto the user id who received the message
2711 * @return external_description
2713 public static function get_unread_conversations_count($useridto) {
2716 // Check if messaging is enabled.
2717 if (empty($CFG->messaging)) {
2718 throw new moodle_exception('disabled', 'message');
2721 $params = self::validate_parameters(
2722 self::get_unread_conversations_count_parameters(),
2723 array('useridto' => $useridto)
2726 $context = context_system::instance();
2727 self::validate_context($context);
2729 $useridto = $params['useridto'];
2731 if (!empty($useridto)) {
2732 if (core_user::is_real_user($useridto)) {
2733 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2735 throw new moodle_exception('invaliduser');
2738 $useridto = $USER->id;
2741 // Check if the current user is the receiver or just a privileged user.
2742 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2743 throw new moodle_exception('accessdenied', 'admin');
2746 return \core_message\api::count_unread_conversations($userto);
2750 * Get unread conversations count return description.
2752 * @return external_single_structure
2755 public static function get_unread_conversations_count_returns() {
2756 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2760 * Get blocked users parameters description.
2762 * @return external_function_parameters
2765 public static function get_blocked_users_parameters() {
2766 return new external_function_parameters(
2768 'userid' => new external_value(PARAM_INT,
2769 'the user whose blocked users we want to retrieve',
2776 * Retrieve a list of users blocked
2778 * @param int $userid the user whose blocked users we want to retrieve
2779 * @return external_description
2782 public static function get_blocked_users($userid) {
2783 global $CFG, $USER, $PAGE;
2785 // Warnings array, it can be empty at the end but is mandatory.
2786 $warnings = array();
2792 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2793 $userid = $params['userid'];
2795 // Validate context.
2796 $context = context_system::instance();
2797 self::validate_context($context);
2799 // Check if private messaging between users is allowed.
2800 if (empty($CFG->messaging)) {
2801 throw new moodle_exception('disabled', 'message');
2804 $user = core_user::get_user($userid, '*', MUST_EXIST);
2805 core_user::require_active_user($user);
2807 // Check if we have permissions for retrieve the information.
2808 $capability = 'moodle/site:manageallmessaging';
2809 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2810 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2813 // Now, we can get safely all the blocked users.
2814 $users = \core_message\api::get_blocked_users($user->id);
2816 $blockedusers = array();
2817 foreach ($users as $user) {
2820 'fullname' => fullname($user),
2823 $userpicture = new user_picture($user);
2824 $userpicture->size = 1; // Size f1.
2825 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2827 $blockedusers[] = $newuser;
2831 'users' => $blockedusers,
2832 'warnings' => $warnings
2838 * Get blocked users return description.
2840 * @return external_single_structure
2843 public static function get_blocked_users_returns() {
2844 return new external_single_structure(
2846 'users' => new external_multiple_structure(
2847 new external_single_structure(
2849 'id' => new external_value(PARAM_INT, 'User ID'),
2850 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2851 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2854 'List of blocked users'
2856 'warnings' => new external_warnings()
2862 * Returns description of method parameters
2864 * @return external_function_parameters
2867 public static function mark_message_read_parameters() {
2868 return new external_function_parameters(
2870 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2871 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2878 * Mark a single message as read, trigger message_viewed event
2880 * @param int $messageid id of the message (in the message table)
2881 * @param int $timeread timestamp for when the message should be marked read
2882 * @return external_description
2883 * @throws invalid_parameter_exception
2884 * @throws moodle_exception
2887 public static function mark_message_read($messageid, $timeread) {
2888 global $CFG, $DB, $USER;
2890 // Check if private messaging between users is allowed.
2891 if (empty($CFG->messaging)) {
2892 throw new moodle_exception('disabled', 'message');
2895 // Warnings array, it can be empty at the end but is mandatory.
2896 $warnings = array();
2900 'messageid' => $messageid,
2901 'timeread' => $timeread
2903 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2905 if (empty($params['timeread'])) {
2908 $timeread = $params['timeread'];
2911 // Validate context.
2912 $context = context_system::instance();
2913 self::validate_context($context);
2915 $sql = "SELECT m.*, mcm.userid as useridto
2917 INNER JOIN {message_conversations} mc
2918 ON m.conversationid = mc.id
2919 INNER JOIN {message_conversation_members} mcm
2920 ON mcm.conversationid = mc.id
2921 LEFT JOIN {message_user_actions} mua
2922 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2923 WHERE mua.id is NULL
2924 AND mcm.userid != m.useridfrom
2926 $messageparams = [];
2927 $messageparams[] = $USER->id;
2928 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2929 $messageparams[] = $params['messageid'];
2930 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2932 if ($message->useridto != $USER->id) {
2933 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2936 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2939 'messageid' => $message->id,
2940 'warnings' => $warnings
2946 * Returns description of method result value
2948 * @return external_description
2951 public static function mark_message_read_returns() {
2952 return new external_single_structure(
2954 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2955 'warnings' => new external_warnings()
2961 * Returns description of method parameters
2963 * @return external_function_parameters
2965 public static function mark_notification_read_parameters() {
2966 return new external_function_parameters(
2968 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2969 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2976 * Mark a single notification as read.
2978 * This will trigger a 'notification_viewed' event.
2980 * @param int $notificationid id of the notification
2981 * @param int $timeread timestamp for when the notification should be marked read
2982 * @return external_description
2983 * @throws invalid_parameter_exception
2984 * @throws moodle_exception
2986 public static function mark_notification_read($notificationid, $timeread) {
2987 global $CFG, $DB, $USER;
2989 // Check if private messaging between users is allowed.
2990 if (empty($CFG->messaging)) {
2991 throw new moodle_exception('disabled', 'message');
2994 // Warnings array, it can be empty at the end but is mandatory.
2995 $warnings = array();
2999 'notificationid' => $notificationid,
3000 'timeread' => $timeread
3002 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
3004 if (empty($params['timeread'])) {
3007 $timeread = $params['timeread'];
3010 // Validate context.
3011 $context = context_system::instance();
3012 self::validate_context($context);
3014 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
3016 if ($notification->useridto != $USER->id) {
3017 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
3018 'notification as read');
3021 \core_message\api::mark_notification_as_read($notification, $timeread);
3024 'notificationid' => $notification->id,
3025 'warnings' => $warnings
3032 * Returns description of method result value
3034 * @return external_description
3036 public static function mark_notification_read_returns() {
3037 return new external_single_structure(
3039 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
3040 'warnings' => new external_warnings()
3046 * Mark all messages as read parameters description.
3048 * @deprecated since 3.6
3049 * @return external_function_parameters
3052 public static function mark_all_messages_as_read_parameters() {
3053 return new external_function_parameters(
3055 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3056 'useridfrom' => new external_value(
3057 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
3064 * Mark all messages as read function.
3066 * @deprecated since 3.6
3067 * @throws invalid_parameter_exception
3068 * @throws moodle_exception
3069 * @param int $useridto the user id who received the message
3070 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
3071 * @return external_description
3074 public static function mark_all_messages_as_read($useridto, $useridfrom) {
3077 // Check if messaging is enabled.
3078 if (empty($CFG->messaging)) {
3079 throw new moodle_exception('disabled', 'message');
3082 $params = self::validate_parameters(
3083 self::mark_all_messages_as_read_parameters(),
3085 'useridto' => $useridto,
3086 'useridfrom' => $useridfrom,
3090 $context = context_system::instance();
3091 self::validate_context($context);
3093 $useridto = $params['useridto'];
3094 $useridfrom = $params['useridfrom'];
3096 if (!empty($useridto)) {
3097 if (core_user::is_real_user($useridto)) {
3098 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3100 throw new moodle_exception('invaliduser');
3104 if (!empty($useridfrom)) {
3105 // We use get_user here because the from user can be the noreply or support user.
3106 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3109 // Check if the current user is the sender/receiver or just a privileged user.
3110 if ($useridto != $USER->id and $useridfrom != $USER->id and
3111 // The deleteanymessage cap seems more reasonable here than readallmessages.
3112 !has_capability('moodle/site:deleteanymessage', $context)) {
3113 throw new moodle_exception('accessdenied', 'admin');
3117 if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
3118 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
3121 \core_message\api::mark_all_messages_as_read($useridto);
3128 * Mark all messages as read return description.
3130 * @deprecated since 3.6
3131 * @return external_single_structure
3134 public static function mark_all_messages_as_read_returns() {
3135 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
3139 * Marking the method as deprecated.
3143 public static function mark_all_messages_as_read_is_deprecated() {
3148 * Mark all conversation messages as read parameters description.
3150 * @return external_function_parameters
3153 public static function mark_all_conversation_messages_as_read_parameters() {
3154 return new external_function_parameters(
3156 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
3158 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
3164 * Mark all conversation messages as read function.
3166 * @param int $userid The user id of who we want to delete the conversation for
3167 * @param int $conversationid The id of the conversations
3170 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
3173 // Check if messaging is enabled.
3174 if (empty($CFG->messaging)) {
3175 throw new moodle_exception('disabled', 'message');
3179 'userid' => $userid,
3180 'conversationid' => $conversationid,
3182 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
3184 $context = context_system::instance();
3185 self::validate_context($context);
3187 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3188 core_user::require_active_user($user);
3190 if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
3191 \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
3193 throw new moodle_exception('accessdenied', 'admin');
3198 * Mark all conversation messages as read return description.
3200 * @return external_warnings
3203 public static function mark_all_conversation_messages_as_read_returns() {
3204 return new external_warnings();
3208 * Returns description of method parameters.
3210 * @deprecated since 3.6
3211 * @return external_function_parameters
3214 public static function delete_conversation_parameters() {
3215 return new external_function_parameters(
3217 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3218 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
3224 * Deletes a conversation.
3226 * @deprecated since 3.6
3227 * @param int $userid The user id of who we want to delete the conversation for
3228 * @param int $otheruserid The user id of the other user in the conversation
3230 * @throws moodle_exception
3233 public static function delete_conversation($userid, $otheruserid) {
3236 // Check if private messaging between users is allowed.
3237 if (empty($CFG->messaging)) {
3238 throw new moodle_exception('disabled', 'message');
3241 // Warnings array, it can be empty at the end but is mandatory.
3242 $warnings = array();
3246 'userid' => $userid,
3247 'otheruserid' => $otheruserid,
3249 $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
3251 // Validate context.
3252 $context = context_system::instance();
3253 self::validate_context($context);
3255 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3256 core_user::require_active_user($user);
3258 if (!$conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']])) {
3262 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3263 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3266 throw new moodle_exception('You do not have permission to delete messages');
3270 'status' => $status,
3271 'warnings' => $warnings
3278 * Returns description of method result value.
3280 * @deprecated since 3.6
3281 * @return external_description
3284 public static function delete_conversation_returns() {
3285 return new external_single_structure(
3287 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
3288 'warnings' => new external_warnings()
3294 * Marking the method as deprecated.
3298 public static function delete_conversation_is_deprecated() {
3303 * Returns description of method parameters.
3305 * @return external_function_parameters
3308 public static function delete_conversations_by_id_parameters() {
3309 return new external_function_parameters(
3311 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3312 'conversationids' => new external_multiple_structure(
3313 new external_value(PARAM_INT, 'The id of the conversation'),
3314 'List of conversation IDs'
3321 * Deletes a conversation.
3323 * @param int $userid The user id of who we want to delete the conversation for
3324 * @param int[] $conversationids The ids of the conversations
3326 * @throws moodle_exception
3329 public static function delete_conversations_by_id($userid, array $conversationids) {
3332 // Check if private messaging between users is allowed.
3333 if (empty($CFG->messaging)) {
3334 throw new moodle_exception('disabled', 'message');
3339 'userid' => $userid,
3340 'conversationids' => $conversationids,
3342 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
3344 // Validate context.
3345 $context = context_system::instance();
3346 self::validate_context($context);
3348 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3349 core_user::require_active_user($user);
3351 foreach ($params['conversationids'] as $conversationid) {
3352 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3353 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3355 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
3363 * Returns description of method result value.
3365 * @return external_description
3368 public static function delete_conversations_by_id_returns() {
3369 return new external_warnings();
3373 * Returns description of method parameters
3375 * @return external_function_parameters
3378 public static function delete_message_parameters() {
3379 return new external_function_parameters(
3381 'messageid' => new external_value(PARAM_INT, 'The message id'),
3382 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
3383 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
3391 * @param int $messageid the message id
3392 * @param int $userid the user id of who we want to delete the message for
3393 * @param bool $read if is a message read (default to true)
3394 * @return external_description
3395 * @throws moodle_exception
3398 public static function delete_message($messageid, $userid, $read = true) {
3401 // Check if private messaging between users is allowed.
3402 if (empty($CFG->messaging)) {
3403 throw new moodle_exception('disabled', 'message');
3406 // Warnings array, it can be empty at the end but is mandatory.
3407 $warnings = array();
3411 'messageid' => $messageid,
3412 'userid' => $userid,
3415 $params = self::validate_parameters(self::delete_message_parameters(), $params);
3417 // Validate context.
3418 $context = context_system::instance();
3419 self::validate_context($context);
3421 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3422 core_user::require_active_user($user);
3424 if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
3425 $status = \core_message\api::delete_message($user->id, $params['messageid']);
3427 throw new moodle_exception('You do not have permission to delete this message');
3431 'status' => $status,
3432 'warnings' => $warnings