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 $capability = 'moodle/site:manageallmessaging';
208 if (($USER->id != $userid) && !has_capability($capability, $context)) {
209 throw new required_capability_exception($context, $capability, 'nopermissions', '');
212 $params = array('userids' => $userids, 'userid' => $userid);
213 $params = self::validate_parameters(self::create_contacts_parameters(), $params);
216 foreach ($params['userids'] as $id) {
217 if (!message_add_contact($id, 0, $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 $capability = 'moodle/site:manageallmessaging';
293 if (($USER->id != $userid) && !has_capability($capability, $context)) {
294 throw new required_capability_exception($context, $capability, 'nopermissions', '');
297 $params = array('userids' => $userids, 'userid' => $userid);
298 $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
300 foreach ($params['userids'] as $id) {
301 \core_message\api::remove_contact($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 $capability = 'moodle/site:manageallmessaging';
351 if (($USER->id != $userid) && !has_capability($capability, $context)) {
352 throw new required_capability_exception($context, $capability, 'nopermissions', '');
355 $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
356 $params = self::validate_parameters(self::block_user_parameters(), $params);
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 $capability = 'moodle/site:manageallmessaging';
407 if (($USER->id != $userid) && !has_capability($capability, $context)) {
408 throw new required_capability_exception($context, $capability, 'nopermissions', '');
411 $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
412 $params = self::validate_parameters(self::unblock_user_parameters(), $params);
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 $capability = 'moodle/site:manageallmessaging';
474 if (($USER->id != $userid) && !has_capability($capability, $context)) {
475 throw new required_capability_exception($context, $capability, 'nopermissions', '');
478 $params = array('userids' => $userids, 'userid' => $userid);
479 $params = self::validate_parameters(self::block_contacts_parameters(), $params);
482 foreach ($params['userids'] as $id) {
483 if (!message_block_contact($id, $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 $capability = 'moodle/site:manageallmessaging';
560 if (($USER->id != $userid) && !has_capability($capability, $context)) {
561 throw new required_capability_exception($context, $capability, 'nopermissions', '');
564 $params = array('userids' => $userids, 'userid' => $userid);
565 $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
567 foreach ($params['userids'] as $id) {
568 message_unblock_contact($id, $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 $capability = 'moodle/site:manageallmessaging';
630 if (($USER->id != $userid) && !has_capability($capability, $context)) {
631 throw new required_capability_exception($context, $capability, 'nopermissions', '');
634 $params = ['userid' => $userid];
635 $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
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);
711 $capability = 'moodle/site:manageallmessaging';
712 if (($USER->id != $userid) && !has_capability($capability, $context)) {
713 throw new required_capability_exception($context, $capability, 'nopermissions', '');
718 'conversationid' => $conversationid,
719 'includecontactrequests' => $includecontactrequests,
720 'limitfrom' => $limitfrom,
721 'limitnum' => $limitnum
723 self::validate_parameters(self::get_conversation_members_parameters(), $params);
725 return \core_message\api::get_conversation_members($userid, $conversationid, $includecontactrequests,
726 $limitfrom, $limitnum);
730 * Returns the get conversation members return description.
732 * @return external_description
734 public static function get_conversation_members_returns() {
735 return new external_multiple_structure(
736 self::get_conversation_member_structure(true)
741 * Creates a contact request parameters description.
743 * @return external_function_parameters
745 public static function create_contact_request_parameters() {
746 return new external_function_parameters(
748 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
749 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
755 * Creates a contact request.
757 * @param int $userid The id of the user who is creating the contact request
758 * @param int $requesteduserid The id of the user being requested
760 public static function create_contact_request(int $userid, int $requesteduserid) {
763 // Check if messaging is enabled.
764 if (empty($CFG->messaging)) {
765 throw new moodle_exception('disabled', 'message');
769 $context = context_system::instance();
770 self::validate_context($context);
772 $capability = 'moodle/site:manageallmessaging';
773 if (($USER->id != $userid) && !has_capability($capability, $context)) {
774 throw new required_capability_exception($context, $capability, 'nopermissions', '');
777 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
778 $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
780 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
783 'itemid' => $params['requesteduserid'],
784 'warningcode' => 'cannotcreatecontactrequest',
785 'message' => 'You are unable to create a contact request for this user'
790 if (!\core_message\api::does_contact_request_exist($params['userid'], $params['requesteduserid'])) {
791 \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
798 * Creates a contact request return description.
800 * @return external_description
802 public static function create_contact_request_returns() {
803 return new external_warnings();
807 * Confirm a contact request parameters description.
809 * @return external_function_parameters
811 public static function confirm_contact_request_parameters() {
812 return new external_function_parameters(
814 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
815 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
821 * Confirm a contact request.
823 * @param int $userid The id of the user who is creating the contact request
824 * @param int $requesteduserid The id of the user being requested
826 public static function confirm_contact_request(int $userid, int $requesteduserid) {
829 // Check if messaging is enabled.
830 if (empty($CFG->messaging)) {
831 throw new moodle_exception('disabled', 'message');
835 $context = context_system::instance();
836 self::validate_context($context);
838 $capability = 'moodle/site:manageallmessaging';
839 if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
840 throw new required_capability_exception($context, $capability, 'nopermissions', '');
843 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
844 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
846 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
852 * Confirm a contact request return description.
854 * @return external_description
856 public static function confirm_contact_request_returns() {
857 return new external_warnings();
861 * Declines a contact request parameters description.
863 * @return external_function_parameters
865 public static function decline_contact_request_parameters() {
866 return new external_function_parameters(
868 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
869 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
875 * Declines a contact request.
877 * @param int $userid The id of the user who is creating the contact request
878 * @param int $requesteduserid The id of the user being requested
880 public static function decline_contact_request(int $userid, int $requesteduserid) {
883 // Check if messaging is enabled.
884 if (empty($CFG->messaging)) {
885 throw new moodle_exception('disabled', 'message');
889 $context = context_system::instance();
890 self::validate_context($context);
892 $capability = 'moodle/site:manageallmessaging';
893 if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
894 throw new required_capability_exception($context, $capability, 'nopermissions', '');
897 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
898 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
900 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
906 * Declines a contact request return description.
908 * @return external_description
910 public static function decline_contact_request_returns() {
911 return new external_warnings();
915 * Return the structure of a message area contact.
917 * @return external_single_structure
920 private static function get_messagearea_contact_structure() {
921 return new external_single_structure(
923 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
924 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
925 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
926 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
927 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
928 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
929 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
930 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
931 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
932 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
933 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
934 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
935 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
936 VALUE_DEFAULT, null),
942 * Return the structure of a conversation.
944 * @return external_single_structure
947 private static function get_conversation_structure() {
948 return new external_single_structure(
950 'id' => new external_value(PARAM_INT, 'The conversation id'),
951 'name' => new external_value(PARAM_NOTAGS, 'The conversation name, if set', VALUE_DEFAULT, null),
952 'subname' => new external_value(PARAM_NOTAGS, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
953 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group)'),
954 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
955 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked conversation this conversation as a favourite'),
956 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
957 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
958 VALUE_DEFAULT, null),
959 'members' => new external_multiple_structure(
960 self::get_conversation_member_structure()
962 'messages' => new external_multiple_structure(
963 self::get_conversation_message_structure()
970 * Return the structure of a conversation member.
972 * @param bool $includecontactrequests Are we including contact requests?
973 * @return external_single_structure
976 private static function get_conversation_member_structure(bool $includecontactrequests = false) {
978 'id' => new external_value(PARAM_INT, 'The user id'),
979 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
980 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
981 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
982 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
983 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
984 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
985 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
988 if ($includecontactrequests) {
989 $result['contactrequests'] = new external_multiple_structure(
990 new external_single_structure(
992 'id' => new external_value(PARAM_INT, 'The id of the message'),
993 'userid' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
994 'requesteduserid' => new external_value(PARAM_RAW, 'The text of the message'),
995 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
997 ), 'The contact requests', VALUE_OPTIONAL
1001 return new external_single_structure(
1007 * Return the structure of a message area message.
1009 * @return external_single_structure
1012 private static function get_conversation_message_structure() {
1013 return new external_single_structure(
1015 'id' => new external_value(PARAM_INT, 'The id of the message'),
1016 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1017 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1018 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1024 * Return the structure of a message area message.
1026 * @return external_single_structure
1029 private static function get_messagearea_message_structure() {
1030 return new external_single_structure(
1032 'id' => new external_value(PARAM_INT, 'The id of the message'),
1033 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1034 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1035 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1036 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1037 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1038 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1039 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1040 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1041 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1047 * Get messagearea search users in course parameters.
1049 * @return external_function_parameters
1052 public static function data_for_messagearea_search_users_in_course_parameters() {
1053 return new external_function_parameters(
1055 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1056 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1057 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1058 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1059 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1065 * Get messagearea search users in course results.
1067 * @param int $userid The id of the user who is performing the search
1068 * @param int $courseid The id of the course
1069 * @param string $search The string being searched
1070 * @param int $limitfrom
1071 * @param int $limitnum
1073 * @throws moodle_exception
1076 public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1078 global $CFG, $PAGE, $USER;
1080 // Check if messaging is enabled.
1081 if (empty($CFG->messaging)) {
1082 throw new moodle_exception('disabled', 'message');
1085 $systemcontext = context_system::instance();
1088 'userid' => $userid,
1089 'courseid' => $courseid,
1090 'search' => $search,
1091 'limitfrom' => $limitfrom,
1092 'limitnum' => $limitnum
1094 self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1095 self::validate_context($systemcontext);
1097 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1098 throw new moodle_exception('You do not have permission to perform this action.');
1101 $users = \core_message\api::search_users_in_course($userid, $courseid, $search, $limitfrom, $limitnum);
1102 $results = new \core_message\output\messagearea\user_search_results($users);
1104 $renderer = $PAGE->get_renderer('core_message');
1105 return $results->export_for_template($renderer);
1109 * Get messagearea search users in course returns.
1111 * @return external_single_structure
1114 public static function data_for_messagearea_search_users_in_course_returns() {
1115 return new external_single_structure(
1117 'contacts' => new external_multiple_structure(
1118 self::get_messagearea_contact_structure()
1125 * Get messagearea search users parameters.
1127 * @return external_function_parameters
1130 public static function data_for_messagearea_search_users_parameters() {
1131 return new external_function_parameters(
1133 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1134 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1135 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1141 * Get messagearea search users results.
1143 * @param int $userid The id of the user who is performing the search
1144 * @param string $search The string being searched
1145 * @param int $limitnum
1147 * @throws moodle_exception
1150 public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1151 global $CFG, $PAGE, $USER;
1153 // Check if messaging is enabled.
1154 if (empty($CFG->messaging)) {
1155 throw new moodle_exception('disabled', 'message');
1158 $systemcontext = context_system::instance();
1161 'userid' => $userid,
1162 'search' => $search,
1163 'limitnum' => $limitnum
1165 self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1166 self::validate_context($systemcontext);
1168 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1169 throw new moodle_exception('You do not have permission to perform this action.');
1172 list($contacts, $courses, $noncontacts) = \core_message\api::search_users($userid, $search, $limitnum);
1173 $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1175 $renderer = $PAGE->get_renderer('core_message');
1176 return $search->export_for_template($renderer);
1180 * Get messagearea search users returns.
1182 * @return external_single_structure
1185 public static function data_for_messagearea_search_users_returns() {
1186 return new external_single_structure(
1188 'contacts' => new external_multiple_structure(
1189 self::get_messagearea_contact_structure()
1191 'courses' => new external_multiple_structure(
1192 new external_single_structure(
1194 'id' => new external_value(PARAM_INT, 'The course id'),
1195 'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1196 'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1200 'noncontacts' => new external_multiple_structure(
1201 self::get_messagearea_contact_structure()
1208 * Get messagearea search messages parameters.
1210 * @return external_function_parameters
1213 public static function data_for_messagearea_search_messages_parameters() {
1214 return new external_function_parameters(
1216 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1217 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1218 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1219 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1225 * Get messagearea search messages results.
1227 * @param int $userid The id of the user who is performing the search
1228 * @param string $search The string being searched
1229 * @param int $limitfrom
1230 * @param int $limitnum
1232 * @throws moodle_exception
1235 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1236 global $CFG, $PAGE, $USER;
1238 // Check if messaging is enabled.
1239 if (empty($CFG->messaging)) {
1240 throw new moodle_exception('disabled', 'message');
1243 $systemcontext = context_system::instance();
1246 'userid' => $userid,
1247 'search' => $search,
1248 'limitfrom' => $limitfrom,
1249 'limitnum' => $limitnum
1252 self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1253 self::validate_context($systemcontext);
1255 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1256 throw new moodle_exception('You do not have permission to perform this action.');
1259 $messages = \core_message\api::search_messages($userid, $search, $limitfrom, $limitnum);
1260 $results = new \core_message\output\messagearea\message_search_results($messages);
1262 $renderer = $PAGE->get_renderer('core_message');
1263 return $results->export_for_template($renderer);
1267 * Get messagearea search messages returns.
1269 * @return external_single_structure
1272 public static function data_for_messagearea_search_messages_returns() {
1273 return new external_single_structure(
1275 'contacts' => new external_multiple_structure(
1276 self::get_messagearea_contact_structure()
1283 * Get conversations parameters.
1285 * @return external_function_parameters
1288 public static function get_conversations_parameters() {
1289 return new external_function_parameters(
1291 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1292 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1293 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1294 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1295 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1296 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1297 VALUE_DEFAULT, null),
1304 * Get the list of conversations for the user.
1306 * @param int $userid The id of the user who is performing the search
1307 * @param int $limitfrom
1308 * @param int $limitnum
1309 * @param int|null $type
1310 * @param bool|null $favourites
1312 * @throws \moodle_exception if the messaging feature is disabled on the site.
1315 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null) {
1318 // All the standard BL checks.
1319 if (empty($CFG->messaging)) {
1320 throw new moodle_exception('disabled', 'message');
1324 'userid' => $userid,
1325 'limitfrom' => $limitfrom,
1326 'limitnum' => $limitnum,
1328 'favourites' => $favourites
1330 self::validate_parameters(self::get_conversations_parameters(), $params);
1332 $systemcontext = context_system::instance();
1333 self::validate_context($systemcontext);
1335 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1336 throw new moodle_exception('You do not have permission to perform this action.');
1339 $conversations = \core_message\api::get_conversations($userid, $limitfrom, $limitnum, $type, $favourites);
1340 return (object) ['conversations' => $conversations];
1344 * Get conversations returns.
1346 * @return external_single_structure
1349 public static function get_conversations_returns() {
1350 return new external_single_structure(
1352 'conversations' => new external_multiple_structure(
1353 self::get_conversation_structure()
1360 * The messagearea conversations parameters.
1362 * @deprecated since 3.6
1363 * @return external_function_parameters
1366 public static function data_for_messagearea_conversations_parameters() {
1367 return new external_function_parameters(
1369 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1370 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1371 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1377 * Get messagearea conversations.
1379 * NOTE FOR FINAL DEPRECATION:
1380 * When removing this method, please also consider removal of get_conversations_legacy_formatter()
1381 * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
1382 * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
1385 * @deprecated since 3.6
1386 * @param int $userid The id of the user who we are viewing conversations for
1387 * @param int $limitfrom
1388 * @param int $limitnum
1390 * @throws moodle_exception
1393 public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1394 global $CFG, $PAGE, $USER;
1396 // Check if messaging is enabled.
1397 if (empty($CFG->messaging)) {
1398 throw new moodle_exception('disabled', 'message');
1401 $systemcontext = context_system::instance();
1404 'userid' => $userid,
1405 'limitfrom' => $limitfrom,
1406 'limitnum' => $limitnum
1408 self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1409 self::validate_context($systemcontext);
1411 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1412 throw new moodle_exception('You do not have permission to perform this action.');
1415 $conversations = \core_message\api::get_conversations($userid, $limitfrom, $limitnum);
1417 // Format the conversations in the legacy style, as the get_conversations method has since been changed.
1418 $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
1420 $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1422 $renderer = $PAGE->get_renderer('core_message');
1423 return $conversations->export_for_template($renderer);
1427 * The messagearea conversations return structure.
1429 * @deprecated since 3.6
1430 * @return external_single_structure
1433 public static function data_for_messagearea_conversations_returns() {
1434 return new external_single_structure(
1436 'contacts' => new external_multiple_structure(
1437 self::get_messagearea_contact_structure()
1444 * Marking the method as deprecated.
1448 public static function data_for_messagearea_conversations_is_deprecated() {
1453 * The messagearea contacts return parameters.
1455 * @return external_function_parameters
1458 public static function data_for_messagearea_contacts_parameters() {
1459 return self::data_for_messagearea_conversations_parameters();
1463 * Get messagearea contacts parameters.
1465 * @param int $userid The id of the user who we are viewing conversations for
1466 * @param int $limitfrom
1467 * @param int $limitnum
1469 * @throws moodle_exception
1472 public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1473 global $CFG, $PAGE, $USER;
1475 // Check if messaging is enabled.
1476 if (empty($CFG->messaging)) {
1477 throw new moodle_exception('disabled', 'message');
1480 $systemcontext = context_system::instance();
1483 'userid' => $userid,
1484 'limitfrom' => $limitfrom,
1485 'limitnum' => $limitnum
1487 self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1488 self::validate_context($systemcontext);
1490 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1491 throw new moodle_exception('You do not have permission to perform this action.');
1494 $contacts = \core_message\api::get_contacts($userid, $limitfrom, $limitnum);
1495 $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1497 $renderer = $PAGE->get_renderer('core_message');
1498 return $contacts->export_for_template($renderer);
1502 * The messagearea contacts return structure.
1504 * @return external_single_structure
1507 public static function data_for_messagearea_contacts_returns() {
1508 return self::data_for_messagearea_conversations_returns();
1512 * The messagearea messages parameters.
1514 * @return external_function_parameters
1517 public static function data_for_messagearea_messages_parameters() {
1518 return new external_function_parameters(
1520 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1521 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1522 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1523 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1524 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1525 'timefrom' => new external_value(PARAM_INT,
1526 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1532 * Get messagearea messages.
1534 * @param int $currentuserid The current user's id
1535 * @param int $otheruserid The other user's id
1536 * @param int $limitfrom
1537 * @param int $limitnum
1538 * @param boolean $newest
1540 * @throws moodle_exception
1543 public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1544 $newest = false, $timefrom = 0) {
1545 global $CFG, $PAGE, $USER;
1547 // Check if messaging is enabled.
1548 if (empty($CFG->messaging)) {
1549 throw new moodle_exception('disabled', 'message');
1552 $systemcontext = context_system::instance();
1555 'currentuserid' => $currentuserid,
1556 'otheruserid' => $otheruserid,
1557 'limitfrom' => $limitfrom,
1558 'limitnum' => $limitnum,
1559 'newest' => $newest,
1560 'timefrom' => $timefrom,
1562 self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1563 self::validate_context($systemcontext);
1565 if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1566 throw new moodle_exception('You do not have permission to perform this action.');
1570 $sort = 'timecreated DESC';
1572 $sort = 'timecreated ASC';
1575 // We need to enforce a one second delay on messages to avoid race conditions of current
1576 // messages still being sent.
1578 // There is a chance that we could request messages before the current time's
1579 // second has elapsed and while other messages are being sent in that same second. In which
1580 // case those messages will be lost.
1582 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1583 if (!empty($timefrom)) {
1584 $timeto = time() - 1;
1589 // No requesting messages from the current time, as stated above.
1590 if ($timefrom == time()) {
1593 $messages = \core_message\api::get_messages($currentuserid, $otheruserid, $limitfrom,
1594 $limitnum, $sort, $timefrom, $timeto);
1597 $messages = new \core_message\output\messagearea\messages($currentuserid, $otheruserid, $messages);
1599 $renderer = $PAGE->get_renderer('core_message');
1600 return $messages->export_for_template($renderer);
1604 * The messagearea messages return structure.
1606 * @return external_single_structure
1609 public static function data_for_messagearea_messages_returns() {
1610 return new external_single_structure(
1612 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1613 the messages on behalf of?'),
1614 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1615 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1616 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1617 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1618 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1619 'messages' => new external_multiple_structure(
1620 self::get_messagearea_message_structure()
1622 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1628 * The conversation messages parameters.
1630 * @return external_function_parameters
1633 public static function get_conversation_messages_parameters() {
1634 return new external_function_parameters(
1636 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1637 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1638 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1639 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1640 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1641 'timefrom' => new external_value(PARAM_INT,
1642 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1648 * Get conversation messages.
1650 * @param int $currentuserid The current user's id.
1651 * @param int $convid The conversation id.
1652 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1653 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1654 * @param bool $newest True for getting first newest messages, false otherwise.
1655 * @param int $timefrom The time from the conversation messages to get.
1656 * @return stdClass The messages and members who have sent some of these messages.
1657 * @throws moodle_exception
1660 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1661 bool $newest = false, int $timefrom = 0) {
1662 global $CFG, $PAGE, $USER;
1664 // Check if messaging is enabled.
1665 if (empty($CFG->messaging)) {
1666 throw new moodle_exception('disabled', 'message');
1669 $systemcontext = context_system::instance();
1672 'currentuserid' => $currentuserid,
1673 'convid' => $convid,
1674 'limitfrom' => $limitfrom,
1675 'limitnum' => $limitnum,
1676 'newest' => $newest,
1677 'timefrom' => $timefrom,
1679 self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1680 self::validate_context($systemcontext);
1682 if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1683 throw new moodle_exception('You do not have permission to perform this action.');
1686 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1688 // We need to enforce a one second delay on messages to avoid race conditions of current
1689 // messages still being sent.
1691 // There is a chance that we could request messages before the current time's
1692 // second has elapsed and while other messages are being sent in that same second. In which
1693 // case those messages will be lost.
1695 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1696 $timeto = empty($timefrom) ? 0 : time() - 1;
1698 // No requesting messages from the current time, as stated above.
1699 if ($timefrom == time()) {
1702 $messages = \core_message\api::get_conversation_messages($currentuserid, $convid, $limitfrom,
1703 $limitnum, $sort, $timefrom, $timeto);
1710 * The messagearea messages return structure.
1712 * @return external_single_structure
1715 public static function get_conversation_messages_returns() {
1716 return new external_single_structure(
1718 'id' => new external_value(PARAM_INT, 'The conversation id'),
1719 'members' => new external_multiple_structure(
1720 self::get_conversation_member_structure()
1722 'messages' => new external_multiple_structure(
1723 self::get_conversation_message_structure()
1730 * The get most recent message return parameters.
1732 * @return external_function_parameters
1735 public static function data_for_messagearea_get_most_recent_message_parameters() {
1736 return new external_function_parameters(
1738 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1739 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1745 * Get the most recent message in a conversation.
1747 * @param int $currentuserid The current user's id
1748 * @param int $otheruserid The other user's id
1750 * @throws moodle_exception
1753 public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
1754 global $CFG, $PAGE, $USER;
1756 // Check if messaging is enabled.
1757 if (empty($CFG->messaging)) {
1758 throw new moodle_exception('disabled', 'message');
1761 $systemcontext = context_system::instance();
1764 'currentuserid' => $currentuserid,
1765 'otheruserid' => $otheruserid
1767 self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
1768 self::validate_context($systemcontext);
1770 if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1771 throw new moodle_exception('You do not have permission to perform this action.');
1774 $message = \core_message\api::get_most_recent_message($currentuserid, $otheruserid);
1775 $message = new \core_message\output\messagearea\message($message);
1777 $renderer = $PAGE->get_renderer('core_message');
1778 return $message->export_for_template($renderer);
1782 * The get most recent message return structure.
1784 * @return external_single_structure
1787 public static function data_for_messagearea_get_most_recent_message_returns() {
1788 return self::get_messagearea_message_structure();
1792 * The get profile parameters.
1794 * @return external_function_parameters
1797 public static function data_for_messagearea_get_profile_parameters() {
1798 return new external_function_parameters(
1800 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1801 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
1807 * Get the profile information for a contact.
1809 * @param int $currentuserid The current user's id
1810 * @param int $otheruserid The id of the user whose profile we are viewing
1812 * @throws moodle_exception
1815 public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
1816 global $CFG, $PAGE, $USER;
1818 // Check if messaging is enabled.
1819 if (empty($CFG->messaging)) {
1820 throw new moodle_exception('disabled', 'message');
1823 $systemcontext = context_system::instance();
1826 'currentuserid' => $currentuserid,
1827 'otheruserid' => $otheruserid
1829 self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
1830 self::validate_context($systemcontext);
1832 if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1833 throw new moodle_exception('You do not have permission to perform this action.');
1836 $profile = \core_message\api::get_profile($currentuserid, $otheruserid);
1837 $profile = new \core_message\output\messagearea\profile($profile);
1839 $renderer = $PAGE->get_renderer('core_message');
1840 return $profile->export_for_template($renderer);
1844 * The get profile return structure.
1846 * @return external_single_structure
1849 public static function data_for_messagearea_get_profile_returns() {
1850 return new external_single_structure(
1852 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
1853 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
1854 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
1855 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
1856 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1857 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1858 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1859 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1860 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1861 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
1862 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
1868 * Get contacts parameters description.
1870 * @return external_function_parameters
1873 public static function get_contacts_parameters() {
1874 return new external_function_parameters(array());
1880 * @return external_description
1883 public static function get_contacts() {
1884 global $CFG, $PAGE, $USER;
1886 // Check if messaging is enabled.
1887 if (empty($CFG->messaging)) {
1888 throw new moodle_exception('disabled', 'message');
1891 require_once($CFG->dirroot . '/user/lib.php');
1893 $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
1894 $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
1895 foreach ($contacts as $contact) {
1898 if (\core_message\helper::is_online($contact->lastaccess)) {
1902 $newcontact = array(
1903 'id' => $contact->id,
1904 'fullname' => fullname($contact),
1905 'unread' => $contact->messagecount
1908 $userpicture = new user_picture($contact);
1909 $userpicture->size = 1; // Size f1.
1910 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1911 $userpicture->size = 0; // Size f2.
1912 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1914 $allcontacts[$mode][$contact->id] = $newcontact;
1917 $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
1918 foreach ($strangers as $contact) {
1919 $newcontact = array(
1920 'id' => $contact->id,
1921 'fullname' => fullname($contact),
1922 'unread' => $contact->messagecount
1925 $userpicture = new user_picture($contact);
1926 $userpicture->size = 1; // Size f1.
1927 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1928 $userpicture->size = 0; // Size f2.
1929 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1931 $allcontacts['strangers'][$contact->id] = $newcontact;
1934 // Add noreply user and support user to the list, if they don't exist.
1935 $supportuser = core_user::get_support_user();
1936 if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
1937 $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
1938 if ($supportuser->messagecount > 0) {
1939 $supportuser->fullname = fullname($supportuser);
1940 $supportuser->unread = $supportuser->messagecount;
1941 $allcontacts['strangers'][$supportuser->id] = $supportuser;
1945 $noreplyuser = core_user::get_noreply_user();
1946 if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
1947 $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
1948 if ($noreplyuser->messagecount > 0) {
1949 $noreplyuser->fullname = fullname($noreplyuser);
1950 $noreplyuser->unread = $noreplyuser->messagecount;
1951 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
1955 return $allcontacts;
1959 * Get contacts return description.
1961 * @return external_description
1964 public static function get_contacts_returns() {
1965 return new external_single_structure(
1967 'online' => new external_multiple_structure(
1968 new external_single_structure(
1970 'id' => new external_value(PARAM_INT, 'User ID'),
1971 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1972 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1973 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1974 'unread' => new external_value(PARAM_INT, 'Unread message count')
1977 'List of online contacts'
1979 'offline' => new external_multiple_structure(
1980 new external_single_structure(
1982 'id' => new external_value(PARAM_INT, 'User ID'),
1983 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1984 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1985 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1986 'unread' => new external_value(PARAM_INT, 'Unread message count')
1989 'List of offline contacts'
1991 'strangers' => new external_multiple_structure(
1992 new external_single_structure(
1994 'id' => new external_value(PARAM_INT, 'User ID'),
1995 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1996 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1997 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1998 'unread' => new external_value(PARAM_INT, 'Unread message count')
2001 'List of users that are not in the user\'s contact list but have sent a message'
2008 * Search contacts parameters description.
2010 * @return external_function_parameters
2013 public static function search_contacts_parameters() {
2014 return new external_function_parameters(
2016 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2017 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2018 VALUE_DEFAULT, false)
2026 * @param string $searchtext query string.
2027 * @param bool $onlymycourses limit the search to the user's courses only.
2028 * @return external_description
2031 public static function search_contacts($searchtext, $onlymycourses = false) {
2032 global $CFG, $USER, $PAGE;
2033 require_once($CFG->dirroot . '/user/lib.php');
2035 // Check if messaging is enabled.
2036 if (empty($CFG->messaging)) {
2037 throw new moodle_exception('disabled', 'message');
2040 require_once($CFG->libdir . '/enrollib.php');
2042 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2043 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2045 // Extra validation, we do not allow empty queries.
2046 if ($params['searchtext'] === '') {
2047 throw new moodle_exception('querystringcannotbeempty');
2050 $courseids = array();
2051 if ($params['onlymycourses']) {
2052 $mycourses = enrol_get_my_courses(array('id'));
2053 foreach ($mycourses as $mycourse) {
2054 $courseids[] = $mycourse->id;
2057 $courseids[] = SITEID;
2060 // Retrieving the users matching the query.
2061 $users = message_search_users($courseids, $params['searchtext']);
2063 foreach ($users as $user) {
2064 $results[$user->id] = $user;
2067 // Reorganising information.
2068 foreach ($results as &$user) {
2071 'fullname' => fullname($user)
2074 // Avoid undefined property notice as phone not specified.
2075 $user->phone1 = null;
2076 $user->phone2 = null;
2078 $userpicture = new user_picture($user);
2079 $userpicture->size = 1; // Size f1.
2080 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2081 $userpicture->size = 0; // Size f2.
2082 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2091 * Search contacts return description.
2093 * @return external_description
2096 public static function search_contacts_returns() {
2097 return new external_multiple_structure(
2098 new external_single_structure(
2100 'id' => new external_value(PARAM_INT, 'User ID'),
2101 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2102 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2103 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
2111 * Get messages parameters description.
2113 * @return external_function_parameters
2116 public static function get_messages_parameters() {
2117 return new external_function_parameters(
2119 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2120 'useridfrom' => new external_value(
2121 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2123 'type' => new external_value(
2124 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2125 VALUE_DEFAULT, 'both'),
2126 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2127 'newestfirst' => new external_value(
2128 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2129 VALUE_DEFAULT, true),
2130 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2131 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2137 * Get messages function implementation.
2140 * @throws invalid_parameter_exception
2141 * @throws moodle_exception
2142 * @param int $useridto the user id who received the message
2143 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2144 * @param string $type type of message to return, expected values: notifications, conversations and both
2145 * @param bool $read true for retreiving read messages, false for unread
2146 * @param bool $newestfirst true for ordering by newest first, false for oldest first
2147 * @param int $limitfrom limit from
2148 * @param int $limitnum limit num
2149 * @return external_description
2151 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2152 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2155 $warnings = array();
2158 'useridto' => $useridto,
2159 'useridfrom' => $useridfrom,
2162 'newestfirst' => $newestfirst,
2163 'limitfrom' => $limitfrom,
2164 'limitnum' => $limitnum
2167 $params = self::validate_parameters(self::get_messages_parameters(), $params);
2169 $context = context_system::instance();
2170 self::validate_context($context);
2172 $useridto = $params['useridto'];
2173 $useridfrom = $params['useridfrom'];
2174 $type = $params['type'];
2175 $read = $params['read'];
2176 $newestfirst = $params['newestfirst'];
2177 $limitfrom = $params['limitfrom'];
2178 $limitnum = $params['limitnum'];
2180 $allowedvalues = array('notifications', 'conversations', 'both');
2181 if (!in_array($type, $allowedvalues)) {
2182 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2183 'allowed values are: ' . implode(',', $allowedvalues));
2186 // Check if private messaging between users is allowed.
2187 if (empty($CFG->messaging)) {
2188 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2189 if ($type == "conversations") {
2190 throw new moodle_exception('disabled', 'message');
2192 if ($type == "both") {
2194 $warning['item'] = 'message';
2195 $warning['itemid'] = $USER->id;
2196 $warning['warningcode'] = '1';
2197 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2198 Only notifications will be returned';
2199 $warnings[] = $warning;
2203 if (!empty($useridto)) {
2204 if (core_user::is_real_user($useridto)) {
2205 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2207 throw new moodle_exception('invaliduser');
2211 if (!empty($useridfrom)) {
2212 // We use get_user here because the from user can be the noreply or support user.
2213 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2216 // Check if the current user is the sender/receiver or just a privileged user.
2217 if ($useridto != $USER->id and $useridfrom != $USER->id and
2218 !has_capability('moodle/site:readallmessages', $context)) {
2219 throw new moodle_exception('accessdenied', 'admin');
2222 // Which type of messages to retrieve.
2223 $notifications = -1;
2224 if ($type != 'both') {
2225 $notifications = ($type == 'notifications') ? 1 : 0;
2228 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2229 $sort = "mr.timecreated $orderdirection";
2231 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2232 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2234 // In some cases, we don't need to get the to/from user objects from the sql query.
2235 $userfromfullname = '';
2236 $usertofullname = '';
2238 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2239 if (!empty($useridto)) {
2240 $usertofullname = fullname($userto, $canviewfullname);
2241 // The user from may or may not be filled.
2242 if (!empty($useridfrom)) {
2243 $userfromfullname = fullname($userfrom, $canviewfullname);
2246 // If the useridto field is empty, the useridfrom must be filled.
2247 $userfromfullname = fullname($userfrom, $canviewfullname);
2249 foreach ($messages as $mid => $message) {
2251 // Do not return deleted messages.
2252 if (!$message->notification) {
2253 if (($useridto == $USER->id and $message->timeusertodeleted) or
2254 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2255 unset($messages[$mid]);
2260 // We need to get the user from the query.
2261 if (empty($userfromfullname)) {
2262 // Check for non-reply and support users.
2263 if (core_user::is_real_user($message->useridfrom)) {
2264 $user = new stdClass();
2265 $user = username_load_fields_from_object($user, $message, 'userfrom');
2266 $message->userfromfullname = fullname($user, $canviewfullname);
2268 $user = core_user::get_user($message->useridfrom);
2269 $message->userfromfullname = fullname($user, $canviewfullname);
2272 $message->userfromfullname = $userfromfullname;
2275 // We need to get the user from the query.
2276 if (empty($usertofullname)) {
2277 $user = new stdClass();
2278 $user = username_load_fields_from_object($user, $message, 'userto');
2279 $message->usertofullname = fullname($user, $canviewfullname);
2281 $message->usertofullname = $usertofullname;
2284 $message->text = message_format_message_text($message);
2285 $messages[$mid] = (array) $message;
2290 'messages' => $messages,
2291 'warnings' => $warnings
2298 * Get messages return description.
2300 * @return external_single_structure
2303 public static function get_messages_returns() {
2304 return new external_single_structure(
2306 'messages' => new external_multiple_structure(
2307 new external_single_structure(
2309 'id' => new external_value(PARAM_INT, 'Message id'),
2310 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2311 'useridto' => new external_value(PARAM_INT, 'User to id'),
2312 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2313 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2314 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2315 'fullmessageformat' => new external_format_value('fullmessage'),
2316 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2317 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2318 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2319 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2320 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2321 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2322 'timeread' => new external_value(PARAM_INT, 'Time read'),
2323 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2324 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2328 'warnings' => new external_warnings()
2334 * Mark all notifications as read parameters description.
2336 * @return external_function_parameters
2339 public static function mark_all_notifications_as_read_parameters() {
2340 return new external_function_parameters(
2342 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2343 'useridfrom' => new external_value(
2344 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2351 * Mark all notifications as read function.
2354 * @throws invalid_parameter_exception
2355 * @throws moodle_exception
2356 * @param int $useridto the user id who received the message
2357 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2358 * @return external_description
2360 public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2363 $params = self::validate_parameters(
2364 self::mark_all_notifications_as_read_parameters(),
2366 'useridto' => $useridto,
2367 'useridfrom' => $useridfrom,
2371 $context = context_system::instance();
2372 self::validate_context($context);
2374 $useridto = $params['useridto'];
2375 $useridfrom = $params['useridfrom'];
2377 if (!empty($useridto)) {
2378 if (core_user::is_real_user($useridto)) {
2379 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2381 throw new moodle_exception('invaliduser');
2385 if (!empty($useridfrom)) {
2386 // We use get_user here because the from user can be the noreply or support user.
2387 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2390 // Check if the current user is the sender/receiver or just a privileged user.
2391 if ($useridto != $USER->id and $useridfrom != $USER->id and
2392 // The deleteanymessage cap seems more reasonable here than readallmessages.
2393 !has_capability('moodle/site:deleteanymessage', $context)) {
2394 throw new moodle_exception('accessdenied', 'admin');
2397 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2403 * Mark all notifications as read return description.
2405 * @return external_single_structure
2408 public static function mark_all_notifications_as_read_returns() {
2409 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2413 * Get unread conversations count parameters description.
2415 * @return external_function_parameters
2418 public static function get_unread_conversations_count_parameters() {
2419 return new external_function_parameters(
2421 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2427 * Get unread messages count function.
2430 * @throws invalid_parameter_exception
2431 * @throws moodle_exception
2432 * @param int $useridto the user id who received the message
2433 * @return external_description
2435 public static function get_unread_conversations_count($useridto) {
2438 // Check if messaging is enabled.
2439 if (empty($CFG->messaging)) {
2440 throw new moodle_exception('disabled', 'message');
2443 $params = self::validate_parameters(
2444 self::get_unread_conversations_count_parameters(),
2445 array('useridto' => $useridto)
2448 $context = context_system::instance();
2449 self::validate_context($context);
2451 $useridto = $params['useridto'];
2453 if (!empty($useridto)) {
2454 if (core_user::is_real_user($useridto)) {
2455 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2457 throw new moodle_exception('invaliduser');
2460 $useridto = $USER->id;
2463 // Check if the current user is the receiver or just a privileged user.
2464 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2465 throw new moodle_exception('accessdenied', 'admin');
2468 return \core_message\api::count_unread_conversations($userto);
2472 * Get unread conversations count return description.
2474 * @return external_single_structure
2477 public static function get_unread_conversations_count_returns() {
2478 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2482 * Get blocked users parameters description.
2484 * @return external_function_parameters
2487 public static function get_blocked_users_parameters() {
2488 return new external_function_parameters(
2490 'userid' => new external_value(PARAM_INT,
2491 'the user whose blocked users we want to retrieve',
2498 * Retrieve a list of users blocked
2500 * @param int $userid the user whose blocked users we want to retrieve
2501 * @return external_description
2504 public static function get_blocked_users($userid) {
2505 global $CFG, $USER, $PAGE;
2507 // Warnings array, it can be empty at the end but is mandatory.
2508 $warnings = array();
2514 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2515 $userid = $params['userid'];
2517 // Validate context.
2518 $context = context_system::instance();
2519 self::validate_context($context);
2521 // Check if private messaging between users is allowed.
2522 if (empty($CFG->messaging)) {
2523 throw new moodle_exception('disabled', 'message');
2526 $user = core_user::get_user($userid, '*', MUST_EXIST);
2527 core_user::require_active_user($user);
2529 // Check if we have permissions for retrieve the information.
2530 $capability = 'moodle/site:manageallmessaging';
2531 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2532 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2535 // Now, we can get safely all the blocked users.
2536 $users = \core_message\api::get_blocked_users($user->id);
2538 $blockedusers = array();
2539 foreach ($users as $user) {
2542 'fullname' => fullname($user),
2545 $userpicture = new user_picture($user);
2546 $userpicture->size = 1; // Size f1.
2547 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2549 $blockedusers[] = $newuser;
2553 'users' => $blockedusers,
2554 'warnings' => $warnings
2560 * Get blocked users return description.
2562 * @return external_single_structure
2565 public static function get_blocked_users_returns() {
2566 return new external_single_structure(
2568 'users' => new external_multiple_structure(
2569 new external_single_structure(
2571 'id' => new external_value(PARAM_INT, 'User ID'),
2572 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2573 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2576 'List of blocked users'
2578 'warnings' => new external_warnings()
2584 * Returns description of method parameters
2586 * @return external_function_parameters
2589 public static function mark_message_read_parameters() {
2590 return new external_function_parameters(
2592 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2593 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2600 * Mark a single message as read, trigger message_viewed event
2602 * @param int $messageid id of the message (in the message table)
2603 * @param int $timeread timestamp for when the message should be marked read
2604 * @return external_description
2605 * @throws invalid_parameter_exception
2606 * @throws moodle_exception
2609 public static function mark_message_read($messageid, $timeread) {
2610 global $CFG, $DB, $USER;
2612 // Check if private messaging between users is allowed.
2613 if (empty($CFG->messaging)) {
2614 throw new moodle_exception('disabled', 'message');
2617 // Warnings array, it can be empty at the end but is mandatory.
2618 $warnings = array();
2622 'messageid' => $messageid,
2623 'timeread' => $timeread
2625 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2627 if (empty($params['timeread'])) {
2630 $timeread = $params['timeread'];
2633 // Validate context.
2634 $context = context_system::instance();
2635 self::validate_context($context);
2637 $sql = "SELECT m.*, mcm.userid as useridto
2639 INNER JOIN {message_conversations} mc
2640 ON m.conversationid = mc.id
2641 INNER JOIN {message_conversation_members} mcm
2642 ON mcm.conversationid = mc.id
2643 LEFT JOIN {message_user_actions} mua
2644 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2645 WHERE mua.id is NULL
2646 AND mcm.userid != m.useridfrom
2648 $messageparams = [];
2649 $messageparams[] = $USER->id;
2650 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2651 $messageparams[] = $params['messageid'];
2652 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2654 if ($message->useridto != $USER->id) {
2655 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2658 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2661 'messageid' => $message->id,
2662 'warnings' => $warnings
2668 * Returns description of method result value
2670 * @return external_description
2673 public static function mark_message_read_returns() {
2674 return new external_single_structure(
2676 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2677 'warnings' => new external_warnings()
2683 * Returns description of method parameters
2685 * @return external_function_parameters
2687 public static function mark_notification_read_parameters() {
2688 return new external_function_parameters(
2690 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2691 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2698 * Mark a single notification as read.
2700 * This will trigger a 'notification_viewed' event.
2702 * @param int $notificationid id of the notification
2703 * @param int $timeread timestamp for when the notification should be marked read
2704 * @return external_description
2705 * @throws invalid_parameter_exception
2706 * @throws moodle_exception
2708 public static function mark_notification_read($notificationid, $timeread) {
2709 global $CFG, $DB, $USER;
2711 // Check if private messaging between users is allowed.
2712 if (empty($CFG->messaging)) {
2713 throw new moodle_exception('disabled', 'message');
2716 // Warnings array, it can be empty at the end but is mandatory.
2717 $warnings = array();
2721 'notificationid' => $notificationid,
2722 'timeread' => $timeread
2724 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2726 if (empty($params['timeread'])) {
2729 $timeread = $params['timeread'];
2732 // Validate context.
2733 $context = context_system::instance();
2734 self::validate_context($context);
2736 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2738 if ($notification->useridto != $USER->id) {
2739 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2740 'notification as read');
2743 \core_message\api::mark_notification_as_read($notification, $timeread);
2746 'notificationid' => $notification->id,
2747 'warnings' => $warnings
2754 * Returns description of method result value
2756 * @return external_description
2758 public static function mark_notification_read_returns() {
2759 return new external_single_structure(
2761 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2762 'warnings' => new external_warnings()
2768 * Mark all messages as read parameters description.
2770 * @deprecated since 3.6
2771 * @return external_function_parameters
2774 public static function mark_all_messages_as_read_parameters() {
2775 return new external_function_parameters(
2777 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2778 'useridfrom' => new external_value(
2779 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2786 * Mark all messages as read function.
2788 * @deprecated since 3.6
2789 * @throws invalid_parameter_exception
2790 * @throws moodle_exception
2791 * @param int $useridto the user id who received the message
2792 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2793 * @return external_description
2796 public static function mark_all_messages_as_read($useridto, $useridfrom) {
2799 // Check if messaging is enabled.
2800 if (empty($CFG->messaging)) {
2801 throw new moodle_exception('disabled', 'message');
2804 $params = self::validate_parameters(
2805 self::mark_all_messages_as_read_parameters(),
2807 'useridto' => $useridto,
2808 'useridfrom' => $useridfrom,
2812 $context = context_system::instance();
2813 self::validate_context($context);
2815 $useridto = $params['useridto'];
2816 $useridfrom = $params['useridfrom'];
2818 if (!empty($useridto)) {
2819 if (core_user::is_real_user($useridto)) {
2820 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2822 throw new moodle_exception('invaliduser');
2826 if (!empty($useridfrom)) {
2827 // We use get_user here because the from user can be the noreply or support user.
2828 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2831 // Check if the current user is the sender/receiver or just a privileged user.
2832 if ($useridto != $USER->id and $useridfrom != $USER->id and
2833 // The deleteanymessage cap seems more reasonable here than readallmessages.
2834 !has_capability('moodle/site:deleteanymessage', $context)) {
2835 throw new moodle_exception('accessdenied', 'admin');
2839 if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
2840 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
2843 \core_message\api::mark_all_messages_as_read($useridto);
2850 * Mark all messages as read return description.
2852 * @deprecated since 3.6
2853 * @return external_single_structure
2856 public static function mark_all_messages_as_read_returns() {
2857 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2861 * Marking the method as deprecated.
2865 public static function mark_all_messages_as_read_is_deprecated() {
2870 * Mark all conversation messages as read parameters description.
2872 * @return external_function_parameters
2875 public static function mark_all_conversation_messages_as_read_parameters() {
2876 return new external_function_parameters(
2878 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2880 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2886 * Mark all conversation messages as read function.
2888 * @param int $userid The user id of who we want to delete the conversation for
2889 * @param int $conversationid The id of the conversations
2892 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2895 // Check if messaging is enabled.
2896 if (empty($CFG->messaging)) {
2897 throw new moodle_exception('disabled', 'message');
2901 'userid' => $userid,
2902 'conversationid' => $conversationid,
2904 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2906 $context = context_system::instance();
2907 self::validate_context($context);
2909 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2910 core_user::require_active_user($user);
2912 if (\core_message\api::can_mark_all_messages_as_read($userid, $conversationid)) {
2913 \core_message\api::mark_all_messages_as_read($userid, $conversationid);
2915 throw new moodle_exception('accessdenied', 'admin');
2920 * Mark all conversation messages as read return description.
2922 * @return external_warnings
2925 public static function mark_all_conversation_messages_as_read_returns() {
2926 return new external_warnings();
2930 * Returns description of method parameters.
2932 * @deprecated since 3.6
2933 * @return external_function_parameters
2936 public static function delete_conversation_parameters() {
2937 return new external_function_parameters(
2939 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2940 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
2946 * Deletes a conversation.
2948 * @deprecated since 3.6
2949 * @param int $userid The user id of who we want to delete the conversation for
2950 * @param int $otheruserid The user id of the other user in the conversation
2952 * @throws moodle_exception
2955 public static function delete_conversation($userid, $otheruserid) {
2958 // Check if private messaging between users is allowed.
2959 if (empty($CFG->messaging)) {
2960 throw new moodle_exception('disabled', 'message');
2963 // Warnings array, it can be empty at the end but is mandatory.
2964 $warnings = array();
2968 'userid' => $userid,
2969 'otheruserid' => $otheruserid,
2971 $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
2973 // Validate context.
2974 $context = context_system::instance();
2975 self::validate_context($context);
2977 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2978 core_user::require_active_user($user);
2980 if (!$conversationid = \core_message\api::get_conversation_between_users([$userid, $otheruserid])) {
2984 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2985 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2988 throw new moodle_exception('You do not have permission to delete messages');
2992 'status' => $status,
2993 'warnings' => $warnings
3000 * Returns description of method result value.
3002 * @deprecated since 3.6
3003 * @return external_description
3006 public static function delete_conversation_returns() {
3007 return new external_single_structure(
3009 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
3010 'warnings' => new external_warnings()
3016 * Marking the method as deprecated.
3020 public static function delete_conversation_is_deprecated() {
3025 * Returns description of method parameters.
3027 * @return external_function_parameters
3030 public static function delete_conversations_by_id_parameters() {
3031 return new external_function_parameters(
3033 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3034 'conversationids' => new external_multiple_structure(
3035 new external_value(PARAM_INT, 'The id of the conversation'),
3036 'List of conversation IDs'
3043 * Deletes a conversation.
3045 * @param int $userid The user id of who we want to delete the conversation for
3046 * @param int[] $conversationids The ids of the conversations
3048 * @throws moodle_exception
3051 public static function delete_conversations_by_id($userid, array $conversationids) {
3054 // Check if private messaging between users is allowed.
3055 if (empty($CFG->messaging)) {
3056 throw new moodle_exception('disabled', 'message');
3061 'userid' => $userid,
3062 'conversationids' => $conversationids,
3064 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
3066 // Validate context.
3067 $context = context_system::instance();
3068 self::validate_context($context);
3070 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3071 core_user::require_active_user($user);
3073 foreach ($conversationids as $conversationid) {
3074 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3075 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3077 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
3085 * Returns description of method result value.
3087 * @return external_description
3090 public static function delete_conversations_by_id_returns() {
3091 return new external_warnings();
3095 * Returns description of method parameters
3097 * @return external_function_parameters
3100 public static function delete_message_parameters() {
3101 return new external_function_parameters(
3103 'messageid' => new external_value(PARAM_INT, 'The message id'),
3104 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
3105 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
3113 * @param int $messageid the message id
3114 * @param int $userid the user id of who we want to delete the message for
3115 * @param bool $read if is a message read (default to true)
3116 * @return external_description
3117 * @throws moodle_exception
3120 public static function delete_message($messageid, $userid, $read = true) {
3123 // Check if private messaging between users is allowed.
3124 if (empty($CFG->messaging)) {
3125 throw new moodle_exception('disabled', 'message');
3128 // Warnings array, it can be empty at the end but is mandatory.
3129 $warnings = array();
3133 'messageid' => $messageid,
3134 'userid' => $userid,
3137 $params = self::validate_parameters(self::delete_message_parameters(), $params);
3139 // Validate context.
3140 $context = context_system::instance();
3141 self::validate_context($context);
3143 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3144 core_user::require_active_user($user);
3146 if (\core_message\api::can_delete_message($user->id, $messageid)) {
3147 $status = \core_message\api::delete_message($user->id, $messageid);
3149 throw new moodle_exception('You do not have permission to delete this message');
3153 'status' => $status,
3154 'warnings' => $warnings
3160 * Returns description of method result value
3162 * @return external_description
3165 public static function delete_message_returns() {
3166 return new external_single_structure(
3168 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
3169 'warnings' => new external_warnings()
3175 * Returns description of method parameters
3177 * @return external_function_parameters
3180 public static function message_processor_config_form_parameters() {
3181 return new external_function_parameters(
3183 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
3184 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
3185 'formvalues' => new external_multiple_structure(
3186 new external_single_structure(
3188 'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
3189 'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
3192 'Config form values',
3200 * Processes a message processor config form.
3202 * @param int $userid the user id
3203 * @param string $name the name of the processor
3204 * @param array $formvalues the form values
3205 * @return external_description
3206 * @throws moodle_exception
3209 public static function message_processor_config_form($userid, $name, $formvalues) {
3212 // Check if messaging is enabled.
3213 if (empty($CFG->messaging)) {
3214 throw new moodle_exception('disabled', 'message');
3217 $params = self::validate_parameters(
3218 self::message_processor_config_form_parameters(),
3220 'userid' => $userid,
3222 'formvalues' => $formvalues,
3226 $user = self::validate_preferences_permissions($params['userid']);
3228 $processor = get_message_processor($name);
3230 $form = new stdClass();
3232 foreach ($formvalues as $formvalue) {
3233 // Curly braces to ensure interpretation is consistent between
3235 $form->{$formvalue['name']} = $formvalue['value'];
3238 $processor->process_form($form, $preferences);
3240 if (!empty($preferences)) {
3241 set_user_preferences($preferences, $userid);
3246 * Returns description of method result value
3248 * @return external_description
3251 public static function message_processor_config_form_returns() {
3256 * Returns description of method parameters
3258 * @return external_function_parameters
3261 public static function get_message_processor_parameters() {
3262 return new external_function_parameters(
3264 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
3265 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
3271 * Get a message processor.
3273 * @param int $userid
3274 * @param string $name the name of the processor
3275 * @return external_description
3276 * @throws moodle_exception
3279 public static function get_message_processor($userid = 0, $name) {
3280 global $USER, $PAGE, $CFG;
3282 // Check if messaging is enabled.
3283 if (empty($CFG->messaging)) {
3284 throw new moodle_exception('disabled', 'message');
3287 $params = self::validate_parameters(
3288 self::get_message_processor_parameters(),
3290 'userid' => $userid,
3295 if (empty($params['userid'])) {
3296 $params['userid'] = $USER->id;
3299 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3300 core_user::require_active_user($user);
3301 self::validate_context(context_user::instance($params['userid']));
3303 $processor = get_message_processor($name);
3305 $processoroutput = new \core_message\output\processor($processor, $user);
3306 $renderer = $PAGE->get_renderer('core_message');
3308 return $processoroutput->export_for_template($renderer);
3312 * Returns description of method result value
3314 * @return external_description
3317 public static function get_message_processor_returns() {
3318 return new external_function_parameters(
3320 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
3321 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
3327 * Check that the user has enough permission to retrieve message or notifications preferences.
3329 * @param int $userid the user id requesting the preferences
3330 * @return stdClass full user object
3331 * @throws moodle_exception
3334 protected static function validate_preferences_permissions($userid) {
3337 if (empty($userid)) {
3340 $user = core_user::get_user($userid, '*', MUST_EXIST);
3341 core_user::require_active_user($user);
3344 $systemcontext = context_system::instance();
3345 self::validate_context($systemcontext);
3347 // Check access control.
3348 if ($user->id == $USER->id) {
3349 // Editing own message profile.
3350 require_capability('moodle/user:editownmessageprofile', $systemcontext);
3352 // Teachers, parents, etc.
3353 $personalcontext = context_user::instance($user->id);
3354 require_capability('moodle/user:editmessageprofile', $personalcontext);
3360 * Returns a notification or message preference structure.
3362 * @return external_single_structure the structure
3365 protected static function get_preferences_structure() {
3366 return new external_single_structure(
3368 'userid' => new external_value(PARAM_INT, 'User id'),
3369 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3370 'processors' => new external_multiple_structure(
3371 new external_single_structure(
3373 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3374 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3375 'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3376 'contextid' => new external_value(PARAM_INT, 'Context id'),
3377 'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3380 'Config form values'
3382 'components' => new external_multiple_structure(
3383 new external_single_structure(
3385 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3386 'notifications' => new external_multiple_structure(
3387 new external_single_structure(
3389 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3390 'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3391 'processors' => new external_multiple_structure(
3392 new external_single_structure(
3394 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3395 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3396 'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3397 'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3398 'loggedin' => new external_single_structure(
3400 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3401 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3402 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3405 'loggedoff' => new external_single_structure(