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', '');
716 // The user needs to be a part of the conversation before querying who the members are.
717 if (!\core_message\api::is_user_in_conversation($userid, $conversationid)) {
718 throw new moodle_exception('You are not a member of this conversation.');
723 'conversationid' => $conversationid,
724 'includecontactrequests' => $includecontactrequests,
725 'limitfrom' => $limitfrom,
726 'limitnum' => $limitnum
728 self::validate_parameters(self::get_conversation_members_parameters(), $params);
730 return \core_message\api::get_conversation_members($userid, $conversationid, $includecontactrequests,
731 $limitfrom, $limitnum);
735 * Returns the get conversation members return description.
737 * @return external_description
739 public static function get_conversation_members_returns() {
740 return new external_multiple_structure(
741 self::get_conversation_member_structure(true)
746 * Creates a contact request parameters description.
748 * @return external_function_parameters
750 public static function create_contact_request_parameters() {
751 return new external_function_parameters(
753 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
754 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
760 * Creates a contact request.
762 * @param int $userid The id of the user who is creating the contact request
763 * @param int $requesteduserid The id of the user being requested
765 public static function create_contact_request(int $userid, int $requesteduserid) {
768 // Check if messaging is enabled.
769 if (empty($CFG->messaging)) {
770 throw new moodle_exception('disabled', 'message');
774 $context = context_system::instance();
775 self::validate_context($context);
777 $capability = 'moodle/site:manageallmessaging';
778 if (($USER->id != $userid) && !has_capability($capability, $context)) {
779 throw new required_capability_exception($context, $capability, 'nopermissions', '');
782 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
783 $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
785 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
788 'itemid' => $params['requesteduserid'],
789 'warningcode' => 'cannotcreatecontactrequest',
790 'message' => 'You are unable to create a contact request for this user'
795 if (!\core_message\api::does_contact_request_exist($params['userid'], $params['requesteduserid'])) {
796 \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
803 * Creates a contact request return description.
805 * @return external_description
807 public static function create_contact_request_returns() {
808 return new external_warnings();
812 * Confirm a contact request parameters description.
814 * @return external_function_parameters
816 public static function confirm_contact_request_parameters() {
817 return new external_function_parameters(
819 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
820 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
826 * Confirm a contact request.
828 * @param int $userid The id of the user who is creating the contact request
829 * @param int $requesteduserid The id of the user being requested
831 public static function confirm_contact_request(int $userid, int $requesteduserid) {
834 // Check if messaging is enabled.
835 if (empty($CFG->messaging)) {
836 throw new moodle_exception('disabled', 'message');
840 $context = context_system::instance();
841 self::validate_context($context);
843 $capability = 'moodle/site:manageallmessaging';
844 if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
845 throw new required_capability_exception($context, $capability, 'nopermissions', '');
848 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
849 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
851 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
857 * Confirm a contact request return description.
859 * @return external_description
861 public static function confirm_contact_request_returns() {
862 return new external_warnings();
866 * Declines a contact request parameters description.
868 * @return external_function_parameters
870 public static function decline_contact_request_parameters() {
871 return new external_function_parameters(
873 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
874 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
880 * Declines a contact request.
882 * @param int $userid The id of the user who is creating the contact request
883 * @param int $requesteduserid The id of the user being requested
885 public static function decline_contact_request(int $userid, int $requesteduserid) {
888 // Check if messaging is enabled.
889 if (empty($CFG->messaging)) {
890 throw new moodle_exception('disabled', 'message');
894 $context = context_system::instance();
895 self::validate_context($context);
897 $capability = 'moodle/site:manageallmessaging';
898 if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
899 throw new required_capability_exception($context, $capability, 'nopermissions', '');
902 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
903 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
905 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
911 * Declines a contact request return description.
913 * @return external_description
915 public static function decline_contact_request_returns() {
916 return new external_warnings();
920 * Return the structure of a message area contact.
922 * @return external_single_structure
925 private static function get_messagearea_contact_structure() {
926 return new external_single_structure(
928 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
929 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
930 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
931 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
932 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
933 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
934 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
935 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
936 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
937 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
938 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
939 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
940 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
941 VALUE_DEFAULT, null),
947 * Return the structure of a conversation member.
949 * @param bool $includecontactrequests Are we including contact requests?
950 * @return external_single_structure
953 private static function get_conversation_member_structure(bool $includecontactrequests = false) {
955 'id' => new external_value(PARAM_INT, 'The user id'),
956 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
957 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
958 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
959 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
960 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
961 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
962 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
965 if ($includecontactrequests) {
966 $result['contactrequests'] = new external_multiple_structure(
967 new external_single_structure(
969 'id' => new external_value(PARAM_INT, 'The id of the message'),
970 'userid' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
971 'requesteduserid' => new external_value(PARAM_RAW, 'The text of the message'),
972 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
974 ), 'The contact requests', VALUE_OPTIONAL
978 return new external_single_structure(
984 * Return the structure of a message area message.
986 * @return external_single_structure
989 private static function get_conversation_message_structure() {
990 return new external_single_structure(
992 'id' => new external_value(PARAM_INT, 'The id of the message'),
993 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
994 'text' => new external_value(PARAM_RAW, 'The text of the message'),
995 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1001 * Return the structure of a message area message.
1003 * @return external_single_structure
1006 private static function get_messagearea_message_structure() {
1007 return new external_single_structure(
1009 'id' => new external_value(PARAM_INT, 'The id of the message'),
1010 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1011 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1012 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1013 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1014 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1015 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1016 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1017 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1018 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1024 * Get messagearea search users in course parameters.
1026 * @return external_function_parameters
1029 public static function data_for_messagearea_search_users_in_course_parameters() {
1030 return new external_function_parameters(
1032 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1033 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1034 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1035 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1036 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1042 * Get messagearea search users in course results.
1044 * @param int $userid The id of the user who is performing the search
1045 * @param int $courseid The id of the course
1046 * @param string $search The string being searched
1047 * @param int $limitfrom
1048 * @param int $limitnum
1050 * @throws moodle_exception
1053 public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1055 global $CFG, $PAGE, $USER;
1057 // Check if messaging is enabled.
1058 if (empty($CFG->messaging)) {
1059 throw new moodle_exception('disabled', 'message');
1062 $systemcontext = context_system::instance();
1065 'userid' => $userid,
1066 'courseid' => $courseid,
1067 'search' => $search,
1068 'limitfrom' => $limitfrom,
1069 'limitnum' => $limitnum
1071 self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1072 self::validate_context($systemcontext);
1074 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1075 throw new moodle_exception('You do not have permission to perform this action.');
1078 $users = \core_message\api::search_users_in_course($userid, $courseid, $search, $limitfrom, $limitnum);
1079 $results = new \core_message\output\messagearea\user_search_results($users);
1081 $renderer = $PAGE->get_renderer('core_message');
1082 return $results->export_for_template($renderer);
1086 * Get messagearea search users in course returns.
1088 * @return external_single_structure
1091 public static function data_for_messagearea_search_users_in_course_returns() {
1092 return new external_single_structure(
1094 'contacts' => new external_multiple_structure(
1095 self::get_messagearea_contact_structure()
1102 * Get messagearea search users parameters.
1104 * @return external_function_parameters
1107 public static function data_for_messagearea_search_users_parameters() {
1108 return new external_function_parameters(
1110 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1111 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1112 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1118 * Get messagearea search users results.
1120 * @param int $userid The id of the user who is performing the search
1121 * @param string $search The string being searched
1122 * @param int $limitnum
1124 * @throws moodle_exception
1127 public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1128 global $CFG, $PAGE, $USER;
1130 // Check if messaging is enabled.
1131 if (empty($CFG->messaging)) {
1132 throw new moodle_exception('disabled', 'message');
1135 $systemcontext = context_system::instance();
1138 'userid' => $userid,
1139 'search' => $search,
1140 'limitnum' => $limitnum
1142 self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1143 self::validate_context($systemcontext);
1145 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1146 throw new moodle_exception('You do not have permission to perform this action.');
1149 list($contacts, $courses, $noncontacts) = \core_message\api::search_users($userid, $search, $limitnum);
1150 $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1152 $renderer = $PAGE->get_renderer('core_message');
1153 return $search->export_for_template($renderer);
1157 * Get messagearea search users returns.
1159 * @return external_single_structure
1162 public static function data_for_messagearea_search_users_returns() {
1163 return new external_single_structure(
1165 'contacts' => new external_multiple_structure(
1166 self::get_messagearea_contact_structure()
1168 'courses' => new external_multiple_structure(
1169 new external_single_structure(
1171 'id' => new external_value(PARAM_INT, 'The course id'),
1172 'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1173 'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1177 'noncontacts' => new external_multiple_structure(
1178 self::get_messagearea_contact_structure()
1185 * Get messagearea search messages parameters.
1187 * @return external_function_parameters
1190 public static function data_for_messagearea_search_messages_parameters() {
1191 return new external_function_parameters(
1193 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1194 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1195 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1196 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1202 * Get messagearea search messages results.
1204 * @param int $userid The id of the user who is performing the search
1205 * @param string $search The string being searched
1206 * @param int $limitfrom
1207 * @param int $limitnum
1209 * @throws moodle_exception
1212 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1213 global $CFG, $PAGE, $USER;
1215 // Check if messaging is enabled.
1216 if (empty($CFG->messaging)) {
1217 throw new moodle_exception('disabled', 'message');
1220 $systemcontext = context_system::instance();
1223 'userid' => $userid,
1224 'search' => $search,
1225 'limitfrom' => $limitfrom,
1226 'limitnum' => $limitnum
1229 self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1230 self::validate_context($systemcontext);
1232 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1233 throw new moodle_exception('You do not have permission to perform this action.');
1236 $messages = \core_message\api::search_messages($userid, $search, $limitfrom, $limitnum);
1237 $results = new \core_message\output\messagearea\message_search_results($messages);
1239 $renderer = $PAGE->get_renderer('core_message');
1240 return $results->export_for_template($renderer);
1244 * Get messagearea search messages returns.
1246 * @return external_single_structure
1249 public static function data_for_messagearea_search_messages_returns() {
1250 return new external_single_structure(
1252 'contacts' => new external_multiple_structure(
1253 self::get_messagearea_contact_structure()
1260 * The messagearea conversations parameters.
1262 * @return external_function_parameters
1265 public static function data_for_messagearea_conversations_parameters() {
1266 return new external_function_parameters(
1268 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1269 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1270 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1276 * Get messagearea conversations.
1278 * @param int $userid The id of the user who we are viewing conversations for
1279 * @param int $limitfrom
1280 * @param int $limitnum
1282 * @throws moodle_exception
1285 public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1286 global $CFG, $PAGE, $USER;
1288 // Check if messaging is enabled.
1289 if (empty($CFG->messaging)) {
1290 throw new moodle_exception('disabled', 'message');
1293 $systemcontext = context_system::instance();
1296 'userid' => $userid,
1297 'limitfrom' => $limitfrom,
1298 'limitnum' => $limitnum
1300 self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1301 self::validate_context($systemcontext);
1303 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1304 throw new moodle_exception('You do not have permission to perform this action.');
1307 $conversations = \core_message\api::get_conversations($userid, $limitfrom, $limitnum);
1308 $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1310 $renderer = $PAGE->get_renderer('core_message');
1311 return $conversations->export_for_template($renderer);
1315 * The messagearea conversations return structure.
1317 * @return external_single_structure
1320 public static function data_for_messagearea_conversations_returns() {
1321 return new external_single_structure(
1323 'contacts' => new external_multiple_structure(
1324 self::get_messagearea_contact_structure()
1331 * The messagearea contacts return parameters.
1333 * @return external_function_parameters
1336 public static function data_for_messagearea_contacts_parameters() {
1337 return self::data_for_messagearea_conversations_parameters();
1341 * Get messagearea contacts parameters.
1343 * @param int $userid The id of the user who we are viewing conversations for
1344 * @param int $limitfrom
1345 * @param int $limitnum
1347 * @throws moodle_exception
1350 public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1351 global $CFG, $PAGE, $USER;
1353 // Check if messaging is enabled.
1354 if (empty($CFG->messaging)) {
1355 throw new moodle_exception('disabled', 'message');
1358 $systemcontext = context_system::instance();
1361 'userid' => $userid,
1362 'limitfrom' => $limitfrom,
1363 'limitnum' => $limitnum
1365 self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1366 self::validate_context($systemcontext);
1368 if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1369 throw new moodle_exception('You do not have permission to perform this action.');
1372 $contacts = \core_message\api::get_contacts($userid, $limitfrom, $limitnum);
1373 $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1375 $renderer = $PAGE->get_renderer('core_message');
1376 return $contacts->export_for_template($renderer);
1380 * The messagearea contacts return structure.
1382 * @return external_single_structure
1385 public static function data_for_messagearea_contacts_returns() {
1386 return self::data_for_messagearea_conversations_returns();
1390 * The messagearea messages parameters.
1392 * @return external_function_parameters
1395 public static function data_for_messagearea_messages_parameters() {
1396 return new external_function_parameters(
1398 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1399 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1400 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1401 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1402 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1403 'timefrom' => new external_value(PARAM_INT,
1404 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1410 * Get messagearea messages.
1412 * @param int $currentuserid The current user's id
1413 * @param int $otheruserid The other user's id
1414 * @param int $limitfrom
1415 * @param int $limitnum
1416 * @param boolean $newest
1418 * @throws moodle_exception
1421 public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1422 $newest = false, $timefrom = 0) {
1423 global $CFG, $PAGE, $USER;
1425 // Check if messaging is enabled.
1426 if (empty($CFG->messaging)) {
1427 throw new moodle_exception('disabled', 'message');
1430 $systemcontext = context_system::instance();
1433 'currentuserid' => $currentuserid,
1434 'otheruserid' => $otheruserid,
1435 'limitfrom' => $limitfrom,
1436 'limitnum' => $limitnum,
1437 'newest' => $newest,
1438 'timefrom' => $timefrom,
1440 self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1441 self::validate_context($systemcontext);
1443 if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1444 throw new moodle_exception('You do not have permission to perform this action.');
1448 $sort = 'timecreated DESC';
1450 $sort = 'timecreated ASC';
1453 // We need to enforce a one second delay on messages to avoid race conditions of current
1454 // messages still being sent.
1456 // There is a chance that we could request messages before the current time's
1457 // second has elapsed and while other messages are being sent in that same second. In which
1458 // case those messages will be lost.
1460 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1461 if (!empty($timefrom)) {
1462 $timeto = time() - 1;
1467 // No requesting messages from the current time, as stated above.
1468 if ($timefrom == time()) {
1471 $messages = \core_message\api::get_messages($currentuserid, $otheruserid, $limitfrom,
1472 $limitnum, $sort, $timefrom, $timeto);
1475 $messages = new \core_message\output\messagearea\messages($currentuserid, $otheruserid, $messages);
1477 $renderer = $PAGE->get_renderer('core_message');
1478 return $messages->export_for_template($renderer);
1482 * The messagearea messages return structure.
1484 * @return external_single_structure
1487 public static function data_for_messagearea_messages_returns() {
1488 return new external_single_structure(
1490 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1491 the messages on behalf of?'),
1492 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1493 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1494 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1495 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1496 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1497 'messages' => new external_multiple_structure(
1498 self::get_messagearea_message_structure()
1500 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1506 * The conversation messages parameters.
1508 * @return external_function_parameters
1511 public static function get_conversation_messages_parameters() {
1512 return new external_function_parameters(
1514 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1515 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1516 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1517 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1518 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1519 'timefrom' => new external_value(PARAM_INT,
1520 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1526 * Get conversation messages.
1528 * @param int $currentuserid The current user's id.
1529 * @param int $convid The conversation id.
1530 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1531 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1532 * @param bool $newest True for getting first newest messages, false otherwise.
1533 * @param int $timefrom The time from the conversation messages to get.
1534 * @return stdClass The messages and members who have sent some of these messages.
1535 * @throws moodle_exception
1538 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1539 bool $newest = false, int $timefrom = 0) {
1540 global $CFG, $PAGE, $USER;
1542 // Check if messaging is enabled.
1543 if (empty($CFG->messaging)) {
1544 throw new moodle_exception('disabled', 'message');
1547 $systemcontext = context_system::instance();
1550 'currentuserid' => $currentuserid,
1551 'convid' => $convid,
1552 'limitfrom' => $limitfrom,
1553 'limitnum' => $limitnum,
1554 'newest' => $newest,
1555 'timefrom' => $timefrom,
1557 self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1558 self::validate_context($systemcontext);
1560 if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1561 throw new moodle_exception('You do not have permission to perform this action.');
1564 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1566 // We need to enforce a one second delay on messages to avoid race conditions of current
1567 // messages still being sent.
1569 // There is a chance that we could request messages before the current time's
1570 // second has elapsed and while other messages are being sent in that same second. In which
1571 // case those messages will be lost.
1573 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1574 $timeto = empty($timefrom) ? 0 : time() - 1;
1576 // No requesting messages from the current time, as stated above.
1577 if ($timefrom == time()) {
1580 $messages = \core_message\api::get_conversation_messages($currentuserid, $convid, $limitfrom,
1581 $limitnum, $sort, $timefrom, $timeto);
1588 * The messagearea messages return structure.
1590 * @return external_single_structure
1593 public static function get_conversation_messages_returns() {
1594 return new external_single_structure(
1596 'id' => new external_value(PARAM_INT, 'The conversation id'),
1597 'members' => new external_multiple_structure(
1598 self::get_conversation_member_structure()
1600 'messages' => new external_multiple_structure(
1601 self::get_conversation_message_structure()
1608 * The get most recent message return parameters.
1610 * @return external_function_parameters
1613 public static function data_for_messagearea_get_most_recent_message_parameters() {
1614 return new external_function_parameters(
1616 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1617 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1623 * Get the most recent message in a conversation.
1625 * @param int $currentuserid The current user's id
1626 * @param int $otheruserid The other user's id
1628 * @throws moodle_exception
1631 public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
1632 global $CFG, $PAGE, $USER;
1634 // Check if messaging is enabled.
1635 if (empty($CFG->messaging)) {
1636 throw new moodle_exception('disabled', 'message');
1639 $systemcontext = context_system::instance();
1642 'currentuserid' => $currentuserid,
1643 'otheruserid' => $otheruserid
1645 self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
1646 self::validate_context($systemcontext);
1648 if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1649 throw new moodle_exception('You do not have permission to perform this action.');
1652 $message = \core_message\api::get_most_recent_message($currentuserid, $otheruserid);
1653 $message = new \core_message\output\messagearea\message($message);
1655 $renderer = $PAGE->get_renderer('core_message');
1656 return $message->export_for_template($renderer);
1660 * The get most recent message return structure.
1662 * @return external_single_structure
1665 public static function data_for_messagearea_get_most_recent_message_returns() {
1666 return self::get_messagearea_message_structure();
1670 * The get profile parameters.
1672 * @return external_function_parameters
1675 public static function data_for_messagearea_get_profile_parameters() {
1676 return new external_function_parameters(
1678 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1679 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
1685 * Get the profile information for a contact.
1687 * @param int $currentuserid The current user's id
1688 * @param int $otheruserid The id of the user whose profile we are viewing
1690 * @throws moodle_exception
1693 public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
1694 global $CFG, $PAGE, $USER;
1696 // Check if messaging is enabled.
1697 if (empty($CFG->messaging)) {
1698 throw new moodle_exception('disabled', 'message');
1701 $systemcontext = context_system::instance();
1704 'currentuserid' => $currentuserid,
1705 'otheruserid' => $otheruserid
1707 self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
1708 self::validate_context($systemcontext);
1710 if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1711 throw new moodle_exception('You do not have permission to perform this action.');
1714 $profile = \core_message\api::get_profile($currentuserid, $otheruserid);
1715 $profile = new \core_message\output\messagearea\profile($profile);
1717 $renderer = $PAGE->get_renderer('core_message');
1718 return $profile->export_for_template($renderer);
1722 * The get profile return structure.
1724 * @return external_single_structure
1727 public static function data_for_messagearea_get_profile_returns() {
1728 return new external_single_structure(
1730 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
1731 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
1732 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
1733 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
1734 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1735 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1736 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1737 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1738 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1739 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
1740 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
1746 * Get contacts parameters description.
1748 * @return external_function_parameters
1751 public static function get_contacts_parameters() {
1752 return new external_function_parameters(array());
1758 * @return external_description
1761 public static function get_contacts() {
1762 global $CFG, $PAGE, $USER;
1764 // Check if messaging is enabled.
1765 if (empty($CFG->messaging)) {
1766 throw new moodle_exception('disabled', 'message');
1769 require_once($CFG->dirroot . '/user/lib.php');
1771 $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
1772 $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
1773 foreach ($contacts as $contact) {
1776 if (\core_message\helper::is_online($contact->lastaccess)) {
1780 $newcontact = array(
1781 'id' => $contact->id,
1782 'fullname' => fullname($contact),
1783 'unread' => $contact->messagecount
1786 $userpicture = new user_picture($contact);
1787 $userpicture->size = 1; // Size f1.
1788 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1789 $userpicture->size = 0; // Size f2.
1790 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1792 $allcontacts[$mode][$contact->id] = $newcontact;
1795 $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
1796 foreach ($strangers as $contact) {
1797 $newcontact = array(
1798 'id' => $contact->id,
1799 'fullname' => fullname($contact),
1800 'unread' => $contact->messagecount
1803 $userpicture = new user_picture($contact);
1804 $userpicture->size = 1; // Size f1.
1805 $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1806 $userpicture->size = 0; // Size f2.
1807 $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1809 $allcontacts['strangers'][$contact->id] = $newcontact;
1812 // Add noreply user and support user to the list, if they don't exist.
1813 $supportuser = core_user::get_support_user();
1814 if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
1815 $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
1816 if ($supportuser->messagecount > 0) {
1817 $supportuser->fullname = fullname($supportuser);
1818 $supportuser->unread = $supportuser->messagecount;
1819 $allcontacts['strangers'][$supportuser->id] = $supportuser;
1823 $noreplyuser = core_user::get_noreply_user();
1824 if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
1825 $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
1826 if ($noreplyuser->messagecount > 0) {
1827 $noreplyuser->fullname = fullname($noreplyuser);
1828 $noreplyuser->unread = $noreplyuser->messagecount;
1829 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
1833 return $allcontacts;
1837 * Get contacts return description.
1839 * @return external_description
1842 public static function get_contacts_returns() {
1843 return new external_single_structure(
1845 'online' => new external_multiple_structure(
1846 new external_single_structure(
1848 'id' => new external_value(PARAM_INT, 'User ID'),
1849 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1850 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1851 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1852 'unread' => new external_value(PARAM_INT, 'Unread message count')
1855 'List of online contacts'
1857 'offline' => new external_multiple_structure(
1858 new external_single_structure(
1860 'id' => new external_value(PARAM_INT, 'User ID'),
1861 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1862 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1863 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1864 'unread' => new external_value(PARAM_INT, 'Unread message count')
1867 'List of offline contacts'
1869 'strangers' => new external_multiple_structure(
1870 new external_single_structure(
1872 'id' => new external_value(PARAM_INT, 'User ID'),
1873 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1874 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1875 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1876 'unread' => new external_value(PARAM_INT, 'Unread message count')
1879 'List of users that are not in the user\'s contact list but have sent a message'
1886 * Search contacts parameters description.
1888 * @return external_function_parameters
1891 public static function search_contacts_parameters() {
1892 return new external_function_parameters(
1894 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1895 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1896 VALUE_DEFAULT, false)
1904 * @param string $searchtext query string.
1905 * @param bool $onlymycourses limit the search to the user's courses only.
1906 * @return external_description
1909 public static function search_contacts($searchtext, $onlymycourses = false) {
1910 global $CFG, $USER, $PAGE;
1911 require_once($CFG->dirroot . '/user/lib.php');
1913 // Check if messaging is enabled.
1914 if (empty($CFG->messaging)) {
1915 throw new moodle_exception('disabled', 'message');
1918 require_once($CFG->libdir . '/enrollib.php');
1920 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1921 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1923 // Extra validation, we do not allow empty queries.
1924 if ($params['searchtext'] === '') {
1925 throw new moodle_exception('querystringcannotbeempty');
1928 $courseids = array();
1929 if ($params['onlymycourses']) {
1930 $mycourses = enrol_get_my_courses(array('id'));
1931 foreach ($mycourses as $mycourse) {
1932 $courseids[] = $mycourse->id;
1935 $courseids[] = SITEID;
1938 // Retrieving the users matching the query.
1939 $users = message_search_users($courseids, $params['searchtext']);
1941 foreach ($users as $user) {
1942 $results[$user->id] = $user;
1945 // Reorganising information.
1946 foreach ($results as &$user) {
1949 'fullname' => fullname($user)
1952 // Avoid undefined property notice as phone not specified.
1953 $user->phone1 = null;
1954 $user->phone2 = null;
1956 $userpicture = new user_picture($user);
1957 $userpicture->size = 1; // Size f1.
1958 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1959 $userpicture->size = 0; // Size f2.
1960 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1969 * Search contacts return description.
1971 * @return external_description
1974 public static function search_contacts_returns() {
1975 return new external_multiple_structure(
1976 new external_single_structure(
1978 'id' => new external_value(PARAM_INT, 'User ID'),
1979 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1980 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1981 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1989 * Get messages parameters description.
1991 * @return external_function_parameters
1994 public static function get_messages_parameters() {
1995 return new external_function_parameters(
1997 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1998 'useridfrom' => new external_value(
1999 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2001 'type' => new external_value(
2002 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2003 VALUE_DEFAULT, 'both'),
2004 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2005 'newestfirst' => new external_value(
2006 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2007 VALUE_DEFAULT, true),
2008 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2009 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2015 * Get messages function implementation.
2018 * @throws invalid_parameter_exception
2019 * @throws moodle_exception
2020 * @param int $useridto the user id who received the message
2021 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2022 * @param string $type type of message to return, expected values: notifications, conversations and both
2023 * @param bool $read true for retreiving read messages, false for unread
2024 * @param bool $newestfirst true for ordering by newest first, false for oldest first
2025 * @param int $limitfrom limit from
2026 * @param int $limitnum limit num
2027 * @return external_description
2029 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2030 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2033 $warnings = array();
2036 'useridto' => $useridto,
2037 'useridfrom' => $useridfrom,
2040 'newestfirst' => $newestfirst,
2041 'limitfrom' => $limitfrom,
2042 'limitnum' => $limitnum
2045 $params = self::validate_parameters(self::get_messages_parameters(), $params);
2047 $context = context_system::instance();
2048 self::validate_context($context);
2050 $useridto = $params['useridto'];
2051 $useridfrom = $params['useridfrom'];
2052 $type = $params['type'];
2053 $read = $params['read'];
2054 $newestfirst = $params['newestfirst'];
2055 $limitfrom = $params['limitfrom'];
2056 $limitnum = $params['limitnum'];
2058 $allowedvalues = array('notifications', 'conversations', 'both');
2059 if (!in_array($type, $allowedvalues)) {
2060 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2061 'allowed values are: ' . implode(',', $allowedvalues));
2064 // Check if private messaging between users is allowed.
2065 if (empty($CFG->messaging)) {
2066 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2067 if ($type == "conversations") {
2068 throw new moodle_exception('disabled', 'message');
2070 if ($type == "both") {
2072 $warning['item'] = 'message';
2073 $warning['itemid'] = $USER->id;
2074 $warning['warningcode'] = '1';
2075 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2076 Only notifications will be returned';
2077 $warnings[] = $warning;
2081 if (!empty($useridto)) {
2082 if (core_user::is_real_user($useridto)) {
2083 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2085 throw new moodle_exception('invaliduser');
2089 if (!empty($useridfrom)) {
2090 // We use get_user here because the from user can be the noreply or support user.
2091 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2094 // Check if the current user is the sender/receiver or just a privileged user.
2095 if ($useridto != $USER->id and $useridfrom != $USER->id and
2096 !has_capability('moodle/site:readallmessages', $context)) {
2097 throw new moodle_exception('accessdenied', 'admin');
2100 // Which type of messages to retrieve.
2101 $notifications = -1;
2102 if ($type != 'both') {
2103 $notifications = ($type == 'notifications') ? 1 : 0;
2106 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2107 $sort = "mr.timecreated $orderdirection";
2109 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2110 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2112 // In some cases, we don't need to get the to/from user objects from the sql query.
2113 $userfromfullname = '';
2114 $usertofullname = '';
2116 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2117 if (!empty($useridto)) {
2118 $usertofullname = fullname($userto, $canviewfullname);
2119 // The user from may or may not be filled.
2120 if (!empty($useridfrom)) {
2121 $userfromfullname = fullname($userfrom, $canviewfullname);
2124 // If the useridto field is empty, the useridfrom must be filled.
2125 $userfromfullname = fullname($userfrom, $canviewfullname);
2127 foreach ($messages as $mid => $message) {
2129 // Do not return deleted messages.
2130 if (!$message->notification) {
2131 if (($useridto == $USER->id and $message->timeusertodeleted) or
2132 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2133 unset($messages[$mid]);
2138 // We need to get the user from the query.
2139 if (empty($userfromfullname)) {
2140 // Check for non-reply and support users.
2141 if (core_user::is_real_user($message->useridfrom)) {
2142 $user = new stdClass();
2143 $user = username_load_fields_from_object($user, $message, 'userfrom');
2144 $message->userfromfullname = fullname($user, $canviewfullname);
2146 $user = core_user::get_user($message->useridfrom);
2147 $message->userfromfullname = fullname($user, $canviewfullname);
2150 $message->userfromfullname = $userfromfullname;
2153 // We need to get the user from the query.
2154 if (empty($usertofullname)) {
2155 $user = new stdClass();
2156 $user = username_load_fields_from_object($user, $message, 'userto');
2157 $message->usertofullname = fullname($user, $canviewfullname);
2159 $message->usertofullname = $usertofullname;
2162 $message->text = message_format_message_text($message);
2163 $messages[$mid] = (array) $message;
2168 'messages' => $messages,
2169 'warnings' => $warnings
2176 * Get messages return description.
2178 * @return external_single_structure
2181 public static function get_messages_returns() {
2182 return new external_single_structure(
2184 'messages' => new external_multiple_structure(
2185 new external_single_structure(
2187 'id' => new external_value(PARAM_INT, 'Message id'),
2188 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2189 'useridto' => new external_value(PARAM_INT, 'User to id'),
2190 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2191 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2192 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2193 'fullmessageformat' => new external_format_value('fullmessage'),
2194 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2195 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2196 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2197 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2198 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2199 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2200 'timeread' => new external_value(PARAM_INT, 'Time read'),
2201 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2202 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2206 'warnings' => new external_warnings()
2212 * Mark all notifications as read parameters description.
2214 * @return external_function_parameters
2217 public static function mark_all_notifications_as_read_parameters() {
2218 return new external_function_parameters(
2220 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2221 'useridfrom' => new external_value(
2222 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2229 * Mark all notifications as read function.
2232 * @throws invalid_parameter_exception
2233 * @throws moodle_exception
2234 * @param int $useridto the user id who received the message
2235 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2236 * @return external_description
2238 public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2241 $params = self::validate_parameters(
2242 self::mark_all_notifications_as_read_parameters(),
2244 'useridto' => $useridto,
2245 'useridfrom' => $useridfrom,
2249 $context = context_system::instance();
2250 self::validate_context($context);
2252 $useridto = $params['useridto'];
2253 $useridfrom = $params['useridfrom'];
2255 if (!empty($useridto)) {
2256 if (core_user::is_real_user($useridto)) {
2257 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2259 throw new moodle_exception('invaliduser');
2263 if (!empty($useridfrom)) {
2264 // We use get_user here because the from user can be the noreply or support user.
2265 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2268 // Check if the current user is the sender/receiver or just a privileged user.
2269 if ($useridto != $USER->id and $useridfrom != $USER->id and
2270 // The deleteanymessage cap seems more reasonable here than readallmessages.
2271 !has_capability('moodle/site:deleteanymessage', $context)) {
2272 throw new moodle_exception('accessdenied', 'admin');
2275 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2281 * Mark all notifications as read return description.
2283 * @return external_single_structure
2286 public static function mark_all_notifications_as_read_returns() {
2287 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2291 * Get unread conversations count parameters description.
2293 * @return external_function_parameters
2296 public static function get_unread_conversations_count_parameters() {
2297 return new external_function_parameters(
2299 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2305 * Get unread messages count function.
2308 * @throws invalid_parameter_exception
2309 * @throws moodle_exception
2310 * @param int $useridto the user id who received the message
2311 * @return external_description
2313 public static function get_unread_conversations_count($useridto) {
2316 // Check if messaging is enabled.
2317 if (empty($CFG->messaging)) {
2318 throw new moodle_exception('disabled', 'message');
2321 $params = self::validate_parameters(
2322 self::get_unread_conversations_count_parameters(),
2323 array('useridto' => $useridto)
2326 $context = context_system::instance();
2327 self::validate_context($context);
2329 $useridto = $params['useridto'];
2331 if (!empty($useridto)) {
2332 if (core_user::is_real_user($useridto)) {
2333 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2335 throw new moodle_exception('invaliduser');
2338 $useridto = $USER->id;
2341 // Check if the current user is the receiver or just a privileged user.
2342 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2343 throw new moodle_exception('accessdenied', 'admin');
2346 return \core_message\api::count_unread_conversations($userto);
2350 * Get unread conversations count return description.
2352 * @return external_single_structure
2355 public static function get_unread_conversations_count_returns() {
2356 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2360 * Get blocked users parameters description.
2362 * @return external_function_parameters
2365 public static function get_blocked_users_parameters() {
2366 return new external_function_parameters(
2368 'userid' => new external_value(PARAM_INT,
2369 'the user whose blocked users we want to retrieve',
2376 * Retrieve a list of users blocked
2378 * @param int $userid the user whose blocked users we want to retrieve
2379 * @return external_description
2382 public static function get_blocked_users($userid) {
2383 global $CFG, $USER, $PAGE;
2385 // Warnings array, it can be empty at the end but is mandatory.
2386 $warnings = array();
2392 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2393 $userid = $params['userid'];
2395 // Validate context.
2396 $context = context_system::instance();
2397 self::validate_context($context);
2399 // Check if private messaging between users is allowed.
2400 if (empty($CFG->messaging)) {
2401 throw new moodle_exception('disabled', 'message');
2404 $user = core_user::get_user($userid, '*', MUST_EXIST);
2405 core_user::require_active_user($user);
2407 // Check if we have permissions for retrieve the information.
2408 $capability = 'moodle/site:manageallmessaging';
2409 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2410 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2413 // Now, we can get safely all the blocked users.
2414 $users = \core_message\api::get_blocked_users($user->id);
2416 $blockedusers = array();
2417 foreach ($users as $user) {
2420 'fullname' => fullname($user),
2423 $userpicture = new user_picture($user);
2424 $userpicture->size = 1; // Size f1.
2425 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2427 $blockedusers[] = $newuser;
2431 'users' => $blockedusers,
2432 'warnings' => $warnings
2438 * Get blocked users return description.
2440 * @return external_single_structure
2443 public static function get_blocked_users_returns() {
2444 return new external_single_structure(
2446 'users' => new external_multiple_structure(
2447 new external_single_structure(
2449 'id' => new external_value(PARAM_INT, 'User ID'),
2450 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2451 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2454 'List of blocked users'
2456 'warnings' => new external_warnings()
2462 * Returns description of method parameters
2464 * @return external_function_parameters
2467 public static function mark_message_read_parameters() {
2468 return new external_function_parameters(
2470 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2471 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2478 * Mark a single message as read, trigger message_viewed event
2480 * @param int $messageid id of the message (in the message table)
2481 * @param int $timeread timestamp for when the message should be marked read
2482 * @return external_description
2483 * @throws invalid_parameter_exception
2484 * @throws moodle_exception
2487 public static function mark_message_read($messageid, $timeread) {
2488 global $CFG, $DB, $USER;
2490 // Check if private messaging between users is allowed.
2491 if (empty($CFG->messaging)) {
2492 throw new moodle_exception('disabled', 'message');
2495 // Warnings array, it can be empty at the end but is mandatory.
2496 $warnings = array();
2500 'messageid' => $messageid,
2501 'timeread' => $timeread
2503 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2505 if (empty($params['timeread'])) {
2508 $timeread = $params['timeread'];
2511 // Validate context.
2512 $context = context_system::instance();
2513 self::validate_context($context);
2515 $sql = "SELECT m.*, mcm.userid as useridto
2517 INNER JOIN {message_conversations} mc
2518 ON m.conversationid = mc.id
2519 INNER JOIN {message_conversation_members} mcm
2520 ON mcm.conversationid = mc.id
2521 LEFT JOIN {message_user_actions} mua
2522 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2523 WHERE mua.id is NULL
2524 AND mcm.userid != m.useridfrom
2526 $messageparams = [];
2527 $messageparams[] = $USER->id;
2528 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2529 $messageparams[] = $params['messageid'];
2530 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2532 if ($message->useridto != $USER->id) {
2533 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2536 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2539 'messageid' => $message->id,
2540 'warnings' => $warnings
2546 * Returns description of method result value
2548 * @return external_description
2551 public static function mark_message_read_returns() {
2552 return new external_single_structure(
2554 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2555 'warnings' => new external_warnings()
2561 * Returns description of method parameters
2563 * @return external_function_parameters
2565 public static function mark_notification_read_parameters() {
2566 return new external_function_parameters(
2568 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2569 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2576 * Mark a single notification as read.
2578 * This will trigger a 'notification_viewed' event.
2580 * @param int $notificationid id of the notification
2581 * @param int $timeread timestamp for when the notification should be marked read
2582 * @return external_description
2583 * @throws invalid_parameter_exception
2584 * @throws moodle_exception
2586 public static function mark_notification_read($notificationid, $timeread) {
2587 global $CFG, $DB, $USER;
2589 // Check if private messaging between users is allowed.
2590 if (empty($CFG->messaging)) {
2591 throw new moodle_exception('disabled', 'message');
2594 // Warnings array, it can be empty at the end but is mandatory.
2595 $warnings = array();
2599 'notificationid' => $notificationid,
2600 'timeread' => $timeread
2602 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2604 if (empty($params['timeread'])) {
2607 $timeread = $params['timeread'];
2610 // Validate context.
2611 $context = context_system::instance();
2612 self::validate_context($context);
2614 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2616 if ($notification->useridto != $USER->id) {
2617 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2618 'notification as read');
2621 \core_message\api::mark_notification_as_read($notification, $timeread);
2624 'notificationid' => $notification->id,
2625 'warnings' => $warnings
2632 * Returns description of method result value
2634 * @return external_description
2636 public static function mark_notification_read_returns() {
2637 return new external_single_structure(
2639 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2640 'warnings' => new external_warnings()
2646 * Mark all messages as read parameters description.
2648 * @deprecated since 3.6
2649 * @return external_function_parameters
2652 public static function mark_all_messages_as_read_parameters() {
2653 return new external_function_parameters(
2655 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2656 'useridfrom' => new external_value(
2657 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2664 * Mark all messages as read function.
2666 * @deprecated since 3.6
2667 * @throws invalid_parameter_exception
2668 * @throws moodle_exception
2669 * @param int $useridto the user id who received the message
2670 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2671 * @return external_description
2674 public static function mark_all_messages_as_read($useridto, $useridfrom) {
2677 // Check if messaging is enabled.
2678 if (empty($CFG->messaging)) {
2679 throw new moodle_exception('disabled', 'message');
2682 $params = self::validate_parameters(
2683 self::mark_all_messages_as_read_parameters(),
2685 'useridto' => $useridto,
2686 'useridfrom' => $useridfrom,
2690 $context = context_system::instance();
2691 self::validate_context($context);
2693 $useridto = $params['useridto'];
2694 $useridfrom = $params['useridfrom'];
2696 if (!empty($useridto)) {
2697 if (core_user::is_real_user($useridto)) {
2698 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2700 throw new moodle_exception('invaliduser');
2704 if (!empty($useridfrom)) {
2705 // We use get_user here because the from user can be the noreply or support user.
2706 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2709 // Check if the current user is the sender/receiver or just a privileged user.
2710 if ($useridto != $USER->id and $useridfrom != $USER->id and
2711 // The deleteanymessage cap seems more reasonable here than readallmessages.
2712 !has_capability('moodle/site:deleteanymessage', $context)) {
2713 throw new moodle_exception('accessdenied', 'admin');
2717 if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
2718 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
2721 \core_message\api::mark_all_messages_as_read($useridto);
2728 * Mark all messages as read return description.
2730 * @deprecated since 3.6
2731 * @return external_single_structure
2734 public static function mark_all_messages_as_read_returns() {
2735 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2739 * Marking the method as deprecated.
2743 public static function mark_all_messages_as_read_is_deprecated() {
2748 * Mark all conversation messages as read parameters description.
2750 * @return external_function_parameters
2753 public static function mark_all_conversation_messages_as_read_parameters() {
2754 return new external_function_parameters(
2756 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2758 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2764 * Mark all conversation messages as read function.
2766 * @param int $userid The user id of who we want to delete the conversation for
2767 * @param int $conversationid The id of the conversations
2770 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2773 // Check if messaging is enabled.
2774 if (empty($CFG->messaging)) {
2775 throw new moodle_exception('disabled', 'message');
2779 'userid' => $userid,
2780 'conversationid' => $conversationid,
2782 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2784 $context = context_system::instance();
2785 self::validate_context($context);
2787 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2788 core_user::require_active_user($user);
2790 if (\core_message\api::can_mark_all_messages_as_read($userid, $conversationid)) {
2791 \core_message\api::mark_all_messages_as_read($userid, $conversationid);
2793 throw new moodle_exception('accessdenied', 'admin');
2798 * Mark all conversation messages as read return description.
2800 * @return external_warnings
2803 public static function mark_all_conversation_messages_as_read_returns() {
2804 return new external_warnings();
2808 * Returns description of method parameters.
2810 * @deprecated since 3.6
2811 * @return external_function_parameters
2814 public static function delete_conversation_parameters() {
2815 return new external_function_parameters(
2817 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2818 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
2824 * Deletes a conversation.
2826 * @deprecated since 3.6
2827 * @param int $userid The user id of who we want to delete the conversation for
2828 * @param int $otheruserid The user id of the other user in the conversation
2830 * @throws moodle_exception
2833 public static function delete_conversation($userid, $otheruserid) {
2836 // Check if private messaging between users is allowed.
2837 if (empty($CFG->messaging)) {
2838 throw new moodle_exception('disabled', 'message');
2841 // Warnings array, it can be empty at the end but is mandatory.
2842 $warnings = array();
2846 'userid' => $userid,
2847 'otheruserid' => $otheruserid,
2849 $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
2851 // Validate context.
2852 $context = context_system::instance();
2853 self::validate_context($context);
2855 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2856 core_user::require_active_user($user);
2858 if (!$conversationid = \core_message\api::get_conversation_between_users([$userid, $otheruserid])) {
2862 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2863 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2866 throw new moodle_exception('You do not have permission to delete messages');
2870 'status' => $status,
2871 'warnings' => $warnings
2878 * Returns description of method result value.
2880 * @deprecated since 3.6
2881 * @return external_description
2884 public static function delete_conversation_returns() {
2885 return new external_single_structure(
2887 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
2888 'warnings' => new external_warnings()
2894 * Marking the method as deprecated.
2898 public static function delete_conversation_is_deprecated() {
2903 * Returns description of method parameters.
2905 * @return external_function_parameters
2908 public static function delete_conversations_by_id_parameters() {
2909 return new external_function_parameters(
2911 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2912 'conversationids' => new external_multiple_structure(
2913 new external_value(PARAM_INT, 'The id of the conversation'),
2914 'List of conversation IDs'
2921 * Deletes a conversation.
2923 * @param int $userid The user id of who we want to delete the conversation for
2924 * @param int[] $conversationids The ids of the conversations
2926 * @throws moodle_exception
2929 public static function delete_conversations_by_id($userid, array $conversationids) {
2932 // Check if private messaging between users is allowed.
2933 if (empty($CFG->messaging)) {
2934 throw new moodle_exception('disabled', 'message');
2939 'userid' => $userid,
2940 'conversationids' => $conversationids,
2942 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
2944 // Validate context.
2945 $context = context_system::instance();
2946 self::validate_context($context);
2948 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2949 core_user::require_active_user($user);
2951 foreach ($conversationids as $conversationid) {
2952 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2953 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2955 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2963 * Returns description of method result value.
2965 * @return external_description
2968 public static function delete_conversations_by_id_returns() {
2969 return new external_warnings();
2973 * Returns description of method parameters
2975 * @return external_function_parameters
2978 public static function delete_message_parameters() {
2979 return new external_function_parameters(
2981 'messageid' => new external_value(PARAM_INT, 'The message id'),
2982 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2983 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2991 * @param int $messageid the message id
2992 * @param int $userid the user id of who we want to delete the message for
2993 * @param bool $read if is a message read (default to true)
2994 * @return external_description
2995 * @throws moodle_exception
2998 public static function delete_message($messageid, $userid, $read = true) {
3001 // Check if private messaging between users is allowed.
3002 if (empty($CFG->messaging)) {
3003 throw new moodle_exception('disabled', 'message');
3006 // Warnings array, it can be empty at the end but is mandatory.
3007 $warnings = array();
3011 'messageid' => $messageid,
3012 'userid' => $userid,
3015 $params = self::validate_parameters(self::delete_message_parameters(), $params);
3017 // Validate context.
3018 $context = context_system::instance();
3019 self::validate_context($context);
3021 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3022 core_user::require_active_user($user);
3024 if (\core_message\api::can_delete_message($user->id, $messageid)) {
3025 $status = \core_message\api::delete_message($user->id, $messageid);
3027 throw new moodle_exception('You do not have permission to delete this message');
3031 'status' => $status,
3032 'warnings' => $warnings
3038 * Returns description of method result value
3040 * @return external_description
3043 public static function delete_message_returns() {
3044 return new external_single_structure(
3046 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
3047 'warnings' => new external_warnings()
3053 * Returns description of method parameters
3055 * @return external_function_parameters
3058 public static function message_processor_config_form_parameters() {
3059 return new external_function_parameters(
3061 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
3062 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
3063 'formvalues' => new external_multiple_structure(
3064 new external_single_structure(
3066 'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
3067 'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
3070 'Config form values',
3078 * Processes a message processor config form.
3080 * @param int $userid the user id
3081 * @param string $name the name of the processor
3082 * @param array $formvalues the form values
3083 * @return external_description
3084 * @throws moodle_exception
3087 public static function message_processor_config_form($userid, $name, $formvalues) {
3090 // Check if messaging is enabled.
3091 if (empty($CFG->messaging)) {
3092 throw new moodle_exception('disabled', 'message');
3095 $params = self::validate_parameters(
3096 self::message_processor_config_form_parameters(),
3098 'userid' => $userid,
3100 'formvalues' => $formvalues,
3104 $user = self::validate_preferences_permissions($params['userid']);
3106 $processor = get_message_processor($name);
3108 $form = new stdClass();
3110 foreach ($formvalues as $formvalue) {
3111 // Curly braces to ensure interpretation is consistent between
3113 $form->{$formvalue['name']} = $formvalue['value'];
3116 $processor->process_form($form, $preferences);
3118 if (!empty($preferences)) {
3119 set_user_preferences($preferences, $userid);
3124 * Returns description of method result value
3126 * @return external_description
3129 public static function message_processor_config_form_returns() {
3134 * Returns description of method parameters
3136 * @return external_function_parameters
3139 public static function get_message_processor_parameters() {
3140 return new external_function_parameters(
3142 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
3143 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
3149 * Get a message processor.
3151 * @param int $userid
3152 * @param string $name the name of the processor
3153 * @return external_description
3154 * @throws moodle_exception
3157 public static function get_message_processor($userid = 0, $name) {
3158 global $USER, $PAGE, $CFG;
3160 // Check if messaging is enabled.
3161 if (empty($CFG->messaging)) {
3162 throw new moodle_exception('disabled', 'message');
3165 $params = self::validate_parameters(
3166 self::get_message_processor_parameters(),
3168 'userid' => $userid,
3173 if (empty($params['userid'])) {
3174 $params['userid'] = $USER->id;
3177 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3178 core_user::require_active_user($user);
3179 self::validate_context(context_user::instance($params['userid']));
3181 $processor = get_message_processor($name);
3183 $processoroutput = new \core_message\output\processor($processor, $user);
3184 $renderer = $PAGE->get_renderer('core_message');
3186 return $processoroutput->export_for_template($renderer);
3190 * Returns description of method result value
3192 * @return external_description
3195 public static function get_message_processor_returns() {
3196 return new external_function_parameters(
3198 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
3199 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
3205 * Check that the user has enough permission to retrieve message or notifications preferences.
3207 * @param int $userid the user id requesting the preferences
3208 * @return stdClass full user object
3209 * @throws moodle_exception
3212 protected static function validate_preferences_permissions($userid) {
3215 if (empty($userid)) {
3218 $user = core_user::get_user($userid, '*', MUST_EXIST);
3219 core_user::require_active_user($user);
3222 $systemcontext = context_system::instance();
3223 self::validate_context($systemcontext);
3225 // Check access control.
3226 if ($user->id == $USER->id) {
3227 // Editing own message profile.
3228 require_capability('moodle/user:editownmessageprofile', $systemcontext);
3230 // Teachers, parents, etc.
3231 $personalcontext = context_user::instance($user->id);
3232 require_capability('moodle/user:editmessageprofile', $personalcontext);
3238 * Returns a notification or message preference structure.
3240 * @return external_single_structure the structure
3243 protected static function get_preferences_structure() {
3244 return new external_single_structure(
3246 'userid' => new external_value(PARAM_INT, 'User id'),
3247 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3248 'processors' => new external_multiple_structure(
3249 new external_single_structure(
3251 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3252 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3253 'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3254 'contextid' => new external_value(PARAM_INT, 'Context id'),
3255 'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3258 'Config form values'
3260 'components' => new external_multiple_structure(
3261 new external_single_structure(
3263 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3264 'notifications' => new external_multiple_structure(
3265 new external_single_structure(
3267 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3268 'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3269 'processors' => new external_multiple_structure(
3270 new external_single_structure(
3272 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3273 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3274 'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3275 'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3276 'loggedin' => new external_single_structure(
3278 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3279 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3280 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3283 'loggedoff' => new external_single_structure(
3285 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3286 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3287 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3292 'Processors values for this notification'
3296 'List of notificaitons for the component'
3300 'Available components'
3307 * Returns description of method parameters
3309 * @return external_function_parameters
3312 public static function get_user_notification_preferences_parameters() {
3313 return new external_function_parameters(
3315 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3321 * Get the notification preferences for a given user.
3323 * @param int $userid id of the user, 0 for current user
3324 * @return external_description
3325 * @throws moodle_exception
3328 public static function get_user_notification_preferences($userid = 0) {
3331 $params = self::validate_parameters(
3332 self::get_user_notification_preferences_parameters(),
3334 'userid' => $userid,
3337 $user = self::validate_preferences_permissions($params['userid']);
3339 $processors = get_message_processors();
3340 $providers = message_get_providers_for_user($user->id);
3341 $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3342 $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3344 $renderer = $PAGE->get_renderer('core_message');
3347 'warnings' => array(),
3348 'preferences' => $notificationlist->export_for_template($renderer)
3354 * Returns description of method result value
3356 * @return external_description
3359 public static function get_user_notification_preferences_returns() {
3360 return new external_function_parameters(
3362 'preferences' => self::get_preferences_structure(),
3363 'warnings' => new external_warnings(),
3369 * Returns description of method parameters
3371 * @return external_function_parameters
3374 public static function get_user_message_preferences_parameters() {
3375 return new external_function_parameters(
3377 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3383 * Get the notification preferences for a given user.
3385 * @param int $userid id of the user, 0 for current user
3386 * @return external_description
3387 * @throws moodle_exception
3390 public static function get_user_message_preferences($userid = 0) {
3393 $params = self::validate_parameters(
3394 self::get_user_message_preferences_parameters(),
3396 'userid' => $userid,
3400 $user = self::validate_preferences_permissions($params['userid']);
3402 // Filter out enabled, available system_configured and user_configured processors only.
3403 $readyprocessors = array_filter(get_message_processors(), function($processor) {
3404 return $processor->enabled &&
3405 $processor->configured &&
3406 $processor->object->is_user_configured() &&
3407 // Filter out processors that don't have and message preferences to configure.
3408 $processor->object->has_message_preferences();