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 {
44 * Returns description of method parameters
46 * @return external_function_parameters
49 public static function send_instant_messages_parameters() {
50 return new external_function_parameters(
52 'messages' => new external_multiple_structure(
53 new external_single_structure(
55 'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
56 'text' => new external_value(PARAM_RAW, 'the text of the message'),
57 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
58 '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),
67 * Send private messages from the current USER to other users
69 * @param array $messages An array of message to send.
73 public static function send_instant_messages($messages = array()) {
74 global $CFG, $USER, $DB;
76 // Check if messaging is enabled.
77 if (empty($CFG->messaging)) {
78 throw new moodle_exception('disabled', 'message');
81 // Ensure the current user is allowed to run this function
82 $context = context_system::instance();
83 self::validate_context($context);
84 require_capability('moodle/site:sendmessage', $context);
86 $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
88 //retrieve all tousers of the messages
90 foreach($params['messages'] as $message) {
91 $receivers[] = $message['touserid'];
93 list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
94 $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
96 $resultmessages = array();
97 foreach ($params['messages'] as $message) {
98 $resultmsg = array(); //the infos about the success of the operation
100 // We are going to do some checking.
101 // Code should match /messages/index.php checks.
104 // Check the user exists.
105 if (empty($tousers[$message['touserid']])) {
107 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
110 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
111 // Check if the recipient can be messaged by the sender.
112 if ($success && !\core_message\api::can_post_message($tousers[$message['touserid']], $USER)) {
114 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
117 // Now we can send the message (at least try).
119 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
120 $success = message_post_message($USER, $tousers[$message['touserid']],
121 $message['text'], external_validate_format($message['textformat']));
124 // Build the resultmsg.
125 if (isset($message['clientmsgid'])) {
126 $resultmsg['clientmsgid'] = $message['clientmsgid'];
129 $resultmsg['msgid'] = $success;
131 // WARNINGS: for backward compatibility we return this errormessage.
132 // We should have thrown exceptions as these errors prevent results to be returned.
133 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
134 $resultmsg['msgid'] = -1;
135 $resultmsg['errormessage'] = $errormessage;
138 $resultmessages[] = $resultmsg;
141 return $resultmessages;
145 * Returns description of method result value
147 * @return external_description
150 public static function send_instant_messages_returns() {
151 return new external_multiple_structure(
152 new external_single_structure(
154 'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds: id of the created message if it succeeded, -1 when failed'),
155 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
156 'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
163 * Create contacts parameters description.
165 * @deprecated since Moodle 3.6
166 * @return external_function_parameters
169 public static function create_contacts_parameters() {
170 return new external_function_parameters(
172 'userids' => new external_multiple_structure(
173 new external_value(PARAM_INT, 'User ID'),
176 'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
177 current user', VALUE_DEFAULT, 0)
185 * @deprecated since Moodle 3.6
186 * @param array $userids array of user IDs.
187 * @param int $userid The id of the user we are creating the contacts for
188 * @return external_description
191 public static function create_contacts($userids, $userid = 0) {
194 // Check if messaging is enabled.
195 if (empty($CFG->messaging)) {
196 throw new moodle_exception('disabled', 'message');
199 if (empty($userid)) {
204 $context = context_system::instance();
205 self::validate_context($context);
207 $params = array('userids' => $userids, 'userid' => $userid);
208 $params = self::validate_parameters(self::create_contacts_parameters(), $params);
210 $capability = 'moodle/site:manageallmessaging';
211 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
212 throw new required_capability_exception($context, $capability, 'nopermissions', '');
216 foreach ($params['userids'] as $id) {
217 if (!message_add_contact($id, 0, $params['userid'])) {
221 'warningcode' => 'contactnotcreated',
222 'message' => 'The contact could not be created'
230 * Create contacts return description.
232 * @deprecated since Moodle 3.6
233 * @return external_description
236 public static function create_contacts_returns() {
237 return new external_warnings();
241 * Marking the method as deprecated.
245 public static function create_contacts_is_deprecated() {
250 * Delete contacts parameters description.
252 * @return external_function_parameters
255 public static function delete_contacts_parameters() {
256 return new external_function_parameters(
258 'userids' => new external_multiple_structure(
259 new external_value(PARAM_INT, 'User ID'),
262 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
263 current user', VALUE_DEFAULT, 0)
271 * @param array $userids array of user IDs.
272 * @param int $userid The id of the user we are deleting the contacts for
276 public static function delete_contacts($userids, $userid = 0) {
279 // Check if messaging is enabled.
280 if (empty($CFG->messaging)) {
281 throw new moodle_exception('disabled', 'message');
284 if (empty($userid)) {
289 $context = context_system::instance();
290 self::validate_context($context);
292 $params = array('userids' => $userids, 'userid' => $userid);
293 $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
295 $capability = 'moodle/site:manageallmessaging';
296 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
297 throw new required_capability_exception($context, $capability, 'nopermissions', '');
300 foreach ($params['userids'] as $id) {
301 \core_message\api::remove_contact($params['userid'], $id);
308 * Delete contacts return description.
310 * @return external_description
313 public static function delete_contacts_returns() {
318 * Block user parameters description.
320 * @return external_function_parameters
322 public static function block_user_parameters() {
323 return new external_function_parameters(
325 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
326 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
334 * @param int $userid The id of the user who is blocking
335 * @param int $blockeduserid The id of the user being blocked
336 * @return external_description
338 public static function block_user(int $userid, int $blockeduserid) {
341 // Check if messaging is enabled.
342 if (empty($CFG->messaging)) {
343 throw new moodle_exception('disabled', 'message');
347 $context = context_system::instance();
348 self::validate_context($context);
350 $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
351 $params = self::validate_parameters(self::block_user_parameters(), $params);
353 $capability = 'moodle/site:manageallmessaging';
354 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
355 throw new required_capability_exception($context, $capability, 'nopermissions', '');
358 if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
359 \core_message\api::block_user($params['userid'], $params['blockeduserid']);
366 * Block user return description.
368 * @return external_description
370 public static function block_user_returns() {
371 return new external_warnings();
375 * Unblock user parameters description.
377 * @return external_function_parameters
379 public static function unblock_user_parameters() {
380 return new external_function_parameters(
382 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
383 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
391 * @param int $userid The id of the user who is unblocking
392 * @param int $unblockeduserid The id of the user being unblocked
394 public static function unblock_user(int $userid, int $unblockeduserid) {
397 // Check if messaging is enabled.
398 if (empty($CFG->messaging)) {
399 throw new moodle_exception('disabled', 'message');
403 $context = context_system::instance();
404 self::validate_context($context);
406 $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
407 $params = self::validate_parameters(self::unblock_user_parameters(), $params);
409 $capability = 'moodle/site:manageallmessaging';
410 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
411 throw new required_capability_exception($context, $capability, 'nopermissions', '');
414 \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
420 * Unblock user return description.
422 * @return external_description
424 public static function unblock_user_returns() {
425 return new external_warnings();
429 * Block contacts parameters description.
431 * @deprecated since Moodle 3.6
432 * @return external_function_parameters
435 public static function block_contacts_parameters() {
436 return new external_function_parameters(
438 'userids' => new external_multiple_structure(
439 new external_value(PARAM_INT, 'User ID'),
442 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
443 current user', VALUE_DEFAULT, 0)
451 * @deprecated since Moodle 3.6
452 * @param array $userids array of user IDs.
453 * @param int $userid The id of the user we are blocking the contacts for
454 * @return external_description
457 public static function block_contacts($userids, $userid = 0) {
460 // Check if messaging is enabled.
461 if (empty($CFG->messaging)) {
462 throw new moodle_exception('disabled', 'message');
465 if (empty($userid)) {
470 $context = context_system::instance();
471 self::validate_context($context);
473 $params = array('userids' => $userids, 'userid' => $userid);
474 $params = self::validate_parameters(self::block_contacts_parameters(), $params);
476 $capability = 'moodle/site:manageallmessaging';
477 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
478 throw new required_capability_exception($context, $capability, 'nopermissions', '');
482 foreach ($params['userids'] as $id) {
483 if (!message_block_contact($id, $params['userid'])) {
487 'warningcode' => 'contactnotblocked',
488 'message' => 'The contact could not be blocked'
496 * Block contacts return description.
498 * @deprecated since Moodle 3.6
499 * @return external_description
502 public static function block_contacts_returns() {
503 return new external_warnings();
507 * Marking the method as deprecated.
511 public static function block_contacts_is_deprecated() {
516 * Unblock contacts parameters description.
518 * @deprecated since Moodle 3.6
519 * @return external_function_parameters
522 public static function unblock_contacts_parameters() {
523 return new external_function_parameters(
525 'userids' => new external_multiple_structure(
526 new external_value(PARAM_INT, 'User ID'),
529 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
530 current user', VALUE_DEFAULT, 0)
538 * @param array $userids array of user IDs.
539 * @param int $userid The id of the user we are unblocking the contacts for
543 public static function unblock_contacts($userids, $userid = 0) {
546 // Check if messaging is enabled.
547 if (empty($CFG->messaging)) {
548 throw new moodle_exception('disabled', 'message');
551 if (empty($userid)) {
556 $context = context_system::instance();
557 self::validate_context($context);
559 $params = array('userids' => $userids, 'userid' => $userid);
560 $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
562 $capability = 'moodle/site:manageallmessaging';
563 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
564 throw new required_capability_exception($context, $capability, 'nopermissions', '');
567 foreach ($params['userids'] as $id) {
568 message_unblock_contact($id, $params['userid']);
575 * Unblock contacts return description.
577 * @deprecated since Moodle 3.6
578 * @return external_description
581 public static function unblock_contacts_returns() {
586 * Marking the method as deprecated.
590 public static function unblock_contacts_is_deprecated() {
595 * Returns contact requests parameters description.
597 * @return external_function_parameters
599 public static function get_contact_requests_parameters() {
600 return new external_function_parameters(
602 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for')
608 * Handles returning the contact requests for a user.
610 * This also includes the user data necessary to display information
613 * It will not include blocked users.
615 * @param int $userid The id of the user we want to get the contact requests for
617 public static function get_contact_requests(int $userid) {
620 // Check if messaging is enabled.
621 if (empty($CFG->messaging)) {
622 throw new moodle_exception('disabled', 'message');
626 $context = context_system::instance();
627 self::validate_context($context);
629 $params = ['userid' => $userid];
630 $params = self::validate_parameters(self::get_contact_requests_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 return \core_message\api::get_contact_requests($params['userid']);
641 * Returns the contact requests return description.
643 * @return external_description
645 public static function get_contact_requests_returns() {
646 return new external_multiple_structure(
647 new external_single_structure(
649 'id' => new external_value(core_user::get_property_type('id'), 'ID of the user'),
650 'contactrequestid' => new external_value(PARAM_INT, 'The ID of the contact request'),
651 'picture' => new external_value(core_user::get_property_type('picture'), 'The picture'),
652 'firstname' => new external_value(core_user::get_property_type('firstname'),
653 'The first name(s) of the user'),
654 'lastname' => new external_value(core_user::get_property_type('lastname'),
655 'The family name of the user'),
656 'firstnamephonetic' => new external_value(core_user::get_property_type('firstnamephonetic'),
657 'The phonetic first name of the user'),
658 'lastnamephonetic' => new external_value(core_user::get_property_type('lastnamephonetic'),
659 'The phonetic last name of the user'),
660 'middlename' => new external_value(core_user::get_property_type('middlename'),
661 'The middle name of the user'),
662 'alternatename' => new external_value(core_user::get_property_type('alternatename'),
663 'The alternate name of the user'),
664 'email' => new external_value(core_user::get_property_type('email'), 'An email address')
671 * Returns get conversation members parameters description.
673 * @return external_function_parameters
675 public static function get_conversation_members_parameters() {
676 return new external_function_parameters(
678 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
679 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
680 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
681 VALUE_DEFAULT, false),
682 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
683 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
689 * Returns a list of conversation members.
691 * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
692 * @param int $conversationid The id of the conversation
693 * @param bool $includecontactrequests Do we want to include contact requests with this data?
694 * @param int $limitfrom
695 * @param int $limitnum
698 public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
699 int $limitfrom = 0, int $limitnum = 0) {
702 // Check if messaging is enabled.
703 if (empty($CFG->messaging)) {
704 throw new moodle_exception('disabled', 'message');
708 $context = context_system::instance();
709 self::validate_context($context);
713 'conversationid' => $conversationid,
714 'includecontactrequests' => $includecontactrequests,
715 'limitfrom' => $limitfrom,
716 'limitnum' => $limitnum
718 $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
720 $capability = 'moodle/site:manageallmessaging';
721 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
722 throw new required_capability_exception($context, $capability, 'nopermissions', '');
725 // The user needs to be a part of the conversation before querying who the members are.
726 if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
727 throw new moodle_exception('You are not a member of this conversation.');
731 return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
732 $params['limitfrom'], $params['limitnum']);
736 * Returns the get conversation members return description.
738 * @return external_description
740 public static function get_conversation_members_returns() {
741 return new external_multiple_structure(
742 self::get_conversation_member_structure(true)
747 * Creates a contact request parameters description.
749 * @return external_function_parameters
751 public static function create_contact_request_parameters() {
752 return new external_function_parameters(
754 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
755 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
761 * Creates a contact request.
763 * @param int $userid The id of the user who is creating the contact request
764 * @param int $requesteduserid The id of the user being requested
766 public static function create_contact_request(int $userid, int $requesteduserid) {
769 // Check if messaging is enabled.
770 if (empty($CFG->messaging)) {
771 throw new moodle_exception('disabled', 'message');
775 $context = context_system::instance();
776 self::validate_context($context);
778 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
779 $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
781 $capability = 'moodle/site:manageallmessaging';
782 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
783 throw new required_capability_exception($context, $capability, 'nopermissions', '');
786 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
789 'itemid' => $params['requesteduserid'],
790 'warningcode' => 'cannotcreatecontactrequest',
791 'message' => 'You are unable to create a contact request for this user'
796 if (!\core_message\api::does_contact_request_exist($params['userid'], $params['requesteduserid'])) {
797 \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
804 * Creates a contact request return description.
806 * @return external_description
808 public static function create_contact_request_returns() {
809 return new external_warnings();
813 * Confirm a contact request parameters description.
815 * @return external_function_parameters
817 public static function confirm_contact_request_parameters() {
818 return new external_function_parameters(
820 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
821 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
827 * Confirm a contact request.
829 * @param int $userid The id of the user who is creating the contact request
830 * @param int $requesteduserid The id of the user being requested
832 public static function confirm_contact_request(int $userid, int $requesteduserid) {
835 // Check if messaging is enabled.
836 if (empty($CFG->messaging)) {
837 throw new moodle_exception('disabled', 'message');
841 $context = context_system::instance();
842 self::validate_context($context);
844 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
845 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
847 $capability = 'moodle/site:manageallmessaging';
848 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
849 throw new required_capability_exception($context, $capability, 'nopermissions', '');
852 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
858 * Confirm a contact request return description.
860 * @return external_description
862 public static function confirm_contact_request_returns() {
863 return new external_warnings();
867 * Declines a contact request parameters description.
869 * @return external_function_parameters
871 public static function decline_contact_request_parameters() {
872 return new external_function_parameters(
874 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
875 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
881 * Declines a contact request.
883 * @param int $userid The id of the user who is creating the contact request
884 * @param int $requesteduserid The id of the user being requested
886 public static function decline_contact_request(int $userid, int $requesteduserid) {
889 // Check if messaging is enabled.
890 if (empty($CFG->messaging)) {
891 throw new moodle_exception('disabled', 'message');
895 $context = context_system::instance();
896 self::validate_context($context);
898 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
899 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
901 $capability = 'moodle/site:manageallmessaging';
902 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
903 throw new required_capability_exception($context, $capability, 'nopermissions', '');
906 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
912 * Declines a contact request return description.
914 * @return external_description
916 public static function decline_contact_request_returns() {
917 return new external_warnings();
921 * Return the structure of a message area contact.
923 * @return external_single_structure
926 private static function get_messagearea_contact_structure() {
927 return new external_single_structure(
929 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
930 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
931 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
932 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
933 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
934 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
935 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
936 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
937 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
938 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
939 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
940 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
941 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
942 VALUE_DEFAULT, null),
948 * Return the structure of a conversation.
950 * @return external_single_structure
953 private static function get_conversation_structure() {
954 return new external_single_structure(
956 'id' => new external_value(PARAM_INT, 'The conversation id'),
957 'name' => new external_value(PARAM_NOTAGS, 'The conversation name, if set', VALUE_DEFAULT, null),
958 'subname' => new external_value(PARAM_NOTAGS, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
959 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group)'),
960 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
961 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked conversation this conversation as a favourite'),
962 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
963 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
964 VALUE_DEFAULT, null),
965 'members' => new external_multiple_structure(
966 self::get_conversation_member_structure()
968 'messages' => new external_multiple_structure(
969 self::get_conversation_message_structure()
976 * Return the structure of a conversation member.
978 * @param bool $includecontactrequests Are we including contact requests?
979 * @return external_single_structure
982 private static function get_conversation_member_structure(bool $includecontactrequests = false) {
984 'id' => new external_value(PARAM_INT, 'The user id'),
985 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
986 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
987 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
988 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
989 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
990 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
991 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
994 if ($includecontactrequests) {
995 $result['contactrequests'] = new external_multiple_structure(
996 new external_single_structure(
998 'id' => new external_value(PARAM_INT, 'The id of the message'),
999 'userid' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1000 'requesteduserid' => new external_value(PARAM_RAW, 'The text of the message'),
1001 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1003 ), 'The contact requests', VALUE_OPTIONAL
1007 return new external_single_structure(
1013 * Return the structure of a message area message.
1015 * @return external_single_structure
1018 private static function get_conversation_message_structure() {
1019 return new external_single_structure(
1021 'id' => new external_value(PARAM_INT, 'The id of the message'),
1022 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1023 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1024 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1030 * Return the structure of a message area message.
1032 * @return external_single_structure
1035 private static function get_messagearea_message_structure() {
1036 return new external_single_structure(
1038 'id' => new external_value(PARAM_INT, 'The id of the message'),
1039 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1040 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1041 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1042 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1043 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1044 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1045 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1046 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1047 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1053 * Get messagearea search users in course parameters.
1055 * @return external_function_parameters
1058 public static function data_for_messagearea_search_users_in_course_parameters() {
1059 return new external_function_parameters(
1061 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1062 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1063 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1064 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1065 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1071 * Get messagearea search users in course results.
1073 * @param int $userid The id of the user who is performing the search
1074 * @param int $courseid The id of the course
1075 * @param string $search The string being searched
1076 * @param int $limitfrom
1077 * @param int $limitnum
1079 * @throws moodle_exception
1082 public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1084 global $CFG, $PAGE, $USER;
1086 // Check if messaging is enabled.
1087 if (empty($CFG->messaging)) {
1088 throw new moodle_exception('disabled', 'message');
1091 $systemcontext = context_system::instance();
1094 'userid' => $userid,
1095 'courseid' => $courseid,
1096 'search' => $search,
1097 'limitfrom' => $limitfrom,
1098 'limitnum' => $limitnum
1100 $params = self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1101 self::validate_context($systemcontext);
1103 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1104 throw new moodle_exception('You do not have permission to perform this action.');
1107 $users = \core_message\api::search_users_in_course(
1109 $params['courseid'],
1111 $params['limitfrom'],
1114 $results = new \core_message\output\messagearea\user_search_results($users);
1116 $renderer = $PAGE->get_renderer('core_message');
1117 return $results->export_for_template($renderer);
1121 * Get messagearea search users in course returns.
1123 * @return external_single_structure
1126 public static function data_for_messagearea_search_users_in_course_returns() {
1127 return new external_single_structure(
1129 'contacts' => new external_multiple_structure(
1130 self::get_messagearea_contact_structure()
1137 * Get messagearea search users parameters.
1139 * @return external_function_parameters
1142 public static function data_for_messagearea_search_users_parameters() {
1143 return new external_function_parameters(
1145 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1146 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1147 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1153 * Get messagearea search users results.
1155 * @param int $userid The id of the user who is performing the search
1156 * @param string $search The string being searched
1157 * @param int $limitnum
1159 * @throws moodle_exception
1162 public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1163 global $CFG, $PAGE, $USER;
1165 // Check if messaging is enabled.
1166 if (empty($CFG->messaging)) {
1167 throw new moodle_exception('disabled', 'message');
1170 $systemcontext = context_system::instance();
1173 'userid' => $userid,
1174 'search' => $search,
1175 'limitnum' => $limitnum
1177 $params = self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1178 self::validate_context($systemcontext);
1180 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1181 throw new moodle_exception('You do not have permission to perform this action.');
1184 list($contacts, $courses, $noncontacts) = \core_message\api::search_users(
1190 $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1192 $renderer = $PAGE->get_renderer('core_message');
1193 return $search->export_for_template($renderer);
1197 * Get messagearea search users returns.
1199 * @return external_single_structure
1202 public static function data_for_messagearea_search_users_returns() {
1203 return new external_single_structure(
1205 'contacts' => new external_multiple_structure(
1206 self::get_messagearea_contact_structure()
1208 'courses' => new external_multiple_structure(
1209 new external_single_structure(
1211 'id' => new external_value(PARAM_INT, 'The course id'),
1212 'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1213 'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1217 'noncontacts' => new external_multiple_structure(
1218 self::get_messagearea_contact_structure()
1225 * Get messagearea search messages parameters.
1227 * @return external_function_parameters
1230 public static function data_for_messagearea_search_messages_parameters() {
1231 return new external_function_parameters(
1233 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1234 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1235 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1236 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1242 * Get messagearea search messages results.
1244 * @param int $userid The id of the user who is performing the search
1245 * @param string $search The string being searched
1246 * @param int $limitfrom
1247 * @param int $limitnum
1249 * @throws moodle_exception
1252 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1253 global $CFG, $PAGE, $USER;
1255 // Check if messaging is enabled.
1256 if (empty($CFG->messaging)) {
1257 throw new moodle_exception('disabled', 'message');
1260 $systemcontext = context_system::instance();
1263 'userid' => $userid,
1264 'search' => $search,
1265 'limitfrom' => $limitfrom,
1266 'limitnum' => $limitnum
1269 $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1270 self::validate_context($systemcontext);
1272 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1273 throw new moodle_exception('You do not have permission to perform this action.');
1276 $messages = \core_message\api::search_messages(
1279 $params['limitfrom'],
1282 $results = new \core_message\output\messagearea\message_search_results($messages);
1284 $renderer = $PAGE->get_renderer('core_message');
1285 return $results->export_for_template($renderer);
1289 * Get messagearea search messages returns.
1291 * @return external_single_structure
1294 public static function data_for_messagearea_search_messages_returns() {
1295 return new external_single_structure(
1297 'contacts' => new external_multiple_structure(
1298 self::get_messagearea_contact_structure()
1305 * Get conversations parameters.
1307 * @return external_function_parameters
1310 public static function get_conversations_parameters() {
1311 return new external_function_parameters(
1313 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1314 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1315 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1316 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1317 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1318 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1319 VALUE_DEFAULT, null),
1326 * Get the list of conversations for the user.
1328 * @param int $userid The id of the user who is performing the search
1329 * @param int $limitfrom
1330 * @param int $limitnum
1331 * @param int|null $type
1332 * @param bool|null $favourites
1334 * @throws \moodle_exception if the messaging feature is disabled on the site.
1337 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null) {
1340 // All the standard BL checks.
1341 if (empty($CFG->messaging)) {
1342 throw new moodle_exception('disabled', 'message');
1346 'userid' => $userid,
1347 'limitfrom' => $limitfrom,
1348 'limitnum' => $limitnum,
1350 'favourites' => $favourites
1352 $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1354 $systemcontext = context_system::instance();
1355 self::validate_context($systemcontext);
1357 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1358 throw new moodle_exception('You do not have permission to perform this action.');
1361 $conversations = \core_message\api::get_conversations(
1363 $params['limitfrom'],
1364 $params['limitnum'],
1366 $params['favourites']
1369 return (object) ['conversations' => $conversations];
1373 * Get conversations returns.
1375 * @return external_single_structure
1378 public static function get_conversations_returns() {
1379 return new external_single_structure(
1381 'conversations' => new external_multiple_structure(
1382 self::get_conversation_structure()
1389 * The messagearea conversations parameters.
1391 * @deprecated since 3.6
1392 * @return external_function_parameters
1395 public static function data_for_messagearea_conversations_parameters() {
1396 return new external_function_parameters(
1398 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1399 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1400 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1406 * Get messagearea conversations.
1408 * NOTE FOR FINAL DEPRECATION:
1409 * When removing this method, please also consider removal of get_conversations_legacy_formatter()
1410 * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
1411 * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
1414 * @deprecated since 3.6
1415 * @param int $userid The id of the user who we are viewing conversations for
1416 * @param int $limitfrom
1417 * @param int $limitnum
1419 * @throws moodle_exception
1422 public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1423 global $CFG, $PAGE, $USER;
1425 // Check if messaging is enabled.
1426 if (empty($CFG->messaging)) {
1427 throw new moodle_exception('disabled', 'message');
1430 $systemcontext = context_system::instance();
1433 'userid' => $userid,
1434 'limitfrom' => $limitfrom,
1435 'limitnum' => $limitnum
1437 $params = self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1438 self::validate_context($systemcontext);
1440 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1441 throw new moodle_exception('You do not have permission to perform this action.');
1444 $conversations = \core_message\api::get_conversations($params['userid'], $params['limitfrom'], $params['limitnum']);
1446 // Format the conversations in the legacy style, as the get_conversations method has since been changed.
1447 $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
1449 $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1451 $renderer = $PAGE->get_renderer('core_message');
1452 return $conversations->export_for_template($renderer);
1456 * The messagearea conversations return structure.
1458 * @deprecated since 3.6
1459 * @return external_single_structure
1462 public static function data_for_messagearea_conversations_returns() {
1463 return new external_single_structure(
1465 'contacts' => new external_multiple_structure(
1466 self::get_messagearea_contact_structure()
1473 * Marking the method as deprecated.
1477 public static function data_for_messagearea_conversations_is_deprecated() {
1482 * The messagearea contacts return parameters.
1484 * @return external_function_parameters
1487 public static function data_for_messagearea_contacts_parameters() {
1488 return self::data_for_messagearea_conversations_parameters();
1492 * Get messagearea contacts parameters.
1494 * @param int $userid The id of the user who we are viewing conversations for
1495 * @param int $limitfrom
1496 * @param int $limitnum
1498 * @throws moodle_exception
1501 public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1502 global $CFG, $PAGE, $USER;
1504 // Check if messaging is enabled.
1505 if (empty($CFG->messaging)) {
1506 throw new moodle_exception('disabled', 'message');
1509 $systemcontext = context_system::instance();
1512 'userid' => $userid,
1513 'limitfrom' => $limitfrom,
1514 'limitnum' => $limitnum
1516 $params = self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1517 self::validate_context($systemcontext);
1519 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1520 throw new moodle_exception('You do not have permission to perform this action.');
1523 $contacts = \core_message\api::get_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1524 $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1526 $renderer = $PAGE->get_renderer('core_message');
1527 return $contacts->export_for_template($renderer);
1531 * The messagearea contacts return structure.
1533 * @return external_single_structure
1536 public static function data_for_messagearea_contacts_returns() {
1537 return self::data_for_messagearea_conversations_returns();
1541 * The messagearea messages parameters.
1543 * @return external_function_parameters
1546 public static function data_for_messagearea_messages_parameters() {
1547 return new external_function_parameters(
1549 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1550 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1551 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1552 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1553 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1554 'timefrom' => new external_value(PARAM_INT,
1555 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1561 * Get messagearea messages.
1563 * @param int $currentuserid The current user's id
1564 * @param int $otheruserid The other user's id
1565 * @param int $limitfrom
1566 * @param int $limitnum
1567 * @param boolean $newest
1569 * @throws moodle_exception
1572 public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1573 $newest = false, $timefrom = 0) {
1574 global $CFG, $PAGE, $USER;
1576 // Check if messaging is enabled.
1577 if (empty($CFG->messaging)) {
1578 throw new moodle_exception('disabled', 'message');
1581 $systemcontext = context_system::instance();
1584 'currentuserid' => $currentuserid,
1585 'otheruserid' => $otheruserid,
1586 'limitfrom' => $limitfrom,
1587 'limitnum' => $limitnum,
1588 'newest' => $newest,
1589 'timefrom' => $timefrom,
1591 $params = self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1592 self::validate_context($systemcontext);
1594 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1595 throw new moodle_exception('You do not have permission to perform this action.');
1598 if ($params['newest']) {
1599 $sort = 'timecreated DESC';
1601 $sort = 'timecreated ASC';
1604 // We need to enforce a one second delay on messages to avoid race conditions of current
1605 // messages still being sent.
1607 // There is a chance that we could request messages before the current time's
1608 // second has elapsed and while other messages are being sent in that same second. In which
1609 // case those messages will be lost.
1611 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1612 if (!empty($params['timefrom'])) {
1613 $timeto = time() - 1;
1618 // No requesting messages from the current time, as stated above.
1619 if ($params['timefrom'] == time()) {
1622 $messages = \core_message\api::get_messages($params['currentuserid'], $params['otheruserid'], $params['limitfrom'],
1623 $params['limitnum'], $sort, $params['timefrom'], $timeto);
1626 $messages = new \core_message\output\messagearea\messages($params['currentuserid'], $params['otheruserid'], $messages);
1628 $renderer = $PAGE->get_renderer('core_message');
1629 return $messages->export_for_template($renderer);
1633 * The messagearea messages return structure.
1635 * @return external_single_structure
1638 public static function data_for_messagearea_messages_returns() {
1639 return new external_single_structure(
1641 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1642 the messages on behalf of?'),
1643 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1644 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1645 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1646 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1647 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1648 'messages' => new external_multiple_structure(
1649 self::get_messagearea_message_structure()
1651 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1657 * The conversation messages parameters.
1659 * @return external_function_parameters
1662 public static function get_conversation_messages_parameters() {
1663 return new external_function_parameters(
1665 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1666 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1667 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1668 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1669 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1670 'timefrom' => new external_value(PARAM_INT,
1671 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1677 * Get conversation messages.
1679 * @param int $currentuserid The current user's id.
1680 * @param int $convid The conversation id.
1681 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1682 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1683 * @param bool $newest True for getting first newest messages, false otherwise.
1684 * @param int $timefrom The time from the conversation messages to get.
1685 * @return stdClass The messages and members who have sent some of these messages.
1686 * @throws moodle_exception
1689 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1690 bool $newest = false, int $timefrom = 0) {
1691 global $CFG, $PAGE, $USER;
1693 // Check if messaging is enabled.
1694 if (empty($CFG->messaging)) {
1695 throw new moodle_exception('disabled', 'message');
1698 $systemcontext = context_system::instance();
1701 'currentuserid' => $currentuserid,
1702 'convid' => $convid,
1703 'limitfrom' => $limitfrom,
1704 'limitnum' => $limitnum,
1705 'newest' => $newest,
1706 'timefrom' => $timefrom,
1708 $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1709 self::validate_context($systemcontext);
1711 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1712 throw new moodle_exception('You do not have permission to perform this action.');
1715 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1717 // We need to enforce a one second delay on messages to avoid race conditions of current
1718 // messages still being sent.
1720 // There is a chance that we could request messages before the current time's
1721 // second has elapsed and while other messages are being sent in that same second. In which
1722 // case those messages will be lost.
1724 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1725 $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1727 // No requesting messages from the current time, as stated above.
1728 if ($params['timefrom'] == time()) {
1731 $messages = \core_message\api::get_conversation_messages(
1732 $params['currentuserid'],
1734 $params['limitfrom'],
1735 $params['limitnum'],
1737 $params['timefrom'],
1745 * The messagearea messages return structure.
1747 * @return external_single_structure
1750 public static function get_conversation_messages_returns() {
1751 return new external_single_structure(
1753 'id' => new external_value(PARAM_INT, 'The conversation id'),
1754 'members' => new external_multiple_structure(
1755 self::get_conversation_member_structure()
1757 'messages' => new external_multiple_structure(
1758 self::get_conversation_message_structure()
1765 * The get most recent message return parameters.
1767 * @return external_function_parameters
1770 public static function data_for_messagearea_get_most_recent_message_parameters() {
1771 return new external_function_parameters(
1773 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1774 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1780 * Get the most recent message in a conversation.
1782 * @param int $currentuserid The current user's id
1783 * @param int $otheruserid The other user's id
1785 * @throws moodle_exception
1788 public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
1789 global $CFG, $PAGE, $USER;
1791 // Check if messaging is enabled.
1792 if (empty($CFG->messaging)) {
1793 throw new moodle_exception('disabled', 'message');
1796 $systemcontext = context_system::instance();
1799 'currentuserid' => $currentuserid,
1800 'otheruserid' => $otheruserid
1802 $params = self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
1803 self::validate_context($systemcontext);
1805 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1806 throw new moodle_exception('You do not have permission to perform this action.');
1809 $message = \core_message\api::get_most_recent_message($params['currentuserid'], $params['otheruserid']);
1810 $message = new \core_message\output\messagearea\message($message);
1812 $renderer = $PAGE->get_renderer('core_message');
1813 return $message->export_for_template($renderer);
1817 * The get most recent message return structure.
1819 * @return external_single_structure
1822 public static function data_for_messagearea_get_most_recent_message_returns() {
1823 return self::get_messagearea_message_structure();
1827 * The get profile parameters.
1829 * @return external_function_parameters
1832 public static function data_for_messagearea_get_profile_parameters() {
1833 return new external_function_parameters(
1835 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1836 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
1842 * Get the profile information for a contact.
1844 * @param int $currentuserid The current user's id
1845 * @param int $otheruserid The id of the user whose profile we are viewing
1847 * @throws moodle_exception
1850 public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
1851 global $CFG, $PAGE, $USER;
1853 // Check if messaging is enabled.
1854 if (empty($CFG->messaging)) {
1855 throw new moodle_exception('disabled', 'message');
1858 $systemcontext = context_system::instance();
1861 'currentuserid' => $currentuserid,
1862 'otheruserid' => $otheruserid
1864 $params = self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
1865 self::validate_context($systemcontext);
1867 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1868 throw new moodle_exception('You do not have permission to perform this action.');
1871 $profile = \core_message\api::get_profile($params['currentuserid'], $params['otheruserid']);
1872 $profile = new \core_message\output\messagearea\profile($profile);
1874 $renderer = $PAGE->get_renderer('core_message');
1875 return $profile->export_for_template($renderer);
1879 * The get profile return structure.
1881 * @return external_single_structure
1884 public static function data_for_messagearea_get_profile_returns() {
1885 return new external_single_structure(
1887 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
1888 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
1889 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
1890 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
1891 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1892 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1893 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1894 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1895 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1896 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
1897 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
1903 * Get contacts parameters description.
1905 * @return external_function_parameters
1908 public static function get_contacts_parameters() {
1909 return new external_function_parameters(array());
1915 * @return external_description
1918 public static function get_contacts() {
1919 global $CFG, $PAGE, $USER;
1921 // Check if messaging is enabled.
1922 if (empty($CFG->messaging)) {
1923 throw new moodle_exception('disabled', 'message');
1926 require_once($CFG->dirroot . '/user/lib.php');
1928 $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
1929 $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
1930 foreach ($contacts as $contact) {
1933 if (\core_message\helper::is_online($contact->lastaccess)) {
1937 $newcontact = array(
1938 'id' => $contact->id,
1939 'fullname' => fullname($contact),
1940 'unread' => $contact->messagecount
1943 $userpicture = new user_picture($contact);
1944 $userpicture->size = 1; // Size f1.
1945 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1946 $userpicture->size = 0; // Size f2.
1947 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1949 $allcontacts[$mode][$contact->id] = $newcontact;
1952 $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
1953 foreach ($strangers as $contact) {
1954 $newcontact = array(
1955 'id' => $contact->id,
1956 'fullname' => fullname($contact),
1957 'unread' => $contact->messagecount
1960 $userpicture = new user_picture($contact);
1961 $userpicture->size = 1; // Size f1.
1962 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1963 $userpicture->size = 0; // Size f2.
1964 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1966 $allcontacts['strangers'][$contact->id] = $newcontact;
1969 // Add noreply user and support user to the list, if they don't exist.
1970 $supportuser = core_user::get_support_user();
1971 if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
1972 $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
1973 if ($supportuser->messagecount > 0) {
1974 $supportuser->fullname = fullname($supportuser);
1975 $supportuser->unread = $supportuser->messagecount;
1976 $allcontacts['strangers'][$supportuser->id] = $supportuser;
1980 $noreplyuser = core_user::get_noreply_user();
1981 if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
1982 $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
1983 if ($noreplyuser->messagecount > 0) {
1984 $noreplyuser->fullname = fullname($noreplyuser);
1985 $noreplyuser->unread = $noreplyuser->messagecount;
1986 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
1990 return $allcontacts;
1994 * Get contacts return description.
1996 * @return external_description
1999 public static function get_contacts_returns() {
2000 return new external_single_structure(
2002 'online' => new external_multiple_structure(
2003 new external_single_structure(
2005 'id' => new external_value(PARAM_INT, 'User ID'),
2006 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2007 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2008 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2009 'unread' => new external_value(PARAM_INT, 'Unread message count')
2012 'List of online contacts'
2014 'offline' => new external_multiple_structure(
2015 new external_single_structure(
2017 'id' => new external_value(PARAM_INT, 'User ID'),
2018 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2019 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2020 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2021 'unread' => new external_value(PARAM_INT, 'Unread message count')
2024 'List of offline contacts'
2026 'strangers' => new external_multiple_structure(
2027 new external_single_structure(
2029 'id' => new external_value(PARAM_INT, 'User ID'),
2030 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2031 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2032 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2033 'unread' => new external_value(PARAM_INT, 'Unread message count')
2036 'List of users that are not in the user\'s contact list but have sent a message'
2043 * Search contacts parameters description.
2045 * @return external_function_parameters
2048 public static function search_contacts_parameters() {
2049 return new external_function_parameters(
2051 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2052 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2053 VALUE_DEFAULT, false)
2061 * @param string $searchtext query string.
2062 * @param bool $onlymycourses limit the search to the user's courses only.
2063 * @return external_description
2066 public static function search_contacts($searchtext, $onlymycourses = false) {
2067 global $CFG, $USER, $PAGE;
2068 require_once($CFG->dirroot . '/user/lib.php');
2070 // Check if messaging is enabled.
2071 if (empty($CFG->messaging)) {
2072 throw new moodle_exception('disabled', 'message');
2075 require_once($CFG->libdir . '/enrollib.php');
2077 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2078 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2080 // Extra validation, we do not allow empty queries.
2081 if ($params['searchtext'] === '') {
2082 throw new moodle_exception('querystringcannotbeempty');
2085 $courseids = array();
2086 if ($params['onlymycourses']) {
2087 $mycourses = enrol_get_my_courses(array('id'));
2088 foreach ($mycourses as $mycourse) {
2089 $courseids[] = $mycourse->id;
2092 $courseids[] = SITEID;
2095 // Retrieving the users matching the query.
2096 $users = message_search_users($courseids, $params['searchtext']);
2098 foreach ($users as $user) {
2099 $results[$user->id] = $user;
2102 // Reorganising information.
2103 foreach ($results as &$user) {
2106 'fullname' => fullname($user)
2109 // Avoid undefined property notice as phone not specified.
2110 $user->phone1 = null;
2111 $user->phone2 = null;
2113 $userpicture = new user_picture($user);
2114 $userpicture->size = 1; // Size f1.
2115 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2116 $userpicture->size = 0; // Size f2.
2117 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2126 * Search contacts return description.
2128 * @return external_description
2131 public static function search_contacts_returns() {
2132 return new external_multiple_structure(
2133 new external_single_structure(
2135 'id' => new external_value(PARAM_INT, 'User ID'),
2136 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2137 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2138 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
2146 * Get messages parameters description.
2148 * @return external_function_parameters
2151 public static function get_messages_parameters() {
2152 return new external_function_parameters(
2154 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2155 'useridfrom' => new external_value(
2156 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2158 'type' => new external_value(
2159 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2160 VALUE_DEFAULT, 'both'),
2161 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2162 'newestfirst' => new external_value(
2163 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2164 VALUE_DEFAULT, true),
2165 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2166 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2172 * Get messages function implementation.
2175 * @throws invalid_parameter_exception
2176 * @throws moodle_exception
2177 * @param int $useridto the user id who received the message
2178 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2179 * @param string $type type of message to return, expected values: notifications, conversations and both
2180 * @param bool $read true for retreiving read messages, false for unread
2181 * @param bool $newestfirst true for ordering by newest first, false for oldest first
2182 * @param int $limitfrom limit from
2183 * @param int $limitnum limit num
2184 * @return external_description
2186 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2187 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2190 $warnings = array();
2193 'useridto' => $useridto,
2194 'useridfrom' => $useridfrom,
2197 'newestfirst' => $newestfirst,
2198 'limitfrom' => $limitfrom,
2199 'limitnum' => $limitnum
2202 $params = self::validate_parameters(self::get_messages_parameters(), $params);
2204 $context = context_system::instance();
2205 self::validate_context($context);
2207 $useridto = $params['useridto'];
2208 $useridfrom = $params['useridfrom'];
2209 $type = $params['type'];
2210 $read = $params['read'];
2211 $newestfirst = $params['newestfirst'];
2212 $limitfrom = $params['limitfrom'];
2213 $limitnum = $params['limitnum'];
2215 $allowedvalues = array('notifications', 'conversations', 'both');
2216 if (!in_array($type, $allowedvalues)) {
2217 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2218 'allowed values are: ' . implode(',', $allowedvalues));
2221 // Check if private messaging between users is allowed.
2222 if (empty($CFG->messaging)) {
2223 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2224 if ($type == "conversations") {
2225 throw new moodle_exception('disabled', 'message');
2227 if ($type == "both") {
2229 $warning['item'] = 'message';
2230 $warning['itemid'] = $USER->id;
2231 $warning['warningcode'] = '1';
2232 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2233 Only notifications will be returned';
2234 $warnings[] = $warning;
2238 if (!empty($useridto)) {
2239 if (core_user::is_real_user($useridto)) {
2240 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2242 throw new moodle_exception('invaliduser');
2246 if (!empty($useridfrom)) {
2247 // We use get_user here because the from user can be the noreply or support user.
2248 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2251 // Check if the current user is the sender/receiver or just a privileged user.
2252 if ($useridto != $USER->id and $useridfrom != $USER->id and
2253 !has_capability('moodle/site:readallmessages', $context)) {
2254 throw new moodle_exception('accessdenied', 'admin');
2257 // Which type of messages to retrieve.
2258 $notifications = -1;
2259 if ($type != 'both') {
2260 $notifications = ($type == 'notifications') ? 1 : 0;
2263 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2264 $sort = "mr.timecreated $orderdirection";
2266 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2267 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2269 // In some cases, we don't need to get the to/from user objects from the sql query.
2270 $userfromfullname = '';
2271 $usertofullname = '';
2273 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2274 if (!empty($useridto)) {
2275 $usertofullname = fullname($userto, $canviewfullname);
2276 // The user from may or may not be filled.
2277 if (!empty($useridfrom)) {
2278 $userfromfullname = fullname($userfrom, $canviewfullname);
2281 // If the useridto field is empty, the useridfrom must be filled.
2282 $userfromfullname = fullname($userfrom, $canviewfullname);
2284 foreach ($messages as $mid => $message) {
2286 // Do not return deleted messages.
2287 if (!$message->notification) {
2288 if (($useridto == $USER->id and $message->timeusertodeleted) or
2289 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2290 unset($messages[$mid]);
2295 // We need to get the user from the query.
2296 if (empty($userfromfullname)) {
2297 // Check for non-reply and support users.
2298 if (core_user::is_real_user($message->useridfrom)) {
2299 $user = new stdClass();
2300 $user = username_load_fields_from_object($user, $message, 'userfrom');
2301 $message->userfromfullname = fullname($user, $canviewfullname);
2303 $user = core_user::get_user($message->useridfrom);
2304 $message->userfromfullname = fullname($user, $canviewfullname);
2307 $message->userfromfullname = $userfromfullname;
2310 // We need to get the user from the query.
2311 if (empty($usertofullname)) {
2312 $user = new stdClass();
2313 $user = username_load_fields_from_object($user, $message, 'userto');
2314 $message->usertofullname = fullname($user, $canviewfullname);
2316 $message->usertofullname = $usertofullname;
2319 $message->text = message_format_message_text($message);
2320 $messages[$mid] = (array) $message;
2325 'messages' => $messages,
2326 'warnings' => $warnings
2333 * Get messages return description.
2335 * @return external_single_structure
2338 public static function get_messages_returns() {
2339 return new external_single_structure(
2341 'messages' => new external_multiple_structure(
2342 new external_single_structure(
2344 'id' => new external_value(PARAM_INT, 'Message id'),
2345 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2346 'useridto' => new external_value(PARAM_INT, 'User to id'),
2347 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2348 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2349 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2350 'fullmessageformat' => new external_format_value('fullmessage'),
2351 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2352 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2353 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2354 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2355 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2356 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2357 'timeread' => new external_value(PARAM_INT, 'Time read'),
2358 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2359 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2363 'warnings' => new external_warnings()
2369 * Mark all notifications as read parameters description.
2371 * @return external_function_parameters
2374 public static function mark_all_notifications_as_read_parameters() {
2375 return new external_function_parameters(
2377 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2378 'useridfrom' => new external_value(
2379 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2386 * Mark all notifications as read function.
2389 * @throws invalid_parameter_exception
2390 * @throws moodle_exception
2391 * @param int $useridto the user id who received the message
2392 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2393 * @return external_description
2395 public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2398 $params = self::validate_parameters(
2399 self::mark_all_notifications_as_read_parameters(),
2401 'useridto' => $useridto,
2402 'useridfrom' => $useridfrom,
2406 $context = context_system::instance();
2407 self::validate_context($context);
2409 $useridto = $params['useridto'];
2410 $useridfrom = $params['useridfrom'];
2412 if (!empty($useridto)) {
2413 if (core_user::is_real_user($useridto)) {
2414 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2416 throw new moodle_exception('invaliduser');
2420 if (!empty($useridfrom)) {
2421 // We use get_user here because the from user can be the noreply or support user.
2422 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2425 // Check if the current user is the sender/receiver or just a privileged user.
2426 if ($useridto != $USER->id and $useridfrom != $USER->id and
2427 // The deleteanymessage cap seems more reasonable here than readallmessages.
2428 !has_capability('moodle/site:deleteanymessage', $context)) {
2429 throw new moodle_exception('accessdenied', 'admin');
2432 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2438 * Mark all notifications as read return description.
2440 * @return external_single_structure
2443 public static function mark_all_notifications_as_read_returns() {
2444 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2448 * Get unread conversations count parameters description.
2450 * @return external_function_parameters
2453 public static function get_unread_conversations_count_parameters() {
2454 return new external_function_parameters(
2456 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2462 * Get unread messages count function.
2465 * @throws invalid_parameter_exception
2466 * @throws moodle_exception
2467 * @param int $useridto the user id who received the message
2468 * @return external_description
2470 public static function get_unread_conversations_count($useridto) {
2473 // Check if messaging is enabled.
2474 if (empty($CFG->messaging)) {
2475 throw new moodle_exception('disabled', 'message');
2478 $params = self::validate_parameters(
2479 self::get_unread_conversations_count_parameters(),
2480 array('useridto' => $useridto)
2483 $context = context_system::instance();
2484 self::validate_context($context);
2486 $useridto = $params['useridto'];
2488 if (!empty($useridto)) {
2489 if (core_user::is_real_user($useridto)) {
2490 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2492 throw new moodle_exception('invaliduser');
2495 $useridto = $USER->id;
2498 // Check if the current user is the receiver or just a privileged user.
2499 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2500 throw new moodle_exception('accessdenied', 'admin');
2503 return \core_message\api::count_unread_conversations($userto);
2507 * Get unread conversations count return description.
2509 * @return external_single_structure
2512 public static function get_unread_conversations_count_returns() {
2513 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2517 * Get blocked users parameters description.
2519 * @return external_function_parameters
2522 public static function get_blocked_users_parameters() {
2523 return new external_function_parameters(
2525 'userid' => new external_value(PARAM_INT,
2526 'the user whose blocked users we want to retrieve',
2533 * Retrieve a list of users blocked
2535 * @param int $userid the user whose blocked users we want to retrieve
2536 * @return external_description
2539 public static function get_blocked_users($userid) {
2540 global $CFG, $USER, $PAGE;
2542 // Warnings array, it can be empty at the end but is mandatory.
2543 $warnings = array();
2549 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2550 $userid = $params['userid'];
2552 // Validate context.
2553 $context = context_system::instance();
2554 self::validate_context($context);
2556 // Check if private messaging between users is allowed.
2557 if (empty($CFG->messaging)) {
2558 throw new moodle_exception('disabled', 'message');
2561 $user = core_user::get_user($userid, '*', MUST_EXIST);
2562 core_user::require_active_user($user);
2564 // Check if we have permissions for retrieve the information.
2565 $capability = 'moodle/site:manageallmessaging';
2566 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2567 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2570 // Now, we can get safely all the blocked users.
2571 $users = \core_message\api::get_blocked_users($user->id);
2573 $blockedusers = array();
2574 foreach ($users as $user) {
2577 'fullname' => fullname($user),
2580 $userpicture = new user_picture($user);
2581 $userpicture->size = 1; // Size f1.
2582 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2584 $blockedusers[] = $newuser;
2588 'users' => $blockedusers,
2589 'warnings' => $warnings
2595 * Get blocked users return description.
2597 * @return external_single_structure
2600 public static function get_blocked_users_returns() {
2601 return new external_single_structure(
2603 'users' => new external_multiple_structure(
2604 new external_single_structure(
2606 'id' => new external_value(PARAM_INT, 'User ID'),
2607 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2608 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2611 'List of blocked users'
2613 'warnings' => new external_warnings()
2619 * Returns description of method parameters
2621 * @return external_function_parameters
2624 public static function mark_message_read_parameters() {
2625 return new external_function_parameters(
2627 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2628 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2635 * Mark a single message as read, trigger message_viewed event
2637 * @param int $messageid id of the message (in the message table)
2638 * @param int $timeread timestamp for when the message should be marked read
2639 * @return external_description
2640 * @throws invalid_parameter_exception
2641 * @throws moodle_exception
2644 public static function mark_message_read($messageid, $timeread) {
2645 global $CFG, $DB, $USER;
2647 // Check if private messaging between users is allowed.
2648 if (empty($CFG->messaging)) {
2649 throw new moodle_exception('disabled', 'message');
2652 // Warnings array, it can be empty at the end but is mandatory.
2653 $warnings = array();
2657 'messageid' => $messageid,
2658 'timeread' => $timeread
2660 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2662 if (empty($params['timeread'])) {
2665 $timeread = $params['timeread'];
2668 // Validate context.
2669 $context = context_system::instance();
2670 self::validate_context($context);
2672 $sql = "SELECT m.*, mcm.userid as useridto
2674 INNER JOIN {message_conversations} mc
2675 ON m.conversationid = mc.id
2676 INNER JOIN {message_conversation_members} mcm
2677 ON mcm.conversationid = mc.id
2678 LEFT JOIN {message_user_actions} mua
2679 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2680 WHERE mua.id is NULL
2681 AND mcm.userid != m.useridfrom
2683 $messageparams = [];
2684 $messageparams[] = $USER->id;
2685 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2686 $messageparams[] = $params['messageid'];
2687 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2689 if ($message->useridto != $USER->id) {
2690 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2693 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2696 'messageid' => $message->id,
2697 'warnings' => $warnings
2703 * Returns description of method result value
2705 * @return external_description
2708 public static function mark_message_read_returns() {
2709 return new external_single_structure(
2711 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2712 'warnings' => new external_warnings()
2718 * Returns description of method parameters
2720 * @return external_function_parameters
2722 public static function mark_notification_read_parameters() {
2723 return new external_function_parameters(
2725 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2726 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2733 * Mark a single notification as read.
2735 * This will trigger a 'notification_viewed' event.
2737 * @param int $notificationid id of the notification
2738 * @param int $timeread timestamp for when the notification should be marked read
2739 * @return external_description
2740 * @throws invalid_parameter_exception
2741 * @throws moodle_exception
2743 public static function mark_notification_read($notificationid, $timeread) {
2744 global $CFG, $DB, $USER;
2746 // Check if private messaging between users is allowed.
2747 if (empty($CFG->messaging)) {
2748 throw new moodle_exception('disabled', 'message');
2751 // Warnings array, it can be empty at the end but is mandatory.
2752 $warnings = array();
2756 'notificationid' => $notificationid,
2757 'timeread' => $timeread
2759 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2761 if (empty($params['timeread'])) {
2764 $timeread = $params['timeread'];
2767 // Validate context.
2768 $context = context_system::instance();
2769 self::validate_context($context);
2771 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2773 if ($notification->useridto != $USER->id) {
2774 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2775 'notification as read');
2778 \core_message\api::mark_notification_as_read($notification, $timeread);
2781 'notificationid' => $notification->id,
2782 'warnings' => $warnings
2789 * Returns description of method result value
2791 * @return external_description
2793 public static function mark_notification_read_returns() {
2794 return new external_single_structure(
2796 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2797 'warnings' => new external_warnings()
2803 * Mark all messages as read parameters description.
2805 * @deprecated since 3.6
2806 * @return external_function_parameters
2809 public static function mark_all_messages_as_read_parameters() {
2810 return new external_function_parameters(
2812 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2813 'useridfrom' => new external_value(
2814 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2821 * Mark all messages as read function.
2823 * @deprecated since 3.6
2824 * @throws invalid_parameter_exception
2825 * @throws moodle_exception
2826 * @param int $useridto the user id who received the message
2827 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2828 * @return external_description
2831 public static function mark_all_messages_as_read($useridto, $useridfrom) {
2834 // Check if messaging is enabled.
2835 if (empty($CFG->messaging)) {
2836 throw new moodle_exception('disabled', 'message');
2839 $params = self::validate_parameters(
2840 self::mark_all_messages_as_read_parameters(),
2842 'useridto' => $useridto,
2843 'useridfrom' => $useridfrom,
2847 $context = context_system::instance();
2848 self::validate_context($context);
2850 $useridto = $params['useridto'];
2851 $useridfrom = $params['useridfrom'];
2853 if (!empty($useridto)) {
2854 if (core_user::is_real_user($useridto)) {
2855 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2857 throw new moodle_exception('invaliduser');
2861 if (!empty($useridfrom)) {
2862 // We use get_user here because the from user can be the noreply or support user.
2863 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2866 // Check if the current user is the sender/receiver or just a privileged user.
2867 if ($useridto != $USER->id and $useridfrom != $USER->id and
2868 // The deleteanymessage cap seems more reasonable here than readallmessages.
2869 !has_capability('moodle/site:deleteanymessage', $context)) {
2870 throw new moodle_exception('accessdenied', 'admin');
2874 if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
2875 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
2878 \core_message\api::mark_all_messages_as_read($useridto);
2885 * Mark all messages as read return description.
2887 * @deprecated since 3.6
2888 * @return external_single_structure
2891 public static function mark_all_messages_as_read_returns() {
2892 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2896 * Marking the method as deprecated.
2900 public static function mark_all_messages_as_read_is_deprecated() {
2905 * Mark all conversation messages as read parameters description.
2907 * @return external_function_parameters
2910 public static function mark_all_conversation_messages_as_read_parameters() {
2911 return new external_function_parameters(
2913 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2915 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2921 * Mark all conversation messages as read function.
2923 * @param int $userid The user id of who we want to delete the conversation for
2924 * @param int $conversationid The id of the conversations
2927 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2930 // Check if messaging is enabled.
2931 if (empty($CFG->messaging)) {
2932 throw new moodle_exception('disabled', 'message');
2936 'userid' => $userid,
2937 'conversationid' => $conversationid,
2939 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2941 $context = context_system::instance();
2942 self::validate_context($context);
2944 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2945 core_user::require_active_user($user);
2947 if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
2948 \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
2950 throw new moodle_exception('accessdenied', 'admin');
2955 * Mark all conversation messages as read return description.
2957 * @return external_warnings
2960 public static function mark_all_conversation_messages_as_read_returns() {
2961 return new external_warnings();
2965 * Returns description of method parameters.
2967 * @deprecated since 3.6
2968 * @return external_function_parameters
2971 public static function delete_conversation_parameters() {
2972 return new external_function_parameters(
2974 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2975 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
2981 * Deletes a conversation.
2983 * @deprecated since 3.6
2984 * @param int $userid The user id of who we want to delete the conversation for
2985 * @param int $otheruserid The user id of the other user in the conversation
2987 * @throws moodle_exception
2990 public static function delete_conversation($userid, $otheruserid) {
2993 // Check if private messaging between users is allowed.
2994 if (empty($CFG->messaging)) {
2995 throw new moodle_exception('disabled', 'message');
2998 // Warnings array, it can be empty at the end but is mandatory.
2999 $warnings = array();
3003 'userid' => $userid,
3004 'otheruserid' => $otheruserid,
3006 $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
3008 // Validate context.
3009 $context = context_system::instance();
3010 self::validate_context($context);
3012 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3013 core_user::require_active_user($user);
3015 if (!$conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']])) {
3019 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3020 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3023 throw new moodle_exception('You do not have permission to delete messages');
3027 'status' => $status,
3028 'warnings' => $warnings
3035 * Returns description of method result value.
3037 * @deprecated since 3.6
3038 * @return external_description
3041 public static function delete_conversation_returns() {
3042 return new external_single_structure(
3044 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
3045 'warnings' => new external_warnings()
3051 * Marking the method as deprecated.
3055 public static function delete_conversation_is_deprecated() {
3060 * Returns description of method parameters.
3062 * @return external_function_parameters
3065 public static function delete_conversations_by_id_parameters() {
3066 return new external_function_parameters(
3068 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3069 'conversationids' => new external_multiple_structure(
3070 new external_value(PARAM_INT, 'The id of the conversation'),
3071 'List of conversation IDs'
3078 * Deletes a conversation.
3080 * @param int $userid The user id of who we want to delete the conversation for
3081 * @param int[] $conversationids The ids of the conversations
3083 * @throws moodle_exception
3086 public static function delete_conversations_by_id($userid, array $conversationids) {
3089 // Check if private messaging between users is allowed.
3090 if (empty($CFG->messaging)) {
3091 throw new moodle_exception('disabled', 'message');
3096 'userid' => $userid,
3097 'conversationids' => $conversationids,
3099 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
3101 // Validate context.
3102 $context = context_system::instance();
3103 self::validate_context($context);
3105 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3106 core_user::require_active_user($user);
3108 foreach ($params['conversationids'] as $conversationid) {
3109 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3110 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3112 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
3120 * Returns description of method result value.
3122 * @return external_description
3125 public static function delete_conversations_by_id_returns() {
3126 return new external_warnings();
3130 * Returns description of method parameters
3132 * @return external_function_parameters
3135 public static function delete_message_parameters() {
3136 return new external_function_parameters(
3138 'messageid' => new external_value(PARAM_INT, 'The message id'),
3139 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
3140 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
3148 * @param int $messageid the message id
3149 * @param int $userid the user id of who we want to delete the message for
3150 * @param bool $read if is a message read (default to true)
3151 * @return external_description
3152 * @throws moodle_exception
3155 public static function delete_message($messageid, $userid, $read = true) {
3158 // Check if private messaging between users is allowed.
3159 if (empty($CFG->messaging)) {
3160 throw new moodle_exception('disabled', 'message');
3163 // Warnings array, it can be empty at the end but is mandatory.
3164 $warnings = array();
3168 'messageid' => $messageid,
3169 'userid' => $userid,
3172 $params = self::validate_parameters(self::delete_message_parameters(), $params);
3174 // Validate context.
3175 $context = context_system::instance();
3176 self::validate_context($context);
3178 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3179 core_user::require_active_user($user);
3181 if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
3182 $status = \core_message\api::delete_message($user->id, $params['messageid']);
3184 throw new moodle_exception('You do not have permission to delete this message');
3188 'status' => $status,
3189 'warnings' => $warnings
3195 * Returns description of method result value
3197 * @return external_description
3200 public static function delete_message_returns() {
3201 return new external_single_structure(
3203 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
3204 'warnings' => new external_warnings()
3210 * Returns description of method parameters
3212 * @return external_function_parameters
3215 public static function message_processor_config_form_parameters() {
3216 return new external_function_parameters(
3218 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
3219 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
3220 'formvalues' => new external_multiple_structure(
3221 new external_single_structure(
3223 'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
3224 'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
3227 'Config form values',
3235 * Processes a message processor config form.
3237 * @param int $userid the user id
3238 * @param string $name the name of the processor
3239 * @param array $formvalues the form values
3240 * @return external_description
3241 * @throws moodle_exception
3244 public static function message_processor_config_form($userid, $name, $formvalues) {
3247 // Check if messaging is enabled.
3248 if (empty($CFG->messaging)) {
3249 throw new moodle_exception('disabled', 'message');
3252 $params = self::validate_parameters(
3253 self::message_processor_config_form_parameters(),
3255 'userid' => $userid,
3257 'formvalues' => $formvalues,
3261 $user = self::validate_preferences_permissions($params['userid']);
3263 $processor = get_message_processor($params['name']);
3265 $form = new stdClass();
3267 foreach ($params['formvalues'] as $formvalue) {
3268 // Curly braces to ensure interpretation is consistent between
3270 $form->{$formvalue['name']} = $formvalue['value'];
3273 $processor->process_form($form, $preferences);
3275 if (!empty($preferences)) {
3276 set_user_preferences($preferences, $params['userid']);
3281 * Returns description of method result value
3283 * @return external_description
3286 public static function message_processor_config_form_returns() {
3291 * Returns description of method parameters
3293 * @return external_function_parameters
3296 public static function get_message_processor_parameters() {
3297 return new external_function_parameters(
3299 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
3300 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
3306 * Get a message processor.
3308 * @param int $userid
3309 * @param string $name the name of the processor
3310 * @return external_description
3311 * @throws moodle_exception
3314 public static function get_message_processor($userid = 0, $name) {
3315 global $USER, $PAGE, $CFG;
3317 // Check if messaging is enabled.
3318 if (empty($CFG->messaging)) {
3319 throw new moodle_exception('disabled', 'message');
3322 $params = self::validate_parameters(
3323 self::get_message_processor_parameters(),
3325 'userid' => $userid,
3330 if (empty($params['userid'])) {
3331 $params['userid'] = $USER->id;
3334 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3335 core_user::require_active_user($user);
3336 self::validate_context(context_user::instance($params['userid']));
3338 $processor = get_message_processor($params['name']);
3340 $processoroutput = new \core_message\output\processor($processor, $user);
3341 $renderer = $PAGE->get_renderer('core_message');
3343 return $processoroutput->export_for_template($renderer);
3347 * Returns description of method result value
3349 * @return external_description
3352 public static function get_message_processor_returns() {
3353 return new external_function_parameters(
3355 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
3356 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
3362 * Check that the user has enough permission to retrieve message or notifications preferences.
3364 * @param int $userid the user id requesting the preferences
3365 * @return stdClass full user object
3366 * @throws moodle_exception
3369 protected static function validate_preferences_permissions($userid) {
3372 if (empty($userid)) {
3375 $user = core_user::get_user($userid, '*', MUST_EXIST);
3376 core_user::require_active_user($user);
3379 $systemcontext = context_system::instance();
3380 self::validate_context($systemcontext);
3382 // Check access control.
3383 if ($user->id == $USER->id) {
3384 // Editing own message profile.
3385 require_capability('moodle/user:editownmessageprofile', $systemcontext);
3387 // Teachers, parents, etc.
3388 $personalcontext = context_user::instance($user->id);
3389 require_capability('moodle/user:editmessageprofile', $personalcontext);
3395 * Returns a notification or message preference structure.
3397 * @return external_single_structure the structure
3400 protected static function get_preferences_structure() {
3401 return new external_single_structure(
3403 'userid' => new external_value(PARAM_INT, 'User id'),
3404 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3405 'processors' => new external_multiple_structure(
3406 new external_single_structure(
3408 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3409 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3410 'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3411 'contextid' => new external_value(PARAM_INT, 'Context id'),
3412 'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3415 'Config form values'
3417 'components' => new external_multiple_structure(
3418 new external_single_structure(
3420 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3421 'notifications' => new external_multiple_structure(