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 $systemcontext = context_system::instance();
1374 'userid' => $userid,
1375 'search' => $search,
1376 'limitfrom' => $limitfrom,
1377 'limitnum' => $limitnum
1379 $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1380 self::validate_context($systemcontext);
1382 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1383 throw new moodle_exception('You do not have permission to perform this action.');
1386 list($contacts, $noncontacts) = \core_message\api::message_search_users(
1389 $params['limitfrom'],
1390 $params['limitnum']);
1392 return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1396 * Get messagearea message search users returns.
1398 * @return external_single_structure
1401 public static function message_search_users_returns() {
1402 return new external_single_structure(
1404 'contacts' => new external_multiple_structure(
1405 self::get_conversation_member_structure(false, true)
1407 'noncontacts' => new external_multiple_structure(
1408 self::get_conversation_member_structure(false, true)
1415 * Get messagearea search messages parameters.
1417 * @return external_function_parameters
1420 public static function data_for_messagearea_search_messages_parameters() {
1421 return new external_function_parameters(
1423 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1424 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1425 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1426 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1432 * Get messagearea search messages results.
1434 * @param int $userid The id of the user who is performing the search
1435 * @param string $search The string being searched
1436 * @param int $limitfrom
1437 * @param int $limitnum
1439 * @throws moodle_exception
1442 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1443 global $CFG, $PAGE, $USER;
1445 // Check if messaging is enabled.
1446 if (empty($CFG->messaging)) {
1447 throw new moodle_exception('disabled', 'message');
1450 $systemcontext = context_system::instance();
1453 'userid' => $userid,
1454 'search' => $search,
1455 'limitfrom' => $limitfrom,
1456 'limitnum' => $limitnum
1459 $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1460 self::validate_context($systemcontext);
1462 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1463 throw new moodle_exception('You do not have permission to perform this action.');
1466 $messages = \core_message\api::search_messages(
1469 $params['limitfrom'],
1472 $results = new \core_message\output\messagearea\message_search_results($messages);
1474 $renderer = $PAGE->get_renderer('core_message');
1475 return $results->export_for_template($renderer);
1479 * Get messagearea search messages returns.
1481 * @return external_single_structure
1484 public static function data_for_messagearea_search_messages_returns() {
1485 return new external_single_structure(
1487 'contacts' => new external_multiple_structure(
1488 self::get_messagearea_contact_structure()
1495 * Get conversations parameters.
1497 * @return external_function_parameters
1500 public static function get_conversations_parameters() {
1501 return new external_function_parameters(
1503 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1504 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1505 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1506 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1507 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1508 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1509 VALUE_DEFAULT, null),
1516 * Get the list of conversations for the user.
1518 * @param int $userid The id of the user who is performing the search
1519 * @param int $limitfrom
1520 * @param int $limitnum
1521 * @param int|null $type
1522 * @param bool|null $favourites
1524 * @throws \moodle_exception if the messaging feature is disabled on the site.
1527 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null) {
1530 // All the standard BL checks.
1531 if (empty($CFG->messaging)) {
1532 throw new moodle_exception('disabled', 'message');
1536 'userid' => $userid,
1537 'limitfrom' => $limitfrom,
1538 'limitnum' => $limitnum,
1540 'favourites' => $favourites
1542 $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1544 $systemcontext = context_system::instance();
1545 self::validate_context($systemcontext);
1547 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1548 throw new moodle_exception('You do not have permission to perform this action.');
1551 $conversations = \core_message\api::get_conversations(
1553 $params['limitfrom'],
1554 $params['limitnum'],
1556 $params['favourites']
1559 return (object) ['conversations' => $conversations];
1563 * Get conversations returns.
1565 * @return external_single_structure
1568 public static function get_conversations_returns() {
1569 return new external_single_structure(
1571 'conversations' => new external_multiple_structure(
1572 self::get_conversation_structure()
1579 * The messagearea conversations parameters.
1581 * @deprecated since 3.6
1582 * @return external_function_parameters
1585 public static function data_for_messagearea_conversations_parameters() {
1586 return new external_function_parameters(
1588 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1589 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1590 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1596 * Get messagearea conversations.
1598 * NOTE FOR FINAL DEPRECATION:
1599 * When removing this method, please also consider removal of get_conversations_legacy_formatter()
1600 * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
1601 * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
1604 * @deprecated since 3.6
1605 * @param int $userid The id of the user who we are viewing conversations for
1606 * @param int $limitfrom
1607 * @param int $limitnum
1609 * @throws moodle_exception
1612 public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1613 global $CFG, $PAGE, $USER;
1615 // Check if messaging is enabled.
1616 if (empty($CFG->messaging)) {
1617 throw new moodle_exception('disabled', 'message');
1620 $systemcontext = context_system::instance();
1623 'userid' => $userid,
1624 'limitfrom' => $limitfrom,
1625 'limitnum' => $limitnum
1627 $params = self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1628 self::validate_context($systemcontext);
1630 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1631 throw new moodle_exception('You do not have permission to perform this action.');
1634 $conversations = \core_message\api::get_conversations($params['userid'], $params['limitfrom'], $params['limitnum']);
1636 // Format the conversations in the legacy style, as the get_conversations method has since been changed.
1637 $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
1639 $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1641 $renderer = $PAGE->get_renderer('core_message');
1642 return $conversations->export_for_template($renderer);
1646 * The messagearea conversations return structure.
1648 * @deprecated since 3.6
1649 * @return external_single_structure
1652 public static function data_for_messagearea_conversations_returns() {
1653 return new external_single_structure(
1655 'contacts' => new external_multiple_structure(
1656 self::get_messagearea_contact_structure()
1663 * Marking the method as deprecated.
1667 public static function data_for_messagearea_conversations_is_deprecated() {
1672 * The messagearea contacts return parameters.
1674 * @deprecated since 3.6
1675 * @return external_function_parameters
1678 public static function data_for_messagearea_contacts_parameters() {
1679 return self::data_for_messagearea_conversations_parameters();
1683 * Get messagearea contacts parameters.
1685 * @deprecated since 3.6
1686 * @param int $userid The id of the user who we are viewing conversations for
1687 * @param int $limitfrom
1688 * @param int $limitnum
1690 * @throws moodle_exception
1693 public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1694 global $CFG, $PAGE, $USER;
1696 // Check if messaging is enabled.
1697 if (empty($CFG->messaging)) {
1698 throw new moodle_exception('disabled', 'message');
1701 $systemcontext = context_system::instance();
1704 'userid' => $userid,
1705 'limitfrom' => $limitfrom,
1706 'limitnum' => $limitnum
1708 $params = self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1709 self::validate_context($systemcontext);
1711 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1712 throw new moodle_exception('You do not have permission to perform this action.');
1715 $contacts = \core_message\api::get_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1716 $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1718 $renderer = $PAGE->get_renderer('core_message');
1719 return $contacts->export_for_template($renderer);
1723 * The messagearea contacts return structure.
1725 * @deprecated since 3.6
1726 * @return external_single_structure
1729 public static function data_for_messagearea_contacts_returns() {
1730 return self::data_for_messagearea_conversations_returns();
1734 * Marking the method as deprecated.
1738 public static function data_for_messagearea_contacts_is_deprecated() {
1743 * The messagearea messages parameters.
1745 * @deprecated since 3.6
1746 * @return external_function_parameters
1749 public static function data_for_messagearea_messages_parameters() {
1750 return new external_function_parameters(
1752 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1753 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1754 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1755 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1756 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1757 'timefrom' => new external_value(PARAM_INT,
1758 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1764 * Get messagearea messages.
1766 * @deprecated since 3.6
1767 * @param int $currentuserid The current user's id
1768 * @param int $otheruserid The other user's id
1769 * @param int $limitfrom
1770 * @param int $limitnum
1771 * @param boolean $newest
1773 * @throws moodle_exception
1776 public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1777 $newest = false, $timefrom = 0) {
1778 global $CFG, $PAGE, $USER;
1780 // Check if messaging is enabled.
1781 if (empty($CFG->messaging)) {
1782 throw new moodle_exception('disabled', 'message');
1785 $systemcontext = context_system::instance();
1788 'currentuserid' => $currentuserid,
1789 'otheruserid' => $otheruserid,
1790 'limitfrom' => $limitfrom,
1791 'limitnum' => $limitnum,
1792 'newest' => $newest,
1793 'timefrom' => $timefrom,
1795 $params = self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1796 self::validate_context($systemcontext);
1798 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1799 throw new moodle_exception('You do not have permission to perform this action.');
1802 if ($params['newest']) {
1803 $sort = 'timecreated DESC';
1805 $sort = 'timecreated ASC';
1808 // We need to enforce a one second delay on messages to avoid race conditions of current
1809 // messages still being sent.
1811 // There is a chance that we could request messages before the current time's
1812 // second has elapsed and while other messages are being sent in that same second. In which
1813 // case those messages will be lost.
1815 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1816 if (!empty($params['timefrom'])) {
1817 $timeto = time() - 1;
1822 // No requesting messages from the current time, as stated above.
1823 if ($params['timefrom'] == time()) {
1826 $messages = \core_message\api::get_messages($params['currentuserid'], $params['otheruserid'], $params['limitfrom'],
1827 $params['limitnum'], $sort, $params['timefrom'], $timeto);
1830 $messages = new \core_message\output\messagearea\messages($params['currentuserid'], $params['otheruserid'], $messages);
1832 $renderer = $PAGE->get_renderer('core_message');
1833 return $messages->export_for_template($renderer);
1837 * The messagearea messages return structure.
1839 * @deprecated since 3.6
1840 * @return external_single_structure
1843 public static function data_for_messagearea_messages_returns() {
1844 return new external_single_structure(
1846 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1847 the messages on behalf of?'),
1848 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1849 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1850 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1851 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1852 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1853 'messages' => new external_multiple_structure(
1854 self::get_messagearea_message_structure()
1856 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1862 * Marking the method as deprecated.
1866 public static function data_for_messagearea_messages_is_deprecated() {
1871 * The conversation messages parameters.
1873 * @return external_function_parameters
1876 public static function get_conversation_messages_parameters() {
1877 return new external_function_parameters(
1879 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1880 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1881 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1882 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1883 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1884 'timefrom' => new external_value(PARAM_INT,
1885 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1891 * Get conversation messages.
1893 * @param int $currentuserid The current user's id.
1894 * @param int $convid The conversation id.
1895 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1896 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1897 * @param bool $newest True for getting first newest messages, false otherwise.
1898 * @param int $timefrom The time from the conversation messages to get.
1899 * @return stdClass The messages and members who have sent some of these messages.
1900 * @throws moodle_exception
1903 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1904 bool $newest = false, int $timefrom = 0) {
1905 global $CFG, $PAGE, $USER;
1907 // Check if messaging is enabled.
1908 if (empty($CFG->messaging)) {
1909 throw new moodle_exception('disabled', 'message');
1912 $systemcontext = context_system::instance();
1915 'currentuserid' => $currentuserid,
1916 'convid' => $convid,
1917 'limitfrom' => $limitfrom,
1918 'limitnum' => $limitnum,
1919 'newest' => $newest,
1920 'timefrom' => $timefrom,
1922 $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1923 self::validate_context($systemcontext);
1925 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1926 throw new moodle_exception('You do not have permission to perform this action.');
1929 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1931 // We need to enforce a one second delay on messages to avoid race conditions of current
1932 // messages still being sent.
1934 // There is a chance that we could request messages before the current time's
1935 // second has elapsed and while other messages are being sent in that same second. In which
1936 // case those messages will be lost.
1938 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1939 $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1941 // No requesting messages from the current time, as stated above.
1942 if ($params['timefrom'] == time()) {
1945 $messages = \core_message\api::get_conversation_messages(
1946 $params['currentuserid'],
1948 $params['limitfrom'],
1949 $params['limitnum'],
1951 $params['timefrom'],
1959 * The messagearea messages return structure.
1961 * @return external_single_structure
1964 public static function get_conversation_messages_returns() {
1965 return new external_single_structure(
1967 'id' => new external_value(PARAM_INT, 'The conversation id'),
1968 'members' => new external_multiple_structure(
1969 self::get_conversation_member_structure()
1971 'messages' => new external_multiple_structure(
1972 self::get_conversation_message_structure()
1979 * The get most recent message return parameters.
1981 * @deprecated since 3.6
1982 * @return external_function_parameters
1985 public static function data_for_messagearea_get_most_recent_message_parameters() {
1986 return new external_function_parameters(
1988 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1989 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1995 * Get the most recent message in a conversation.
1997 * @deprecated since 3.6
1998 * @param int $currentuserid The current user's id
1999 * @param int $otheruserid The other user's id
2001 * @throws moodle_exception
2004 public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
2005 global $CFG, $PAGE, $USER;
2007 // Check if messaging is enabled.
2008 if (empty($CFG->messaging)) {
2009 throw new moodle_exception('disabled', 'message');
2012 $systemcontext = context_system::instance();
2015 'currentuserid' => $currentuserid,
2016 'otheruserid' => $otheruserid
2018 $params = self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
2019 self::validate_context($systemcontext);
2021 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2022 throw new moodle_exception('You do not have permission to perform this action.');
2025 $message = \core_message\api::get_most_recent_message($params['currentuserid'], $params['otheruserid']);
2026 $message = new \core_message\output\messagearea\message($message);
2028 $renderer = $PAGE->get_renderer('core_message');
2029 return $message->export_for_template($renderer);
2033 * The get most recent message return structure.
2035 * @deprecated since 3.6
2036 * @return external_single_structure
2039 public static function data_for_messagearea_get_most_recent_message_returns() {
2040 return self::get_messagearea_message_structure();
2044 * Marking the method as deprecated.
2048 public static function data_for_messagearea_get_most_recent_message_is_deprecated() {
2053 * The get profile parameters.
2055 * @deprecated since 3.6
2056 * @return external_function_parameters
2059 public static function data_for_messagearea_get_profile_parameters() {
2060 return new external_function_parameters(
2062 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2063 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
2069 * Get the profile information for a contact.
2071 * @deprecated since 3.6
2072 * @param int $currentuserid The current user's id
2073 * @param int $otheruserid The id of the user whose profile we are viewing
2075 * @throws moodle_exception
2078 public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
2079 global $CFG, $PAGE, $USER;
2081 // Check if messaging is enabled.
2082 if (empty($CFG->messaging)) {
2083 throw new moodle_exception('disabled', 'message');
2086 $systemcontext = context_system::instance();
2089 'currentuserid' => $currentuserid,
2090 'otheruserid' => $otheruserid
2092 $params = self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
2093 self::validate_context($systemcontext);
2095 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2096 throw new moodle_exception('You do not have permission to perform this action.');
2099 $profile = \core_message\api::get_profile($params['currentuserid'], $params['otheruserid']);
2100 $profile = new \core_message\output\messagearea\profile($profile);
2102 $renderer = $PAGE->get_renderer('core_message');
2103 return $profile->export_for_template($renderer);
2107 * The get profile return structure.
2109 * @deprecated since 3.6
2110 * @return external_single_structure
2113 public static function data_for_messagearea_get_profile_returns() {
2114 return new external_single_structure(
2116 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
2117 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
2118 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
2119 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
2120 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
2121 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
2122 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
2123 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2124 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2125 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
2126 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
2132 * Marking the method as deprecated.
2136 public static function data_for_messagearea_get_profile_is_deprecated() {
2141 * Get contacts parameters description.
2143 * @return external_function_parameters
2146 public static function get_contacts_parameters() {
2147 return new external_function_parameters(array());
2153 * @return external_description
2156 public static function get_contacts() {
2157 global $CFG, $PAGE, $USER;
2159 // Check if messaging is enabled.
2160 if (empty($CFG->messaging)) {
2161 throw new moodle_exception('disabled', 'message');
2164 require_once($CFG->dirroot . '/user/lib.php');
2166 $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
2167 $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
2168 foreach ($contacts as $contact) {
2171 if (\core_message\helper::is_online($contact->lastaccess)) {
2175 $newcontact = array(
2176 'id' => $contact->id,
2177 'fullname' => fullname($contact),
2178 'unread' => $contact->messagecount
2181 $userpicture = new user_picture($contact);
2182 $userpicture->size = 1; // Size f1.
2183 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2184 $userpicture->size = 0; // Size f2.
2185 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2187 $allcontacts[$mode][$contact->id] = $newcontact;
2190 $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
2191 foreach ($strangers as $contact) {
2192 $newcontact = array(
2193 'id' => $contact->id,
2194 'fullname' => fullname($contact),
2195 'unread' => $contact->messagecount
2198 $userpicture = new user_picture($contact);
2199 $userpicture->size = 1; // Size f1.
2200 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2201 $userpicture->size = 0; // Size f2.
2202 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2204 $allcontacts['strangers'][$contact->id] = $newcontact;
2207 // Add noreply user and support user to the list, if they don't exist.
2208 $supportuser = core_user::get_support_user();
2209 if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
2210 $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
2211 if ($supportuser->messagecount > 0) {
2212 $supportuser->fullname = fullname($supportuser);
2213 $supportuser->unread = $supportuser->messagecount;
2214 $allcontacts['strangers'][$supportuser->id] = $supportuser;
2218 $noreplyuser = core_user::get_noreply_user();
2219 if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
2220 $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
2221 if ($noreplyuser->messagecount > 0) {
2222 $noreplyuser->fullname = fullname($noreplyuser);
2223 $noreplyuser->unread = $noreplyuser->messagecount;
2224 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
2228 return $allcontacts;
2232 * Get contacts return description.
2234 * @return external_description
2237 public static function get_contacts_returns() {
2238 return new external_single_structure(
2240 'online' => new external_multiple_structure(
2241 new external_single_structure(
2243 'id' => new external_value(PARAM_INT, 'User ID'),
2244 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2245 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2246 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2247 'unread' => new external_value(PARAM_INT, 'Unread message count')
2250 'List of online contacts'
2252 'offline' => new external_multiple_structure(
2253 new external_single_structure(
2255 'id' => new external_value(PARAM_INT, 'User ID'),
2256 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2257 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2258 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2259 'unread' => new external_value(PARAM_INT, 'Unread message count')
2262 'List of offline contacts'
2264 'strangers' => new external_multiple_structure(
2265 new external_single_structure(
2267 'id' => new external_value(PARAM_INT, 'User ID'),
2268 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2269 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2270 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2271 'unread' => new external_value(PARAM_INT, 'Unread message count')
2274 'List of users that are not in the user\'s contact list but have sent a message'
2281 * Search contacts parameters description.
2283 * @return external_function_parameters
2286 public static function search_contacts_parameters() {
2287 return new external_function_parameters(
2289 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2290 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2291 VALUE_DEFAULT, false)
2299 * @param string $searchtext query string.
2300 * @param bool $onlymycourses limit the search to the user's courses only.
2301 * @return external_description
2304 public static function search_contacts($searchtext, $onlymycourses = false) {
2305 global $CFG, $USER, $PAGE;
2306 require_once($CFG->dirroot . '/user/lib.php');
2308 // Check if messaging is enabled.
2309 if (empty($CFG->messaging)) {
2310 throw new moodle_exception('disabled', 'message');
2313 require_once($CFG->libdir . '/enrollib.php');
2315 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2316 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2318 // Extra validation, we do not allow empty queries.
2319 if ($params['searchtext'] === '') {
2320 throw new moodle_exception('querystringcannotbeempty');
2323 $courseids = array();
2324 if ($params['onlymycourses']) {
2325 $mycourses = enrol_get_my_courses(array('id'));
2326 foreach ($mycourses as $mycourse) {
2327 $courseids[] = $mycourse->id;
2330 $courseids[] = SITEID;
2333 // Retrieving the users matching the query.
2334 $users = message_search_users($courseids, $params['searchtext']);
2336 foreach ($users as $user) {
2337 $results[$user->id] = $user;
2340 // Reorganising information.
2341 foreach ($results as &$user) {
2344 'fullname' => fullname($user)
2347 // Avoid undefined property notice as phone not specified.
2348 $user->phone1 = null;
2349 $user->phone2 = null;
2351 $userpicture = new user_picture($user);
2352 $userpicture->size = 1; // Size f1.
2353 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2354 $userpicture->size = 0; // Size f2.
2355 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2364 * Search contacts return description.
2366 * @return external_description
2369 public static function search_contacts_returns() {
2370 return new external_multiple_structure(
2371 new external_single_structure(
2373 'id' => new external_value(PARAM_INT, 'User ID'),
2374 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2375 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2376 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
2384 * Get messages parameters description.
2386 * @return external_function_parameters
2389 public static function get_messages_parameters() {
2390 return new external_function_parameters(
2392 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2393 'useridfrom' => new external_value(
2394 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2396 'type' => new external_value(
2397 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2398 VALUE_DEFAULT, 'both'),
2399 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2400 'newestfirst' => new external_value(
2401 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2402 VALUE_DEFAULT, true),
2403 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2404 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2410 * Get messages function implementation.
2413 * @throws invalid_parameter_exception
2414 * @throws moodle_exception
2415 * @param int $useridto the user id who received the message
2416 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2417 * @param string $type type of message to return, expected values: notifications, conversations and both
2418 * @param bool $read true for retreiving read messages, false for unread
2419 * @param bool $newestfirst true for ordering by newest first, false for oldest first
2420 * @param int $limitfrom limit from
2421 * @param int $limitnum limit num
2422 * @return external_description
2424 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2425 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2428 $warnings = array();
2431 'useridto' => $useridto,
2432 'useridfrom' => $useridfrom,
2435 'newestfirst' => $newestfirst,
2436 'limitfrom' => $limitfrom,
2437 'limitnum' => $limitnum
2440 $params = self::validate_parameters(self::get_messages_parameters(), $params);
2442 $context = context_system::instance();
2443 self::validate_context($context);
2445 $useridto = $params['useridto'];
2446 $useridfrom = $params['useridfrom'];
2447 $type = $params['type'];
2448 $read = $params['read'];
2449 $newestfirst = $params['newestfirst'];
2450 $limitfrom = $params['limitfrom'];
2451 $limitnum = $params['limitnum'];
2453 $allowedvalues = array('notifications', 'conversations', 'both');
2454 if (!in_array($type, $allowedvalues)) {
2455 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2456 'allowed values are: ' . implode(',', $allowedvalues));
2459 // Check if private messaging between users is allowed.
2460 if (empty($CFG->messaging)) {
2461 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2462 if ($type == "conversations") {
2463 throw new moodle_exception('disabled', 'message');
2465 if ($type == "both") {
2467 $warning['item'] = 'message';
2468 $warning['itemid'] = $USER->id;
2469 $warning['warningcode'] = '1';
2470 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2471 Only notifications will be returned';
2472 $warnings[] = $warning;
2476 if (!empty($useridto)) {
2477 if (core_user::is_real_user($useridto)) {
2478 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2480 throw new moodle_exception('invaliduser');
2484 if (!empty($useridfrom)) {
2485 // We use get_user here because the from user can be the noreply or support user.
2486 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2489 // Check if the current user is the sender/receiver or just a privileged user.
2490 if ($useridto != $USER->id and $useridfrom != $USER->id and
2491 !has_capability('moodle/site:readallmessages', $context)) {
2492 throw new moodle_exception('accessdenied', 'admin');
2495 // Which type of messages to retrieve.
2496 $notifications = -1;
2497 if ($type != 'both') {
2498 $notifications = ($type == 'notifications') ? 1 : 0;
2501 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2502 $sort = "mr.timecreated $orderdirection";
2504 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2505 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2507 // In some cases, we don't need to get the to/from user objects from the sql query.
2508 $userfromfullname = '';
2509 $usertofullname = '';
2511 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2512 if (!empty($useridto)) {
2513 $usertofullname = fullname($userto, $canviewfullname);
2514 // The user from may or may not be filled.
2515 if (!empty($useridfrom)) {
2516 $userfromfullname = fullname($userfrom, $canviewfullname);
2519 // If the useridto field is empty, the useridfrom must be filled.
2520 $userfromfullname = fullname($userfrom, $canviewfullname);
2522 foreach ($messages as $mid => $message) {
2524 // Do not return deleted messages.
2525 if (!$message->notification) {
2526 if (($useridto == $USER->id and $message->timeusertodeleted) or
2527 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2528 unset($messages[$mid]);
2533 // We need to get the user from the query.
2534 if (empty($userfromfullname)) {
2535 // Check for non-reply and support users.
2536 if (core_user::is_real_user($message->useridfrom)) {
2537 $user = new stdClass();
2538 $user = username_load_fields_from_object($user, $message, 'userfrom');
2539 $message->userfromfullname = fullname($user, $canviewfullname);
2541 $user = core_user::get_user($message->useridfrom);
2542 $message->userfromfullname = fullname($user, $canviewfullname);
2545 $message->userfromfullname = $userfromfullname;
2548 // We need to get the user from the query.
2549 if (empty($usertofullname)) {
2550 $user = new stdClass();
2551 $user = username_load_fields_from_object($user, $message, 'userto');
2552 $message->usertofullname = fullname($user, $canviewfullname);
2554 $message->usertofullname = $usertofullname;
2557 $message->text = message_format_message_text($message);
2558 $messages[$mid] = (array) $message;
2563 'messages' => $messages,
2564 'warnings' => $warnings
2571 * Get messages return description.
2573 * @return external_single_structure
2576 public static function get_messages_returns() {
2577 return new external_single_structure(
2579 'messages' => new external_multiple_structure(
2580 new external_single_structure(
2582 'id' => new external_value(PARAM_INT, 'Message id'),
2583 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2584 'useridto' => new external_value(PARAM_INT, 'User to id'),
2585 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2586 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2587 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2588 'fullmessageformat' => new external_format_value('fullmessage'),
2589 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2590 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2591 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2592 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2593 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2594 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2595 'timeread' => new external_value(PARAM_INT, 'Time read'),
2596 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2597 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2601 'warnings' => new external_warnings()
2607 * Mark all notifications as read parameters description.
2609 * @return external_function_parameters
2612 public static function mark_all_notifications_as_read_parameters() {
2613 return new external_function_parameters(
2615 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2616 'useridfrom' => new external_value(
2617 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2624 * Mark all notifications as read function.
2627 * @throws invalid_parameter_exception
2628 * @throws moodle_exception
2629 * @param int $useridto the user id who received the message
2630 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2631 * @return external_description
2633 public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2636 $params = self::validate_parameters(
2637 self::mark_all_notifications_as_read_parameters(),
2639 'useridto' => $useridto,
2640 'useridfrom' => $useridfrom,
2644 $context = context_system::instance();
2645 self::validate_context($context);
2647 $useridto = $params['useridto'];
2648 $useridfrom = $params['useridfrom'];
2650 if (!empty($useridto)) {
2651 if (core_user::is_real_user($useridto)) {
2652 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2654 throw new moodle_exception('invaliduser');
2658 if (!empty($useridfrom)) {
2659 // We use get_user here because the from user can be the noreply or support user.
2660 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2663 // Check if the current user is the sender/receiver or just a privileged user.
2664 if ($useridto != $USER->id and $useridfrom != $USER->id and
2665 // The deleteanymessage cap seems more reasonable here than readallmessages.
2666 !has_capability('moodle/site:deleteanymessage', $context)) {
2667 throw new moodle_exception('accessdenied', 'admin');
2670 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2676 * Mark all notifications as read return description.
2678 * @return external_single_structure
2681 public static function mark_all_notifications_as_read_returns() {
2682 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2686 * Get unread conversations count parameters description.
2688 * @return external_function_parameters
2691 public static function get_unread_conversations_count_parameters() {
2692 return new external_function_parameters(
2694 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2700 * Get unread messages count function.
2703 * @throws invalid_parameter_exception
2704 * @throws moodle_exception
2705 * @param int $useridto the user id who received the message
2706 * @return external_description
2708 public static function get_unread_conversations_count($useridto) {
2711 // Check if messaging is enabled.
2712 if (empty($CFG->messaging)) {
2713 throw new moodle_exception('disabled', 'message');
2716 $params = self::validate_parameters(
2717 self::get_unread_conversations_count_parameters(),
2718 array('useridto' => $useridto)
2721 $context = context_system::instance();
2722 self::validate_context($context);
2724 $useridto = $params['useridto'];
2726 if (!empty($useridto)) {
2727 if (core_user::is_real_user($useridto)) {
2728 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2730 throw new moodle_exception('invaliduser');
2733 $useridto = $USER->id;
2736 // Check if the current user is the receiver or just a privileged user.
2737 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2738 throw new moodle_exception('accessdenied', 'admin');
2741 return \core_message\api::count_unread_conversations($userto);
2745 * Get unread conversations count return description.
2747 * @return external_single_structure
2750 public static function get_unread_conversations_count_returns() {
2751 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2755 * Get blocked users parameters description.
2757 * @return external_function_parameters
2760 public static function get_blocked_users_parameters() {
2761 return new external_function_parameters(
2763 'userid' => new external_value(PARAM_INT,
2764 'the user whose blocked users we want to retrieve',
2771 * Retrieve a list of users blocked
2773 * @param int $userid the user whose blocked users we want to retrieve
2774 * @return external_description
2777 public static function get_blocked_users($userid) {
2778 global $CFG, $USER, $PAGE;
2780 // Warnings array, it can be empty at the end but is mandatory.
2781 $warnings = array();
2787 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2788 $userid = $params['userid'];
2790 // Validate context.
2791 $context = context_system::instance();
2792 self::validate_context($context);
2794 // Check if private messaging between users is allowed.
2795 if (empty($CFG->messaging)) {
2796 throw new moodle_exception('disabled', 'message');
2799 $user = core_user::get_user($userid, '*', MUST_EXIST);
2800 core_user::require_active_user($user);
2802 // Check if we have permissions for retrieve the information.
2803 $capability = 'moodle/site:manageallmessaging';
2804 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2805 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2808 // Now, we can get safely all the blocked users.
2809 $users = \core_message\api::get_blocked_users($user->id);
2811 $blockedusers = array();
2812 foreach ($users as $user) {
2815 'fullname' => fullname($user),
2818 $userpicture = new user_picture($user);
2819 $userpicture->size = 1; // Size f1.
2820 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2822 $blockedusers[] = $newuser;
2826 'users' => $blockedusers,
2827 'warnings' => $warnings
2833 * Get blocked users return description.
2835 * @return external_single_structure
2838 public static function get_blocked_users_returns() {
2839 return new external_single_structure(
2841 'users' => new external_multiple_structure(
2842 new external_single_structure(
2844 'id' => new external_value(PARAM_INT, 'User ID'),
2845 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2846 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2849 'List of blocked users'
2851 'warnings' => new external_warnings()
2857 * Returns description of method parameters
2859 * @return external_function_parameters
2862 public static function mark_message_read_parameters() {
2863 return new external_function_parameters(
2865 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2866 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2873 * Mark a single message as read, trigger message_viewed event
2875 * @param int $messageid id of the message (in the message table)
2876 * @param int $timeread timestamp for when the message should be marked read
2877 * @return external_description
2878 * @throws invalid_parameter_exception
2879 * @throws moodle_exception
2882 public static function mark_message_read($messageid, $timeread) {
2883 global $CFG, $DB, $USER;
2885 // Check if private messaging between users is allowed.
2886 if (empty($CFG->messaging)) {
2887 throw new moodle_exception('disabled', 'message');
2890 // Warnings array, it can be empty at the end but is mandatory.
2891 $warnings = array();
2895 'messageid' => $messageid,
2896 'timeread' => $timeread
2898 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2900 if (empty($params['timeread'])) {
2903 $timeread = $params['timeread'];
2906 // Validate context.
2907 $context = context_system::instance();
2908 self::validate_context($context);
2910 $sql = "SELECT m.*, mcm.userid as useridto
2912 INNER JOIN {message_conversations} mc
2913 ON m.conversationid = mc.id
2914 INNER JOIN {message_conversation_members} mcm
2915 ON mcm.conversationid = mc.id
2916 LEFT JOIN {message_user_actions} mua
2917 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2918 WHERE mua.id is NULL
2919 AND mcm.userid != m.useridfrom
2921 $messageparams = [];
2922 $messageparams[] = $USER->id;
2923 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2924 $messageparams[] = $params['messageid'];
2925 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2927 if ($message->useridto != $USER->id) {
2928 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2931 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2934 'messageid' => $message->id,
2935 'warnings' => $warnings
2941 * Returns description of method result value
2943 * @return external_description
2946 public static function mark_message_read_returns() {
2947 return new external_single_structure(
2949 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2950 'warnings' => new external_warnings()
2956 * Returns description of method parameters
2958 * @return external_function_parameters
2960 public static function mark_notification_read_parameters() {
2961 return new external_function_parameters(
2963 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2964 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2971 * Mark a single notification as read.
2973 * This will trigger a 'notification_viewed' event.
2975 * @param int $notificationid id of the notification
2976 * @param int $timeread timestamp for when the notification should be marked read
2977 * @return external_description
2978 * @throws invalid_parameter_exception
2979 * @throws moodle_exception
2981 public static function mark_notification_read($notificationid, $timeread) {
2982 global $CFG, $DB, $USER;
2984 // Check if private messaging between users is allowed.
2985 if (empty($CFG->messaging)) {
2986 throw new moodle_exception('disabled', 'message');
2989 // Warnings array, it can be empty at the end but is mandatory.
2990 $warnings = array();
2994 'notificationid' => $notificationid,
2995 'timeread' => $timeread
2997 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2999 if (empty($params['timeread'])) {
3002 $timeread = $params['timeread'];
3005 // Validate context.
3006 $context = context_system::instance();
3007 self::validate_context($context);
3009 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
3011 if ($notification->useridto != $USER->id) {
3012 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
3013 'notification as read');
3016 \core_message\api::mark_notification_as_read($notification, $timeread);
3019 'notificationid' => $notification->id,
3020 'warnings' => $warnings
3027 * Returns description of method result value
3029 * @return external_description
3031 public static function mark_notification_read_returns() {
3032 return new external_single_structure(
3034 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
3035 'warnings' => new external_warnings()
3041 * Mark all messages as read parameters description.
3043 * @deprecated since 3.6
3044 * @return external_function_parameters
3047 public static function mark_all_messages_as_read_parameters() {
3048 return new external_function_parameters(
3050 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3051 'useridfrom' => new external_value(
3052 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
3059 * Mark all messages as read function.
3061 * @deprecated since 3.6
3062 * @throws invalid_parameter_exception
3063 * @throws moodle_exception
3064 * @param int $useridto the user id who received the message
3065 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
3066 * @return external_description
3069 public static function mark_all_messages_as_read($useridto, $useridfrom) {
3072 // Check if messaging is enabled.
3073 if (empty($CFG->messaging)) {
3074 throw new moodle_exception('disabled', 'message');
3077 $params = self::validate_parameters(
3078 self::mark_all_messages_as_read_parameters(),
3080 'useridto' => $useridto,
3081 'useridfrom' => $useridfrom,
3085 $context = context_system::instance();
3086 self::validate_context($context);
3088 $useridto = $params['useridto'];
3089 $useridfrom = $params['useridfrom'];
3091 if (!empty($useridto)) {
3092 if (core_user::is_real_user($useridto)) {
3093 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3095 throw new moodle_exception('invaliduser');
3099 if (!empty($useridfrom)) {
3100 // We use get_user here because the from user can be the noreply or support user.
3101 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3104 // Check if the current user is the sender/receiver or just a privileged user.
3105 if ($useridto != $USER->id and $useridfrom != $USER->id and
3106 // The deleteanymessage cap seems more reasonable here than readallmessages.
3107 !has_capability('moodle/site:deleteanymessage', $context)) {
3108 throw new moodle_exception('accessdenied', 'admin');
3112 if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
3113 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
3116 \core_message\api::mark_all_messages_as_read($useridto);
3123 * Mark all messages as read return description.
3125 * @deprecated since 3.6
3126 * @return external_single_structure
3129 public static function mark_all_messages_as_read_returns() {
3130 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
3134 * Marking the method as deprecated.
3138 public static function mark_all_messages_as_read_is_deprecated() {
3143 * Mark all conversation messages as read parameters description.
3145 * @return external_function_parameters
3148 public static function mark_all_conversation_messages_as_read_parameters() {
3149 return new external_function_parameters(
3151 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
3153 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
3159 * Mark all conversation messages as read function.
3161 * @param int $userid The user id of who we want to delete the conversation for
3162 * @param int $conversationid The id of the conversations
3165 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
3168 // Check if messaging is enabled.
3169 if (empty($CFG->messaging)) {
3170 throw new moodle_exception('disabled', 'message');
3174 'userid' => $userid,
3175 'conversationid' => $conversationid,
3177 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
3179 $context = context_system::instance();
3180 self::validate_context($context);
3182 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3183 core_user::require_active_user($user);
3185 if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
3186 \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
3188 throw new moodle_exception('accessdenied', 'admin');
3193 * Mark all conversation messages as read return description.
3195 * @return external_warnings
3198 public static function mark_all_conversation_messages_as_read_returns() {
3199 return new external_warnings();
3203 * Returns description of method parameters.
3205 * @deprecated since 3.6
3206 * @return external_function_parameters
3209 public static function delete_conversation_parameters() {
3210 return new external_function_parameters(
3212 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3213 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
3219 * Deletes a conversation.
3221 * @deprecated since 3.6
3222 * @param int $userid The user id of who we want to delete the conversation for
3223 * @param int $otheruserid The user id of the other user in the conversation
3225 * @throws moodle_exception
3228 public static function delete_conversation($userid, $otheruserid) {
3231 // Check if private messaging between users is allowed.
3232 if (empty($CFG->messaging)) {
3233 throw new moodle_exception('disabled', 'message');
3236 // Warnings array, it can be empty at the end but is mandatory.
3237 $warnings = array();
3241 'userid' => $userid,
3242 'otheruserid' => $otheruserid,
3244 $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
3246 // Validate context.
3247 $context = context_system::instance();
3248 self::validate_context($context);
3250 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3251 core_user::require_active_user($user);
3253 if (!$conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']])) {
3257 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3258 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3261 throw new moodle_exception('You do not have permission to delete messages');
3265 'status' => $status,
3266 'warnings' => $warnings
3273 * Returns description of method result value.
3275 * @deprecated since 3.6
3276 * @return external_description
3279 public static function delete_conversation_returns() {
3280 return new external_single_structure(
3282 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
3283 'warnings' => new external_warnings()
3289 * Marking the method as deprecated.
3293 public static function delete_conversation_is_deprecated() {
3298 * Returns description of method parameters.
3300 * @return external_function_parameters
3303 public static function delete_conversations_by_id_parameters() {
3304 return new external_function_parameters(
3306 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3307 'conversationids' => new external_multiple_structure(
3308 new external_value(PARAM_INT, 'The id of the conversation'),
3309 'List of conversation IDs'
3316 * Deletes a conversation.
3318 * @param int $userid The user id of who we want to delete the conversation for
3319 * @param int[] $conversationids The ids of the conversations
3321 * @throws moodle_exception
3324 public static function delete_conversations_by_id($userid, array $conversationids) {
3327 // Check if private messaging between users is allowed.
3328 if (empty($CFG->messaging)) {
3329 throw new moodle_exception('disabled', 'message');
3334 'userid' => $userid,
3335 'conversationids' => $conversationids,
3337 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
3339 // Validate context.
3340 $context = context_system::instance();
3341 self::validate_context($context);
3343 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3344 core_user::require_active_user($user);
3346 foreach ($params['conversationids'] as $conversationid) {
3347 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3348 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3350 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
3358 * Returns description of method result value.
3360 * @return external_description
3363 public static function delete_conversations_by_id_returns() {
3364 return new external_warnings();
3368 * Returns description of method parameters
3370 * @return external_function_parameters
3373 public static function delete_message_parameters() {
3374 return new external_function_parameters(
3376 'messageid' => new external_value(PARAM_INT, 'The message id'),
3377 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
3378 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
3386 * @param int $messageid the message id
3387 * @param int $userid the user id of who we want to delete the message for
3388 * @param bool $read if is a message read (default to true)
3389 * @return external_description
3390 * @throws moodle_exception
3393 public static function delete_message($messageid, $userid, $read = true) {
3396 // Check if private messaging between users is allowed.
3397 if (empty($CFG->messaging)) {
3398 throw new moodle_exception('disabled', 'message');
3401 // Warnings array, it can be empty at the end but is mandatory.
3402 $warnings = array();
3406 'messageid' => $messageid,
3407 'userid' => $userid,
3410 $params = self::validate_parameters(self::delete_message_parameters(), $params);
3412 // Validate context.
3413 $context = context_system::instance();
3414 self::validate_context($context);
3416 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3417 core_user::require_active_user($user);
3419 if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
3420 $status = \core_message\api::delete_message($user->id, $params['messageid']);
3422 throw new moodle_exception('You do not have permission to delete this message');
3426 'status' => $status,
3427 'warnings' => $warnings
3433 * Returns description of method result value