MDL-67673 phpunit: Introduce a new, lightweight phpunit_dataset
[moodle.git] / message / externallib.php
blobe8091734ea45577a372aeb89d5746062e49242ad
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
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.
8 //
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/>.
18 /**
19 * External message API
21 * @package core_message
22 * @category external
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");
32 /**
33 * Message external functions
35 * @package core_message
36 * @category external
37 * @copyright 2011 Jerome Mouneyrac
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 * @since Moodle 2.2
41 class core_message_external extends external_api {
42 /**
43 * Returns description of method parameters
45 * @return external_function_parameters
46 * @since Moodle 3.6
48 public static function send_messages_to_conversation_parameters() {
49 return new external_function_parameters(
50 array(
51 'conversationid' => new external_value(PARAM_INT, 'id of the conversation'),
52 'messages' => new external_multiple_structure(
53 new external_single_structure(
54 array(
55 'text' => new external_value(PARAM_RAW, 'the text of the message'),
56 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
64 /**
65 * Send messages from the current USER to a conversation.
67 * This conversation may be any type of conversation, individual or group.
69 * @param int $conversationid the id of the conversation to which the messages will be sent.
70 * @param array $messages An array of message to send.
71 * @return array the array of messages which were sent (created).
72 * @since Moodle 3.6
74 public static function send_messages_to_conversation(int $conversationid, array $messages = []) {
75 global $CFG, $USER;
77 // Check if messaging is enabled.
78 if (empty($CFG->messaging)) {
79 throw new moodle_exception('disabled', 'message');
82 // Ensure the current user is allowed to run this function.
83 $context = context_system::instance();
84 self::validate_context($context);
86 $params = self::validate_parameters(self::send_messages_to_conversation_parameters(), [
87 'conversationid' => $conversationid,
88 'messages' => $messages
89 ]);
91 $messages = [];
92 foreach ($params['messages'] as $message) {
93 $createdmessage = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
94 $message['textformat']);
95 $createdmessage->text = message_format_message_text((object) [
96 'smallmessage' => $createdmessage->text,
97 'fullmessageformat' => external_validate_format($message['textformat']),
98 'fullmessagetrust' => $createdmessage->fullmessagetrust
99 ]);
100 $messages[] = $createdmessage;
103 return $messages;
107 * Returns description of method result value.
109 * @return external_description
110 * @since Moodle 3.6
112 public static function send_messages_to_conversation_returns() {
113 return new external_multiple_structure(
114 self::get_conversation_message_structure()
120 * Returns description of method parameters
122 * @return external_function_parameters
123 * @since Moodle 2.2
125 public static function send_instant_messages_parameters() {
126 return new external_function_parameters(
127 array(
128 'messages' => new external_multiple_structure(
129 new external_single_structure(
130 array(
131 'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
132 'text' => new external_value(PARAM_RAW, 'the text of the message'),
133 'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
134 '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),
143 * Send private messages from the current USER to other users
145 * @param array $messages An array of message to send.
146 * @return array
147 * @since Moodle 2.2
149 public static function send_instant_messages($messages = array()) {
150 global $CFG, $USER, $DB;
152 // Check if messaging is enabled.
153 if (empty($CFG->messaging)) {
154 throw new moodle_exception('disabled', 'message');
157 // Ensure the current user is allowed to run this function
158 $context = context_system::instance();
159 self::validate_context($context);
160 require_capability('moodle/site:sendmessage', $context);
162 // Ensure the current user is allowed to delete message for everyone.
163 $candeletemessagesforallusers = has_capability('moodle/site:deleteanymessage', $context);
165 $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
167 //retrieve all tousers of the messages
168 $receivers = array();
169 foreach($params['messages'] as $message) {
170 $receivers[] = $message['touserid'];
172 list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
173 $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
175 $resultmessages = array();
176 $messageids = array();
177 foreach ($params['messages'] as $message) {
178 $resultmsg = array(); //the infos about the success of the operation
180 // We are going to do some checking.
181 // Code should match /messages/index.php checks.
182 $success = true;
184 // Check the user exists.
185 if (empty($tousers[$message['touserid']])) {
186 $success = false;
187 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
190 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
191 // Check if the recipient can be messaged by the sender.
192 if ($success && !\core_message\api::can_send_message($tousers[$message['touserid']]->id, $USER->id)) {
193 $success = false;
194 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
197 // Now we can send the message (at least try).
198 if ($success) {
199 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
200 $success = message_post_message($USER, $tousers[$message['touserid']],
201 $message['text'], external_validate_format($message['textformat']));
204 // Build the resultmsg.
205 if (isset($message['clientmsgid'])) {
206 $resultmsg['clientmsgid'] = $message['clientmsgid'];
208 if ($success) {
209 $resultmsg['msgid'] = $success;
210 $resultmsg['timecreated'] = time();
211 $resultmsg['candeletemessagesforallusers'] = $candeletemessagesforallusers;
212 $messageids[] = $success;
213 } else {
214 // WARNINGS: for backward compatibility we return this errormessage.
215 // We should have thrown exceptions as these errors prevent results to be returned.
216 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
217 $resultmsg['msgid'] = -1;
218 if (!isset($errormessage)) { // Nobody has set a message error or thrown an exception, let's set it.
219 $errormessage = get_string('messageundeliveredbynotificationsettings', 'error');
221 $resultmsg['errormessage'] = $errormessage;
224 $resultmessages[] = $resultmsg;
227 if (!empty($messageids)) {
228 $messagerecords = $DB->get_records_list(
229 'messages',
230 'id',
231 $messageids,
233 'id, conversationid, smallmessage, fullmessageformat, fullmessagetrust');
234 $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) {
235 $id = $resultmessage['msgid'];
236 $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null;
237 $resultmessage['useridfrom'] = $USER->id;
238 $resultmessage['text'] = message_format_message_text((object) [
239 'smallmessage' => $messagerecords[$id]->smallmessage,
240 'fullmessageformat' => external_validate_format($messagerecords[$id]->fullmessageformat),
241 'fullmessagetrust' => $messagerecords[$id]->fullmessagetrust
243 return $resultmessage;
244 }, $resultmessages);
247 return $resultmessages;
251 * Returns description of method result value
253 * @return external_description
254 * @since Moodle 2.2
256 public static function send_instant_messages_returns() {
257 return new external_multiple_structure(
258 new external_single_structure(
259 array(
260 'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds: id of the created message if it succeeded, -1 when failed'),
261 'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
262 'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL),
263 'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL),
264 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
265 'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
266 'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
267 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
268 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
275 * Delete contacts parameters description.
277 * @return external_function_parameters
278 * @since Moodle 2.5
280 public static function delete_contacts_parameters() {
281 return new external_function_parameters(
282 array(
283 'userids' => new external_multiple_structure(
284 new external_value(PARAM_INT, 'User ID'),
285 'List of user IDs'
287 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
288 current user', VALUE_DEFAULT, 0)
294 * Delete contacts.
296 * @param array $userids array of user IDs.
297 * @param int $userid The id of the user we are deleting the contacts for
298 * @return null
299 * @since Moodle 2.5
301 public static function delete_contacts($userids, $userid = 0) {
302 global $CFG, $USER;
304 // Check if messaging is enabled.
305 if (empty($CFG->messaging)) {
306 throw new moodle_exception('disabled', 'message');
309 if (empty($userid)) {
310 $userid = $USER->id;
313 // Validate context.
314 $context = context_system::instance();
315 self::validate_context($context);
317 $params = array('userids' => $userids, 'userid' => $userid);
318 $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
320 $capability = 'moodle/site:manageallmessaging';
321 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
322 throw new required_capability_exception($context, $capability, 'nopermissions', '');
325 foreach ($params['userids'] as $id) {
326 \core_message\api::remove_contact($params['userid'], $id);
329 return null;
333 * Delete contacts return description.
335 * @return external_description
336 * @since Moodle 2.5
338 public static function delete_contacts_returns() {
339 return null;
343 * Mute conversations parameters description.
345 * @return external_function_parameters
347 public static function mute_conversations_parameters() {
348 return new external_function_parameters(
350 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
351 'conversationids' => new external_multiple_structure(
352 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
359 * Mutes conversations.
361 * @param int $userid The id of the user who is blocking
362 * @param array $conversationids The list of conversations being muted
363 * @return external_description
365 public static function mute_conversations(int $userid, array $conversationids) {
366 global $CFG, $USER;
368 // Check if messaging is enabled.
369 if (empty($CFG->messaging)) {
370 throw new moodle_exception('disabled', 'message');
373 // Validate context.
374 $context = context_system::instance();
375 self::validate_context($context);
377 $params = ['userid' => $userid, 'conversationids' => $conversationids];
378 $params = self::validate_parameters(self::mute_conversations_parameters(), $params);
380 $capability = 'moodle/site:manageallmessaging';
381 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
382 throw new required_capability_exception($context, $capability, 'nopermissions', '');
385 foreach ($params['conversationids'] as $conversationid) {
386 if (!\core_message\api::is_conversation_muted($params['userid'], $conversationid)) {
387 \core_message\api::mute_conversation($params['userid'], $conversationid);
391 return [];
395 * Mute conversations return description.
397 * @return external_description
399 public static function mute_conversations_returns() {
400 return new external_warnings();
404 * Unmute conversations parameters description.
406 * @return external_function_parameters
408 public static function unmute_conversations_parameters() {
409 return new external_function_parameters(
411 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
412 'conversationids' => new external_multiple_structure(
413 new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
420 * Unmute conversations.
422 * @param int $userid The id of the user who is unblocking
423 * @param array $conversationids The list of conversations being muted
425 public static function unmute_conversations(int $userid, array $conversationids) {
426 global $CFG, $USER;
428 // Check if messaging is enabled.
429 if (empty($CFG->messaging)) {
430 throw new moodle_exception('disabled', 'message');
433 // Validate context.
434 $context = context_system::instance();
435 self::validate_context($context);
437 $params = ['userid' => $userid, 'conversationids' => $conversationids];
438 $params = self::validate_parameters(self::unmute_conversations_parameters(), $params);
440 $capability = 'moodle/site:manageallmessaging';
441 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
442 throw new required_capability_exception($context, $capability, 'nopermissions', '');
445 foreach ($params['conversationids'] as $conversationid) {
446 \core_message\api::unmute_conversation($params['userid'], $conversationid);
449 return [];
453 * Unmute conversations return description.
455 * @return external_description
457 public static function unmute_conversations_returns() {
458 return new external_warnings();
462 * Block user parameters description.
464 * @return external_function_parameters
466 public static function block_user_parameters() {
467 return new external_function_parameters(
469 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
470 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
476 * Blocks a user.
478 * @param int $userid The id of the user who is blocking
479 * @param int $blockeduserid The id of the user being blocked
480 * @return external_description
482 public static function block_user(int $userid, int $blockeduserid) {
483 global $CFG, $USER;
485 // Check if messaging is enabled.
486 if (empty($CFG->messaging)) {
487 throw new moodle_exception('disabled', 'message');
490 // Validate context.
491 $context = context_system::instance();
492 self::validate_context($context);
494 $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
495 $params = self::validate_parameters(self::block_user_parameters(), $params);
497 $capability = 'moodle/site:manageallmessaging';
498 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
499 throw new required_capability_exception($context, $capability, 'nopermissions', '');
502 // If the blocking is going to be useless then don't do it.
503 if (\core_message\api::can_send_message($userid, $blockeduserid, true)) {
504 return [];
507 if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
508 \core_message\api::block_user($params['userid'], $params['blockeduserid']);
511 return [];
515 * Block user return description.
517 * @return external_description
519 public static function block_user_returns() {
520 return new external_warnings();
524 * Unblock user parameters description.
526 * @return external_function_parameters
528 public static function unblock_user_parameters() {
529 return new external_function_parameters(
531 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
532 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
538 * Unblock user.
540 * @param int $userid The id of the user who is unblocking
541 * @param int $unblockeduserid The id of the user being unblocked
543 public static function unblock_user(int $userid, int $unblockeduserid) {
544 global $CFG, $USER;
546 // Check if messaging is enabled.
547 if (empty($CFG->messaging)) {
548 throw new moodle_exception('disabled', 'message');
551 // Validate context.
552 $context = context_system::instance();
553 self::validate_context($context);
555 $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
556 $params = self::validate_parameters(self::unblock_user_parameters(), $params);
558 $capability = 'moodle/site:manageallmessaging';
559 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
560 throw new required_capability_exception($context, $capability, 'nopermissions', '');
563 \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
565 return [];
569 * Unblock user return description.
571 * @return external_description
573 public static function unblock_user_returns() {
574 return new external_warnings();
578 * Returns contact requests parameters description.
580 * @return external_function_parameters
582 public static function get_contact_requests_parameters() {
583 return new external_function_parameters(
585 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
586 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
587 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
593 * Handles returning the contact requests for a user.
595 * This also includes the user data necessary to display information
596 * about the user.
598 * It will not include blocked users.
600 * @param int $userid The id of the user we want to get the contact requests for
601 * @param int $limitfrom
602 * @param int $limitnum
604 public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
605 global $CFG, $USER;
607 // Check if messaging is enabled.
608 if (empty($CFG->messaging)) {
609 throw new moodle_exception('disabled', 'message');
612 // Validate context.
613 $context = context_system::instance();
614 self::validate_context($context);
616 $params = [
617 'userid' => $userid,
618 'limitfrom' => $limitfrom,
619 'limitnum' => $limitnum
621 $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
623 $capability = 'moodle/site:manageallmessaging';
624 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
625 throw new required_capability_exception($context, $capability, 'nopermissions', '');
628 return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
632 * Returns the contact requests return description.
634 * @return external_description
636 public static function get_contact_requests_returns() {
637 return new external_multiple_structure(
638 self::get_conversation_member_structure()
643 * Returns the number of contact requests the user has received parameters description.
645 * @return external_function_parameters
647 public static function get_received_contact_requests_count_parameters() {
648 return new external_function_parameters(
649 array(
650 'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' .
651 'received contact requests for', VALUE_REQUIRED),
657 * Returns the number of contact requests the user has received.
659 * @param int $userid The ID of the user we want to return the number of received contact requests for
660 * @return external_value
662 public static function get_received_contact_requests_count(int $userid) {
663 global $CFG, $USER;
665 // Check if messaging is enabled.
666 if (empty($CFG->messaging)) {
667 throw new moodle_exception('disabled', 'message');
670 // Validate context.
671 $context = context_system::instance();
672 self::validate_context($context);
674 $params = [
675 'userid' => $userid,
677 $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params);
679 $capability = 'moodle/site:manageallmessaging';
680 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
681 throw new required_capability_exception($context, $capability, 'nopermissions', '');
684 return \core_message\api::get_received_contact_requests_count($params['userid']);
688 * Returns the number of contact requests the user has received return description.
690 * @return external_value
692 public static function get_received_contact_requests_count_returns() {
693 return new external_value(PARAM_INT, 'The number of received contact requests');
697 * Returns get conversation members parameters description.
699 * @return external_function_parameters
701 public static function get_conversation_members_parameters() {
702 return new external_function_parameters(
704 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
705 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
706 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
707 VALUE_DEFAULT, false),
708 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?',
709 VALUE_DEFAULT, false),
710 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
711 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
717 * Returns a list of conversation members.
719 * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
720 * @param int $conversationid The id of the conversation
721 * @param bool $includecontactrequests Do we want to include contact requests with this data?
722 * @param bool $includeprivacyinfo Do we want to include privacy info?
723 * @param int $limitfrom
724 * @param int $limitnum
725 * @return array
727 public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
728 bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) {
729 global $CFG, $USER;
731 // Check if messaging is enabled.
732 if (empty($CFG->messaging)) {
733 throw new moodle_exception('disabled', 'message');
736 // Validate context.
737 $context = context_system::instance();
738 self::validate_context($context);
740 $params = [
741 'userid' => $userid,
742 'conversationid' => $conversationid,
743 'includecontactrequests' => $includecontactrequests,
744 'includeprivacyinfo' => $includeprivacyinfo,
745 'limitfrom' => $limitfrom,
746 'limitnum' => $limitnum
748 $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
750 $capability = 'moodle/site:manageallmessaging';
751 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
752 throw new required_capability_exception($context, $capability, 'nopermissions', '');
755 // The user needs to be a part of the conversation before querying who the members are.
756 if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
757 throw new moodle_exception('You are not a member of this conversation.');
760 return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
761 $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']);
765 * Returns the get conversation members return description.
767 * @return external_description
769 public static function get_conversation_members_returns() {
770 return new external_multiple_structure(
771 self::get_conversation_member_structure()
776 * Creates a contact request parameters description.
778 * @return external_function_parameters
780 public static function create_contact_request_parameters() {
781 return new external_function_parameters(
783 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
784 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
790 * Creates a contact request.
792 * @param int $userid The id of the user who is creating the contact request
793 * @param int $requesteduserid The id of the user being requested
795 public static function create_contact_request(int $userid, int $requesteduserid) {
796 global $CFG, $USER;
798 // Check if messaging is enabled.
799 if (empty($CFG->messaging)) {
800 throw new moodle_exception('disabled', 'message');
803 // Validate context.
804 $context = context_system::instance();
805 self::validate_context($context);
807 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
808 $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
810 $capability = 'moodle/site:manageallmessaging';
811 if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
812 throw new required_capability_exception($context, $capability, 'nopermissions', '');
815 $result = [
816 'warnings' => []
819 if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
820 $result['warnings'][] = [
821 'item' => 'user',
822 'itemid' => $params['requesteduserid'],
823 'warningcode' => 'cannotcreatecontactrequest',
824 'message' => 'You are unable to create a contact request for this user'
826 } else {
827 if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
828 // There should only ever be one but just in case there are multiple then we can return the first.
829 $result['request'] = array_shift($requests);
830 } else {
831 $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
835 return $result;
839 * Creates a contact request return description.
841 * @return external_description
843 public static function create_contact_request_returns() {
844 return new external_single_structure(
845 array(
846 'request' => new external_single_structure(
847 array(
848 'id' => new external_value(PARAM_INT, 'Message id'),
849 'userid' => new external_value(PARAM_INT, 'User from id'),
850 'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
851 'timecreated' => new external_value(PARAM_INT, 'Time created'),
853 'request record',
854 VALUE_OPTIONAL
856 'warnings' => new external_warnings()
862 * Confirm a contact request parameters description.
864 * @return external_function_parameters
866 public static function confirm_contact_request_parameters() {
867 return new external_function_parameters(
869 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
870 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
876 * Confirm a contact request.
878 * @param int $userid The id of the user who is creating the contact request
879 * @param int $requesteduserid The id of the user being requested
881 public static function confirm_contact_request(int $userid, int $requesteduserid) {
882 global $CFG, $USER;
884 // Check if messaging is enabled.
885 if (empty($CFG->messaging)) {
886 throw new moodle_exception('disabled', 'message');
889 // Validate context.
890 $context = context_system::instance();
891 self::validate_context($context);
893 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
894 $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
896 $capability = 'moodle/site:manageallmessaging';
897 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
898 throw new required_capability_exception($context, $capability, 'nopermissions', '');
901 \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
903 return [];
907 * Confirm a contact request return description.
909 * @return external_description
911 public static function confirm_contact_request_returns() {
912 return new external_warnings();
916 * Declines a contact request parameters description.
918 * @return external_function_parameters
920 public static function decline_contact_request_parameters() {
921 return new external_function_parameters(
923 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
924 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
930 * Declines a contact request.
932 * @param int $userid The id of the user who is creating the contact request
933 * @param int $requesteduserid The id of the user being requested
935 public static function decline_contact_request(int $userid, int $requesteduserid) {
936 global $CFG, $USER;
938 // Check if messaging is enabled.
939 if (empty($CFG->messaging)) {
940 throw new moodle_exception('disabled', 'message');
943 // Validate context.
944 $context = context_system::instance();
945 self::validate_context($context);
947 $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
948 $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
950 $capability = 'moodle/site:manageallmessaging';
951 if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
952 throw new required_capability_exception($context, $capability, 'nopermissions', '');
955 \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
957 return [];
961 * Declines a contact request return description.
963 * @return external_description
965 public static function decline_contact_request_returns() {
966 return new external_warnings();
970 * Return the structure of a message area contact.
972 * @return external_single_structure
973 * @since Moodle 3.2
975 private static function get_messagearea_contact_structure() {
976 return new external_single_structure(
977 array(
978 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
979 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
980 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
981 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
982 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
983 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
984 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
985 'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null),
986 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
987 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
988 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
989 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
990 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
991 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
992 VALUE_DEFAULT, null),
993 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null),
999 * Return the structure of a conversation.
1001 * @return external_single_structure
1002 * @since Moodle 3.6
1004 private static function get_conversation_structure() {
1005 return new external_single_structure(
1006 array(
1007 'id' => new external_value(PARAM_INT, 'The conversation id'),
1008 'name' => new external_value(PARAM_RAW, 'The conversation name, if set', VALUE_DEFAULT, null),
1009 'subname' => new external_value(PARAM_RAW, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1010 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1011 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group,3=self)'),
1012 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1013 'ismuted' => new external_value(PARAM_BOOL, 'If the user muted this conversation'),
1014 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this conversation as a favourite'),
1015 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1016 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1017 VALUE_DEFAULT, null),
1018 'members' => new external_multiple_structure(
1019 self::get_conversation_member_structure()
1021 'messages' => new external_multiple_structure(
1022 self::get_conversation_message_structure()
1024 'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
1025 'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
1031 * Return the structure of a conversation member.
1033 * @return external_single_structure
1034 * @since Moodle 3.6
1036 private static function get_conversation_member_structure() {
1037 $result = [
1038 'id' => new external_value(PARAM_INT, 'The user id'),
1039 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1040 'profileurl' => new external_value(PARAM_URL, 'The link to the user\'s profile page'),
1041 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1042 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1043 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1044 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1045 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1046 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1047 'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1048 'canmessageevenifblocked' => new external_value(PARAM_BOOL,
1049 'If the user can still message even if they get blocked'),
1050 'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1051 'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1054 $result['contactrequests'] = new external_multiple_structure(
1055 new external_single_structure(
1057 'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1058 'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1059 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1060 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1062 ), 'The contact requests', VALUE_OPTIONAL
1065 $result['conversations'] = new external_multiple_structure(new external_single_structure(
1066 array(
1067 'id' => new external_value(PARAM_INT, 'Conversations id'),
1068 'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1069 'name' => new external_value(PARAM_RAW, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1070 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1071 ), 'information about conversation', VALUE_OPTIONAL),
1072 'Conversations between users', VALUE_OPTIONAL
1075 return new external_single_structure(
1076 $result
1081 * Return the structure of a message area message.
1083 * @return external_single_structure
1084 * @since Moodle 3.6
1086 private static function get_conversation_message_structure() {
1087 return new external_single_structure(
1088 array(
1089 'id' => new external_value(PARAM_INT, 'The id of the message'),
1090 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1091 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1092 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1098 * Get messagearea message search users parameters.
1100 * @return external_function_parameters
1101 * @since 3.6
1103 public static function message_search_users_parameters() {
1104 return new external_function_parameters(
1105 array(
1106 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1107 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1108 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1109 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1115 * Get search users results.
1117 * @param int $userid The id of the user who is performing the search
1118 * @param string $search The string being searched
1119 * @param int $limitfrom
1120 * @param int $limitnum
1121 * @return array
1122 * @throws moodle_exception
1123 * @since 3.6
1125 public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1126 global $USER;
1128 $systemcontext = context_system::instance();
1130 $params = array(
1131 'userid' => $userid,
1132 'search' => $search,
1133 'limitfrom' => $limitfrom,
1134 'limitnum' => $limitnum
1136 $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1137 self::validate_context($systemcontext);
1139 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1140 throw new moodle_exception('You do not have permission to perform this action.');
1143 list($contacts, $noncontacts) = \core_message\api::message_search_users(
1144 $params['userid'],
1145 $params['search'],
1146 $params['limitfrom'],
1147 $params['limitnum']);
1149 return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1153 * Get messagearea message search users returns.
1155 * @return external_single_structure
1156 * @since 3.2
1158 public static function message_search_users_returns() {
1159 return new external_single_structure(
1160 array(
1161 'contacts' => new external_multiple_structure(
1162 self::get_conversation_member_structure()
1164 'noncontacts' => new external_multiple_structure(
1165 self::get_conversation_member_structure()
1172 * Get messagearea search messages parameters.
1174 * @return external_function_parameters
1175 * @since 3.2
1177 public static function data_for_messagearea_search_messages_parameters() {
1178 return new external_function_parameters(
1179 array(
1180 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1181 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1182 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1183 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1189 * Get messagearea search messages results.
1191 * @param int $userid The id of the user who is performing the search
1192 * @param string $search The string being searched
1193 * @param int $limitfrom
1194 * @param int $limitnum
1195 * @return stdClass
1196 * @throws moodle_exception
1197 * @since 3.2
1199 public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1200 global $CFG, $USER;
1202 // Check if messaging is enabled.
1203 if (empty($CFG->messaging)) {
1204 throw new moodle_exception('disabled', 'message');
1207 $systemcontext = context_system::instance();
1209 $params = array(
1210 'userid' => $userid,
1211 'search' => $search,
1212 'limitfrom' => $limitfrom,
1213 'limitnum' => $limitnum
1216 $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1217 self::validate_context($systemcontext);
1219 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1220 throw new moodle_exception('You do not have permission to perform this action.');
1223 $messages = \core_message\api::search_messages(
1224 $params['userid'],
1225 $params['search'],
1226 $params['limitfrom'],
1227 $params['limitnum']
1230 $data = new \stdClass();
1231 $data->contacts = [];
1232 foreach ($messages as $message) {
1233 $contact = new \stdClass();
1234 $contact->userid = $message->userid;
1235 $contact->fullname = $message->fullname;
1236 $contact->profileimageurl = $message->profileimageurl;
1237 $contact->profileimageurlsmall = $message->profileimageurlsmall;
1238 $contact->messageid = $message->messageid;
1239 $contact->ismessaging = $message->ismessaging;
1240 $contact->sentfromcurrentuser = false;
1241 if ($message->lastmessage) {
1242 if ($message->userid !== $message->useridfrom) {
1243 $contact->sentfromcurrentuser = true;
1245 $contact->lastmessage = shorten_text($message->lastmessage, 60);
1246 } else {
1247 $contact->lastmessage = null;
1249 $contact->lastmessagedate = $message->lastmessagedate;
1250 $contact->showonlinestatus = is_null($message->isonline) ? false : true;
1251 $contact->isonline = $message->isonline;
1252 $contact->isblocked = $message->isblocked;
1253 $contact->isread = $message->isread;
1254 $contact->unreadcount = $message->unreadcount;
1255 $contact->conversationid = $message->conversationid;
1257 $data->contacts[] = $contact;
1260 return $data;
1264 * Get messagearea search messages returns.
1266 * @return external_single_structure
1267 * @since 3.2
1269 public static function data_for_messagearea_search_messages_returns() {
1270 return new external_single_structure(
1271 array(
1272 'contacts' => new external_multiple_structure(
1273 self::get_messagearea_contact_structure()
1280 * Get conversations parameters.
1282 * @return external_function_parameters
1283 * @since 3.6
1285 public static function get_conversations_parameters() {
1286 return new external_function_parameters(
1287 array(
1288 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1289 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1290 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1291 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1292 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1293 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1294 VALUE_DEFAULT, null),
1295 'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private
1296 conversations (false) when private conversations are requested.',
1297 VALUE_DEFAULT, false),
1303 * Get the list of conversations for the user.
1305 * @param int $userid The id of the user who is performing the search
1306 * @param int $limitfrom
1307 * @param int $limitnum
1308 * @param int|null $type
1309 * @param bool|null $favourites
1310 * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false)
1311 * when private conversations are requested.
1312 * @return stdClass
1313 * @throws \moodle_exception if the messaging feature is disabled on the site.
1314 * @since 3.2
1316 public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null,
1317 bool $mergeself = false) {
1318 global $CFG, $USER;
1320 // All the standard BL checks.
1321 if (empty($CFG->messaging)) {
1322 throw new moodle_exception('disabled', 'message');
1325 $params = array(
1326 'userid' => $userid,
1327 'limitfrom' => $limitfrom,
1328 'limitnum' => $limitnum,
1329 'type' => $type,
1330 'favourites' => $favourites,
1331 'mergeself' => $mergeself
1333 $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1335 $systemcontext = context_system::instance();
1336 self::validate_context($systemcontext);
1338 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1339 throw new moodle_exception('You do not have permission to perform this action.');
1342 $conversations = \core_message\api::get_conversations(
1343 $params['userid'],
1344 $params['limitfrom'],
1345 $params['limitnum'],
1346 $params['type'],
1347 $params['favourites'],
1348 $params['mergeself']
1351 return (object) ['conversations' => $conversations];
1355 * Get conversations returns.
1357 * @return external_single_structure
1358 * @since 3.6
1360 public static function get_conversations_returns() {
1361 return new external_single_structure(
1363 'conversations' => new external_multiple_structure(
1364 self::get_conversation_structure(true)
1371 * Get conversation parameters.
1373 * @return external_function_parameters
1375 public static function get_conversation_parameters() {
1376 return new external_function_parameters(
1377 array(
1378 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1379 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1380 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1381 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1382 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1383 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1384 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1385 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1386 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1392 * Get a single conversation.
1394 * @param int $userid The user id to get the conversation for
1395 * @param int $conversationid The id of the conversation to fetch
1396 * @param bool $includecontactrequests Should contact requests be included between members
1397 * @param bool $includeprivacyinfo Should privacy info be included between members
1398 * @param int $memberlimit Limit number of members to load
1399 * @param int $memberoffset Offset members by this amount
1400 * @param int $messagelimit Limit number of messages to load
1401 * @param int $messageoffset Offset the messages
1402 * @param bool $newestmessagesfirst Order messages by newest first
1403 * @return stdClass
1404 * @throws \moodle_exception if the messaging feature is disabled on the site.
1406 public static function get_conversation(
1407 int $userid,
1408 int $conversationid,
1409 bool $includecontactrequests = false,
1410 bool $includeprivacyinfo = false,
1411 int $memberlimit = 0,
1412 int $memberoffset = 0,
1413 int $messagelimit = 0,
1414 int $messageoffset = 0,
1415 bool $newestmessagesfirst = true
1417 global $CFG, $DB, $USER;
1419 // All the standard BL checks.
1420 if (empty($CFG->messaging)) {
1421 throw new moodle_exception('disabled', 'message');
1424 $params = [
1425 'userid' => $userid,
1426 'conversationid' => $conversationid,
1427 'includecontactrequests' => $includecontactrequests,
1428 'includeprivacyinfo' => $includeprivacyinfo,
1429 'memberlimit' => $memberlimit,
1430 'memberoffset' => $memberoffset,
1431 'messagelimit' => $messagelimit,
1432 'messageoffset' => $messageoffset,
1433 'newestmessagesfirst' => $newestmessagesfirst
1435 self::validate_parameters(self::get_conversation_parameters(), $params);
1437 $systemcontext = context_system::instance();
1438 self::validate_context($systemcontext);
1440 $conversation = \core_message\api::get_conversation(
1441 $params['userid'],
1442 $params['conversationid'],
1443 $params['includecontactrequests'],
1444 $params['includeprivacyinfo'],
1445 $params['memberlimit'],
1446 $params['memberoffset'],
1447 $params['messagelimit'],
1448 $params['messageoffset'],
1449 $params['newestmessagesfirst']
1452 if ($conversation) {
1453 return $conversation;
1454 } else {
1455 // We have to throw an exception here because the external functions annoyingly
1456 // don't accept null to be returned for a single structure.
1457 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1462 * Get conversation returns.
1464 * @return external_single_structure
1466 public static function get_conversation_returns() {
1467 return self::get_conversation_structure();
1471 * Get conversation parameters.
1473 * @return external_function_parameters
1475 public static function get_conversation_between_users_parameters() {
1476 return new external_function_parameters(
1477 array(
1478 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1479 'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1480 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1481 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1482 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1483 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1484 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1485 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1486 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1492 * Get a single conversation between users.
1494 * @param int $userid The user id to get the conversation for
1495 * @param int $otheruserid The other user id
1496 * @param bool $includecontactrequests Should contact requests be included between members
1497 * @param bool $includeprivacyinfo Should privacy info be included between members
1498 * @param int $memberlimit Limit number of members to load
1499 * @param int $memberoffset Offset members by this amount
1500 * @param int $messagelimit Limit number of messages to load
1501 * @param int $messageoffset Offset the messages
1502 * @param bool $newestmessagesfirst Order messages by newest first
1503 * @return stdClass
1504 * @throws \moodle_exception if the messaging feature is disabled on the site.
1506 public static function get_conversation_between_users(
1507 int $userid,
1508 int $otheruserid,
1509 bool $includecontactrequests = false,
1510 bool $includeprivacyinfo = false,
1511 int $memberlimit = 0,
1512 int $memberoffset = 0,
1513 int $messagelimit = 0,
1514 int $messageoffset = 0,
1515 bool $newestmessagesfirst = true
1517 global $CFG, $DB, $USER;
1519 // All the standard BL checks.
1520 if (empty($CFG->messaging)) {
1521 throw new moodle_exception('disabled', 'message');
1524 $params = [
1525 'userid' => $userid,
1526 'otheruserid' => $otheruserid,
1527 'includecontactrequests' => $includecontactrequests,
1528 'includeprivacyinfo' => $includeprivacyinfo,
1529 'memberlimit' => $memberlimit,
1530 'memberoffset' => $memberoffset,
1531 'messagelimit' => $messagelimit,
1532 'messageoffset' => $messageoffset,
1533 'newestmessagesfirst' => $newestmessagesfirst
1535 self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
1537 $systemcontext = context_system::instance();
1538 self::validate_context($systemcontext);
1540 $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
1541 $conversation = null;
1543 if ($conversationid) {
1544 $conversation = \core_message\api::get_conversation(
1545 $params['userid'],
1546 $conversationid,
1547 $params['includecontactrequests'],
1548 $params['includeprivacyinfo'],
1549 $params['memberlimit'],
1550 $params['memberoffset'],
1551 $params['messagelimit'],
1552 $params['messageoffset'],
1553 $params['newestmessagesfirst']
1557 if ($conversation) {
1558 return $conversation;
1559 } else {
1560 // We have to throw an exception here because the external functions annoyingly
1561 // don't accept null to be returned for a single structure.
1562 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1567 * Get conversation returns.
1569 * @return external_single_structure
1571 public static function get_conversation_between_users_returns() {
1572 return self::get_conversation_structure(true);
1576 * Get self-conversation parameters.
1578 * @return external_function_parameters
1580 public static function get_self_conversation_parameters() {
1581 return new external_function_parameters(
1582 array(
1583 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'),
1584 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1585 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1586 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1592 * Get a single self-conversation.
1594 * @param int $userid The user id to get the self-conversation for
1595 * @param int $messagelimit Limit number of messages to load
1596 * @param int $messageoffset Offset the messages
1597 * @param bool $newestmessagesfirst Order messages by newest first
1598 * @return stdClass
1599 * @throws \moodle_exception if the messaging feature is disabled on the site.
1600 * @since Moodle 3.7
1602 public static function get_self_conversation(
1603 int $userid,
1604 int $messagelimit = 0,
1605 int $messageoffset = 0,
1606 bool $newestmessagesfirst = true
1608 global $CFG;
1610 // All the standard BL checks.
1611 if (empty($CFG->messaging)) {
1612 throw new moodle_exception('disabled', 'message');
1615 $params = [
1616 'userid' => $userid,
1617 'messagelimit' => $messagelimit,
1618 'messageoffset' => $messageoffset,
1619 'newestmessagesfirst' => $newestmessagesfirst
1621 self::validate_parameters(self::get_self_conversation_parameters(), $params);
1623 $systemcontext = context_system::instance();
1624 self::validate_context($systemcontext);
1626 $conversation = \core_message\api::get_self_conversation($params['userid']);
1628 if ($conversation) {
1629 $conversation = \core_message\api::get_conversation(
1630 $params['userid'],
1631 $conversation->id,
1632 false,
1633 false,
1636 $params['messagelimit'],
1637 $params['messageoffset'],
1638 $params['newestmessagesfirst']
1642 if ($conversation) {
1643 return $conversation;
1644 } else {
1645 // We have to throw an exception here because the external functions annoyingly
1646 // don't accept null to be returned for a single structure.
1647 throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1652 * Get conversation returns.
1654 * @return external_single_structure
1656 public static function get_self_conversation_returns() {
1657 return self::get_conversation_structure();
1661 * The conversation messages parameters.
1663 * @return external_function_parameters
1664 * @since 3.6
1666 public static function get_conversation_messages_parameters() {
1667 return new external_function_parameters(
1668 array(
1669 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1670 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1671 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1672 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1673 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1674 'timefrom' => new external_value(PARAM_INT,
1675 'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1681 * Get conversation messages.
1683 * @param int $currentuserid The current user's id.
1684 * @param int $convid The conversation id.
1685 * @param int $limitfrom Return a subset of records, starting at this point (optional).
1686 * @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1687 * @param bool $newest True for getting first newest messages, false otherwise.
1688 * @param int $timefrom The time from the conversation messages to get.
1689 * @return array The messages and members who have sent some of these messages.
1690 * @throws moodle_exception
1691 * @since 3.6
1693 public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1694 bool $newest = false, int $timefrom = 0) {
1695 global $CFG, $USER;
1697 // Check if messaging is enabled.
1698 if (empty($CFG->messaging)) {
1699 throw new moodle_exception('disabled', 'message');
1702 $systemcontext = context_system::instance();
1704 $params = array(
1705 'currentuserid' => $currentuserid,
1706 'convid' => $convid,
1707 'limitfrom' => $limitfrom,
1708 'limitnum' => $limitnum,
1709 'newest' => $newest,
1710 'timefrom' => $timefrom,
1712 $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1713 self::validate_context($systemcontext);
1715 if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1716 throw new moodle_exception('You do not have permission to perform this action.');
1719 // Check that the user belongs to the conversation.
1720 if (!\core_message\api::is_user_in_conversation($params['currentuserid'], $params['convid'])) {
1721 throw new moodle_exception('User is not part of conversation.');
1724 $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1726 // We need to enforce a one second delay on messages to avoid race conditions of current
1727 // messages still being sent.
1729 // There is a chance that we could request messages before the current time's
1730 // second has elapsed and while other messages are being sent in that same second. In which
1731 // case those messages will be lost.
1733 // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1734 $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1736 // No requesting messages from the current time, as stated above.
1737 if ($params['timefrom'] == time()) {
1738 $messages = [];
1739 } else {
1740 $messages = \core_message\api::get_conversation_messages(
1741 $params['currentuserid'],
1742 $params['convid'],
1743 $params['limitfrom'],
1744 $params['limitnum'],
1745 $sort,
1746 $params['timefrom'],
1747 $timeto);
1750 return $messages;
1754 * The messagearea messages return structure.
1756 * @return external_single_structure
1757 * @since 3.6
1759 public static function get_conversation_messages_returns() {
1760 return new external_single_structure(
1761 array(
1762 'id' => new external_value(PARAM_INT, 'The conversation id'),
1763 'members' => new external_multiple_structure(
1764 self::get_conversation_member_structure()
1766 'messages' => new external_multiple_structure(
1767 self::get_conversation_message_structure()
1774 * The user contacts return parameters.
1776 * @return external_function_parameters
1778 public static function get_user_contacts_parameters() {
1779 return new external_function_parameters(
1780 array(
1781 'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
1782 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1783 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1789 * Get user contacts.
1791 * @param int $userid The id of the user who we are viewing conversations for
1792 * @param int $limitfrom
1793 * @param int $limitnum
1794 * @return array
1795 * @throws moodle_exception
1797 public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
1798 global $CFG, $USER;
1800 // Check if messaging is enabled.
1801 if (empty($CFG->messaging)) {
1802 throw new moodle_exception('disabled', 'message');
1805 $systemcontext = context_system::instance();
1807 $params = array(
1808 'userid' => $userid,
1809 'limitfrom' => $limitfrom,
1810 'limitnum' => $limitnum
1812 $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
1813 self::validate_context($systemcontext);
1815 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1816 throw new moodle_exception('You do not have permission to perform this action.');
1819 return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1823 * The user contacts return structure.
1825 * @return external_multiple_structure
1827 public static function get_user_contacts_returns() {
1828 return new external_multiple_structure(
1829 self::get_conversation_member_structure()
1834 * Search contacts parameters description.
1836 * @return external_function_parameters
1837 * @since Moodle 2.5
1839 public static function search_contacts_parameters() {
1840 return new external_function_parameters(
1841 array(
1842 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1843 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1844 VALUE_DEFAULT, false)
1850 * Search contacts.
1852 * @param string $searchtext query string.
1853 * @param bool $onlymycourses limit the search to the user's courses only.
1854 * @return external_description
1855 * @since Moodle 2.5
1857 public static function search_contacts($searchtext, $onlymycourses = false) {
1858 global $CFG, $USER, $PAGE;
1859 require_once($CFG->dirroot . '/user/lib.php');
1861 // Check if messaging is enabled.
1862 if (empty($CFG->messaging)) {
1863 throw new moodle_exception('disabled', 'message');
1866 require_once($CFG->libdir . '/enrollib.php');
1868 $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1869 $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1871 // Extra validation, we do not allow empty queries.
1872 if ($params['searchtext'] === '') {
1873 throw new moodle_exception('querystringcannotbeempty');
1876 $courseids = array();
1877 if ($params['onlymycourses']) {
1878 $mycourses = enrol_get_my_courses(array('id'));
1879 foreach ($mycourses as $mycourse) {
1880 $courseids[] = $mycourse->id;
1882 } else {
1883 $courseids[] = SITEID;
1886 // Retrieving the users matching the query.
1887 $users = message_search_users($courseids, $params['searchtext']);
1888 $results = array();
1889 foreach ($users as $user) {
1890 $results[$user->id] = $user;
1893 // Reorganising information.
1894 foreach ($results as &$user) {
1895 $newuser = array(
1896 'id' => $user->id,
1897 'fullname' => fullname($user)
1900 // Avoid undefined property notice as phone not specified.
1901 $user->phone1 = null;
1902 $user->phone2 = null;
1904 $userpicture = new user_picture($user);
1905 $userpicture->size = 1; // Size f1.
1906 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1907 $userpicture->size = 0; // Size f2.
1908 $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1910 $user = $newuser;
1913 return $results;
1917 * Search contacts return description.
1919 * @return external_description
1920 * @since Moodle 2.5
1922 public static function search_contacts_returns() {
1923 return new external_multiple_structure(
1924 new external_single_structure(
1925 array(
1926 'id' => new external_value(PARAM_INT, 'User ID'),
1927 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1928 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1929 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1932 'List of contacts'
1937 * Get messages parameters description.
1939 * @return external_function_parameters
1940 * @since 2.8
1942 public static function get_messages_parameters() {
1943 return new external_function_parameters(
1944 array(
1945 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1946 'useridfrom' => new external_value(
1947 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1948 VALUE_DEFAULT, 0),
1949 'type' => new external_value(
1950 PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1951 VALUE_DEFAULT, 'both'),
1952 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
1953 'newestfirst' => new external_value(
1954 PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1955 VALUE_DEFAULT, true),
1956 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1957 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1963 * Get messages function implementation.
1965 * @since 2.8
1966 * @throws invalid_parameter_exception
1967 * @throws moodle_exception
1968 * @param int $useridto the user id who received the message
1969 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
1970 * @param string $type type of message to return, expected values: notifications, conversations and both
1971 * @param bool $read true for retreiving read messages, false for unread
1972 * @param bool $newestfirst true for ordering by newest first, false for oldest first
1973 * @param int $limitfrom limit from
1974 * @param int $limitnum limit num
1975 * @return external_description
1977 public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
1978 $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
1979 global $CFG, $USER;
1981 $warnings = array();
1983 $params = array(
1984 'useridto' => $useridto,
1985 'useridfrom' => $useridfrom,
1986 'type' => $type,
1987 'read' => $read,
1988 'newestfirst' => $newestfirst,
1989 'limitfrom' => $limitfrom,
1990 'limitnum' => $limitnum
1993 $params = self::validate_parameters(self::get_messages_parameters(), $params);
1995 $context = context_system::instance();
1996 self::validate_context($context);
1998 $useridto = $params['useridto'];
1999 $useridfrom = $params['useridfrom'];
2000 $type = $params['type'];
2001 $read = $params['read'];
2002 $newestfirst = $params['newestfirst'];
2003 $limitfrom = $params['limitfrom'];
2004 $limitnum = $params['limitnum'];
2006 $allowedvalues = array('notifications', 'conversations', 'both');
2007 if (!in_array($type, $allowedvalues)) {
2008 throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2009 'allowed values are: ' . implode(',', $allowedvalues));
2012 // Check if private messaging between users is allowed.
2013 if (empty($CFG->messaging)) {
2014 // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2015 if ($type == "conversations") {
2016 throw new moodle_exception('disabled', 'message');
2018 if ($type == "both") {
2019 $warning = array();
2020 $warning['item'] = 'message';
2021 $warning['itemid'] = $USER->id;
2022 $warning['warningcode'] = '1';
2023 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2024 Only notifications will be returned';
2025 $warnings[] = $warning;
2029 if (!empty($useridto)) {
2030 if (core_user::is_real_user($useridto)) {
2031 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2032 } else {
2033 throw new moodle_exception('invaliduser');
2037 if (!empty($useridfrom)) {
2038 // We use get_user here because the from user can be the noreply or support user.
2039 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2042 // Check if the current user is the sender/receiver or just a privileged user.
2043 if ($useridto != $USER->id and $useridfrom != $USER->id and
2044 !has_capability('moodle/site:readallmessages', $context)) {
2045 throw new moodle_exception('accessdenied', 'admin');
2048 // Which type of messages to retrieve.
2049 $notifications = -1;
2050 if ($type != 'both') {
2051 $notifications = ($type == 'notifications') ? 1 : 0;
2054 $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2055 $sort = "mr.timecreated $orderdirection";
2057 if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2058 $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2060 // In some cases, we don't need to get the to/from user objects from the sql query.
2061 $userfromfullname = '';
2062 $usertofullname = '';
2064 // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2065 if (!empty($useridto)) {
2066 $usertofullname = fullname($userto, $canviewfullname);
2067 // The user from may or may not be filled.
2068 if (!empty($useridfrom)) {
2069 $userfromfullname = fullname($userfrom, $canviewfullname);
2071 } else {
2072 // If the useridto field is empty, the useridfrom must be filled.
2073 $userfromfullname = fullname($userfrom, $canviewfullname);
2075 foreach ($messages as $mid => $message) {
2077 // Do not return deleted messages.
2078 if (!$message->notification) {
2079 if (($useridto == $USER->id and $message->timeusertodeleted) or
2080 ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2081 unset($messages[$mid]);
2082 continue;
2086 // We need to get the user from the query.
2087 if (empty($userfromfullname)) {
2088 // Check for non-reply and support users.
2089 if (core_user::is_real_user($message->useridfrom)) {
2090 $user = new stdClass();
2091 $user = username_load_fields_from_object($user, $message, 'userfrom');
2092 $message->userfromfullname = fullname($user, $canviewfullname);
2093 } else {
2094 $user = core_user::get_user($message->useridfrom);
2095 $message->userfromfullname = fullname($user, $canviewfullname);
2097 } else {
2098 $message->userfromfullname = $userfromfullname;
2101 // We need to get the user from the query.
2102 if (empty($usertofullname)) {
2103 $user = new stdClass();
2104 $user = username_load_fields_from_object($user, $message, 'userto');
2105 $message->usertofullname = fullname($user, $canviewfullname);
2106 } else {
2107 $message->usertofullname = $usertofullname;
2110 $message->text = message_format_message_text($message);
2111 $messages[$mid] = (array) $message;
2115 $results = array(
2116 'messages' => $messages,
2117 'warnings' => $warnings
2120 return $results;
2124 * Get messages return description.
2126 * @return external_single_structure
2127 * @since 2.8
2129 public static function get_messages_returns() {
2130 return new external_single_structure(
2131 array(
2132 'messages' => new external_multiple_structure(
2133 new external_single_structure(
2134 array(
2135 'id' => new external_value(PARAM_INT, 'Message id'),
2136 'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2137 'useridto' => new external_value(PARAM_INT, 'User to id'),
2138 'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2139 'text' => new external_value(PARAM_RAW, 'The message text formated'),
2140 'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2141 'fullmessageformat' => new external_format_value('fullmessage'),
2142 'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2143 'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2144 'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2145 'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2146 'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2147 'timecreated' => new external_value(PARAM_INT, 'Time created'),
2148 'timeread' => new external_value(PARAM_INT, 'Time read'),
2149 'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2150 'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
2151 'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
2152 VALUE_OPTIONAL),
2153 'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
2154 'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
2155 The data here is serialised using json_encode().', VALUE_OPTIONAL),
2156 ), 'message'
2159 'warnings' => new external_warnings()
2165 * Mark all notifications as read parameters description.
2167 * @return external_function_parameters
2168 * @since 3.2
2170 public static function mark_all_notifications_as_read_parameters() {
2171 return new external_function_parameters(
2172 array(
2173 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2174 'useridfrom' => new external_value(
2175 PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2176 VALUE_DEFAULT, 0),
2177 'timecreatedto' => new external_value(
2178 PARAM_INT, 'mark messages created before this time as read, 0 for all messages',
2179 VALUE_DEFAULT, 0),
2185 * Mark all notifications as read function.
2187 * @since 3.2
2188 * @throws invalid_parameter_exception
2189 * @throws moodle_exception
2190 * @param int $useridto the user id who received the message
2191 * @param int $useridfrom the user id who send the message. -10 or -20 for no-reply or support user
2192 * @param int $timecreatedto mark message created before this time as read, 0 for all messages
2193 * @return external_description
2195 public static function mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto = 0) {
2196 global $USER;
2198 $params = self::validate_parameters(
2199 self::mark_all_notifications_as_read_parameters(),
2200 array(
2201 'useridto' => $useridto,
2202 'useridfrom' => $useridfrom,
2203 'timecreatedto' => $timecreatedto,
2207 $context = context_system::instance();
2208 self::validate_context($context);
2210 $useridto = $params['useridto'];
2211 $useridfrom = $params['useridfrom'];
2212 $timecreatedto = $params['timecreatedto'];
2214 if (!empty($useridto)) {
2215 if (core_user::is_real_user($useridto)) {
2216 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2217 } else {
2218 throw new moodle_exception('invaliduser');
2222 if (!empty($useridfrom)) {
2223 // We use get_user here because the from user can be the noreply or support user.
2224 $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2227 // Check if the current user is the sender/receiver or just a privileged user.
2228 if ($useridto != $USER->id and $useridfrom != $USER->id and
2229 // The deleteanymessage cap seems more reasonable here than readallmessages.
2230 !has_capability('moodle/site:deleteanymessage', $context)) {
2231 throw new moodle_exception('accessdenied', 'admin');
2234 \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto);
2236 return true;
2240 * Mark all notifications as read return description.
2242 * @return external_single_structure
2243 * @since 3.2
2245 public static function mark_all_notifications_as_read_returns() {
2246 return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2250 * Get unread conversations count parameters description.
2252 * @return external_function_parameters
2253 * @since 3.2
2255 public static function get_unread_conversations_count_parameters() {
2256 return new external_function_parameters(
2257 array(
2258 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2264 * Get unread messages count function.
2266 * @since 3.2
2267 * @throws invalid_parameter_exception
2268 * @throws moodle_exception
2269 * @param int $useridto the user id who received the message
2270 * @return external_description
2272 public static function get_unread_conversations_count($useridto) {
2273 global $USER, $CFG;
2275 // Check if messaging is enabled.
2276 if (empty($CFG->messaging)) {
2277 throw new moodle_exception('disabled', 'message');
2280 $params = self::validate_parameters(
2281 self::get_unread_conversations_count_parameters(),
2282 array('useridto' => $useridto)
2285 $context = context_system::instance();
2286 self::validate_context($context);
2288 $useridto = $params['useridto'];
2290 if (!empty($useridto)) {
2291 if (core_user::is_real_user($useridto)) {
2292 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2293 } else {
2294 throw new moodle_exception('invaliduser');
2296 } else {
2297 $useridto = $USER->id;
2300 // Check if the current user is the receiver or just a privileged user.
2301 if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2302 throw new moodle_exception('accessdenied', 'admin');
2305 return \core_message\api::count_unread_conversations($userto);
2309 * Get unread conversations count return description.
2311 * @return external_single_structure
2312 * @since 3.2
2314 public static function get_unread_conversations_count_returns() {
2315 return new external_value(PARAM_INT, 'The count of unread messages for the user');
2319 * Get blocked users parameters description.
2321 * @return external_function_parameters
2322 * @since 2.9
2324 public static function get_blocked_users_parameters() {
2325 return new external_function_parameters(
2326 array(
2327 'userid' => new external_value(PARAM_INT,
2328 'the user whose blocked users we want to retrieve',
2329 VALUE_REQUIRED),
2335 * Retrieve a list of users blocked
2337 * @param int $userid the user whose blocked users we want to retrieve
2338 * @return external_description
2339 * @since 2.9
2341 public static function get_blocked_users($userid) {
2342 global $CFG, $USER, $PAGE;
2344 // Warnings array, it can be empty at the end but is mandatory.
2345 $warnings = array();
2347 // Validate params.
2348 $params = array(
2349 'userid' => $userid
2351 $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2352 $userid = $params['userid'];
2354 // Validate context.
2355 $context = context_system::instance();
2356 self::validate_context($context);
2358 // Check if private messaging between users is allowed.
2359 if (empty($CFG->messaging)) {
2360 throw new moodle_exception('disabled', 'message');
2363 $user = core_user::get_user($userid, '*', MUST_EXIST);
2364 core_user::require_active_user($user);
2366 // Check if we have permissions for retrieve the information.
2367 $capability = 'moodle/site:manageallmessaging';
2368 if (($USER->id != $userid) && !has_capability($capability, $context)) {
2369 throw new required_capability_exception($context, $capability, 'nopermissions', '');
2372 // Now, we can get safely all the blocked users.
2373 $users = \core_message\api::get_blocked_users($user->id);
2375 $blockedusers = array();
2376 foreach ($users as $user) {
2377 $newuser = array(
2378 'id' => $user->id,
2379 'fullname' => fullname($user),
2382 $userpicture = new user_picture($user);
2383 $userpicture->size = 1; // Size f1.
2384 $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2386 $blockedusers[] = $newuser;
2389 $results = array(
2390 'users' => $blockedusers,
2391 'warnings' => $warnings
2393 return $results;
2397 * Get blocked users return description.
2399 * @return external_single_structure
2400 * @since 2.9
2402 public static function get_blocked_users_returns() {
2403 return new external_single_structure(
2404 array(
2405 'users' => new external_multiple_structure(
2406 new external_single_structure(
2407 array(
2408 'id' => new external_value(PARAM_INT, 'User ID'),
2409 'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2410 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2413 'List of blocked users'
2415 'warnings' => new external_warnings()
2421 * Returns description of method parameters
2423 * @return external_function_parameters
2424 * @since 2.9
2426 public static function mark_message_read_parameters() {
2427 return new external_function_parameters(
2428 array(
2429 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2430 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2431 VALUE_DEFAULT, 0)
2437 * Mark a single message as read, trigger message_viewed event
2439 * @param int $messageid id of the message (in the message table)
2440 * @param int $timeread timestamp for when the message should be marked read
2441 * @return external_description
2442 * @throws invalid_parameter_exception
2443 * @throws moodle_exception
2444 * @since 2.9
2446 public static function mark_message_read($messageid, $timeread) {
2447 global $CFG, $DB, $USER;
2449 // Check if private messaging between users is allowed.
2450 if (empty($CFG->messaging)) {
2451 throw new moodle_exception('disabled', 'message');
2454 // Warnings array, it can be empty at the end but is mandatory.
2455 $warnings = array();
2457 // Validate params.
2458 $params = array(
2459 'messageid' => $messageid,
2460 'timeread' => $timeread
2462 $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2464 if (empty($params['timeread'])) {
2465 $timeread = time();
2466 } else {
2467 $timeread = $params['timeread'];
2470 // Validate context.
2471 $context = context_system::instance();
2472 self::validate_context($context);
2474 $sql = "SELECT m.*, mcm.userid as useridto
2475 FROM {messages} m
2476 INNER JOIN {message_conversations} mc
2477 ON m.conversationid = mc.id
2478 INNER JOIN {message_conversation_members} mcm
2479 ON mcm.conversationid = mc.id
2480 LEFT JOIN {message_user_actions} mua
2481 ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2482 WHERE mua.id is NULL
2483 AND mcm.userid != m.useridfrom
2484 AND m.id = ?";
2485 $messageparams = [];
2486 $messageparams[] = $USER->id;
2487 $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2488 $messageparams[] = $params['messageid'];
2489 $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2491 if ($message->useridto != $USER->id) {
2492 throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2495 \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2497 $results = array(
2498 'messageid' => $message->id,
2499 'warnings' => $warnings
2501 return $results;
2505 * Returns description of method result value
2507 * @return external_description
2508 * @since 2.9
2510 public static function mark_message_read_returns() {
2511 return new external_single_structure(
2512 array(
2513 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2514 'warnings' => new external_warnings()
2520 * Returns description of method parameters
2522 * @return external_function_parameters
2524 public static function mark_notification_read_parameters() {
2525 return new external_function_parameters(
2526 array(
2527 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2528 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2529 VALUE_DEFAULT, 0)
2535 * Mark a single notification as read.
2537 * This will trigger a 'notification_viewed' event.
2539 * @param int $notificationid id of the notification
2540 * @param int $timeread timestamp for when the notification should be marked read
2541 * @return external_description
2542 * @throws invalid_parameter_exception
2543 * @throws moodle_exception
2545 public static function mark_notification_read($notificationid, $timeread) {
2546 global $CFG, $DB, $USER;
2548 // Warnings array, it can be empty at the end but is mandatory.
2549 $warnings = array();
2551 // Validate params.
2552 $params = array(
2553 'notificationid' => $notificationid,
2554 'timeread' => $timeread
2556 $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2558 if (empty($params['timeread'])) {
2559 $timeread = time();
2560 } else {
2561 $timeread = $params['timeread'];
2564 // Validate context.
2565 $context = context_system::instance();
2566 self::validate_context($context);
2568 $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2570 if ($notification->useridto != $USER->id) {
2571 throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2572 'notification as read');
2575 \core_message\api::mark_notification_as_read($notification, $timeread);
2577 $results = array(
2578 'notificationid' => $notification->id,
2579 'warnings' => $warnings
2582 return $results;
2586 * Returns description of method result value
2588 * @return external_description
2590 public static function mark_notification_read_returns() {
2591 return new external_single_structure(
2592 array(
2593 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2594 'warnings' => new external_warnings()
2600 * Mark all conversation messages as read parameters description.
2602 * @return external_function_parameters
2603 * @since 3.6
2605 public static function mark_all_conversation_messages_as_read_parameters() {
2606 return new external_function_parameters(
2607 array(
2608 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2609 'conversationid' =>
2610 new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2616 * Mark all conversation messages as read function.
2618 * @param int $userid The user id of who we want to delete the conversation for
2619 * @param int $conversationid The id of the conversations
2620 * @since 3.6
2622 public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2623 global $CFG;
2625 // Check if messaging is enabled.
2626 if (empty($CFG->messaging)) {
2627 throw new moodle_exception('disabled', 'message');
2630 $params = array(
2631 'userid' => $userid,
2632 'conversationid' => $conversationid,
2634 $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2636 $context = context_system::instance();
2637 self::validate_context($context);
2639 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2640 core_user::require_active_user($user);
2642 if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
2643 \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
2644 } else {
2645 throw new moodle_exception('accessdenied', 'admin');
2650 * Mark all conversation messages as read return description.
2652 * @return external_warnings
2653 * @since 3.6
2655 public static function mark_all_conversation_messages_as_read_returns() {
2656 return null;
2660 * Returns description of method parameters.
2662 * @return external_function_parameters
2663 * @since 3.6
2665 public static function delete_conversations_by_id_parameters() {
2666 return new external_function_parameters(
2667 array(
2668 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2669 'conversationids' => new external_multiple_structure(
2670 new external_value(PARAM_INT, 'The id of the conversation'),
2671 'List of conversation IDs'
2678 * Deletes a conversation.
2680 * @param int $userid The user id of who we want to delete the conversation for
2681 * @param int[] $conversationids The ids of the conversations
2682 * @return array
2683 * @throws moodle_exception
2684 * @since 3.6
2686 public static function delete_conversations_by_id($userid, array $conversationids) {
2687 global $CFG;
2689 // Check if private messaging between users is allowed.
2690 if (empty($CFG->messaging)) {
2691 throw new moodle_exception('disabled', 'message');
2694 // Validate params.
2695 $params = [
2696 'userid' => $userid,
2697 'conversationids' => $conversationids,
2699 $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
2701 // Validate context.
2702 $context = context_system::instance();
2703 self::validate_context($context);
2705 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2706 core_user::require_active_user($user);
2708 foreach ($params['conversationids'] as $conversationid) {
2709 if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2710 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2711 } else {
2712 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2716 return [];
2720 * Returns description of method result value.
2722 * @return external_description
2723 * @since 3.6
2725 public static function delete_conversations_by_id_returns() {
2726 return new external_warnings();
2730 * Returns description of method parameters
2732 * @return external_function_parameters
2733 * @since 3.1
2735 public static function delete_message_parameters() {
2736 return new external_function_parameters(
2737 array(
2738 'messageid' => new external_value(PARAM_INT, 'The message id'),
2739 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2740 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2746 * Deletes a message
2748 * @param int $messageid the message id
2749 * @param int $userid the user id of who we want to delete the message for
2750 * @param bool $read if is a message read (default to true)
2751 * @return external_description
2752 * @throws moodle_exception
2753 * @since 3.1
2755 public static function delete_message($messageid, $userid, $read = true) {
2756 global $CFG;
2758 // Check if private messaging between users is allowed.
2759 if (empty($CFG->messaging)) {
2760 throw new moodle_exception('disabled', 'message');
2763 // Warnings array, it can be empty at the end but is mandatory.
2764 $warnings = array();
2766 // Validate params.
2767 $params = array(
2768 'messageid' => $messageid,
2769 'userid' => $userid,
2770 'read' => $read
2772 $params = self::validate_parameters(self::delete_message_parameters(), $params);
2774 // Validate context.
2775 $context = context_system::instance();
2776 self::validate_context($context);
2778 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2779 core_user::require_active_user($user);
2781 if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
2782 $status = \core_message\api::delete_message($user->id, $params['messageid']);
2783 } else {
2784 throw new moodle_exception('You do not have permission to delete this message');
2787 $results = array(
2788 'status' => $status,
2789 'warnings' => $warnings
2791 return $results;
2795 * Returns description of method result value
2797 * @return external_description
2798 * @since 3.1
2800 public static function delete_message_returns() {
2801 return new external_single_structure(
2802 array(
2803 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2804 'warnings' => new external_warnings()
2810 * Returns description of method parameters
2812 * @return external_function_parameters
2813 * @since 3.2
2815 public static function message_processor_config_form_parameters() {
2816 return new external_function_parameters(
2817 array(
2818 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2819 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
2820 'formvalues' => new external_multiple_structure(
2821 new external_single_structure(
2822 array(
2823 'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2824 'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2827 'Config form values',
2828 VALUE_REQUIRED
2835 * Processes a message processor config form.
2837 * @param int $userid the user id
2838 * @param string $name the name of the processor
2839 * @param array $formvalues the form values
2840 * @return external_description
2841 * @throws moodle_exception
2842 * @since 3.2
2844 public static function message_processor_config_form($userid, $name, $formvalues) {
2845 global $USER, $CFG;
2847 // Check if messaging is enabled.
2848 if (empty($CFG->messaging)) {
2849 throw new moodle_exception('disabled', 'message');
2852 $params = self::validate_parameters(
2853 self::message_processor_config_form_parameters(),
2854 array(
2855 'userid' => $userid,
2856 'name' => $name,
2857 'formvalues' => $formvalues,
2861 $user = self::validate_preferences_permissions($params['userid']);
2863 $processor = get_message_processor($params['name']);
2864 $preferences = [];
2865 $form = new stdClass();
2867 foreach ($params['formvalues'] as $formvalue) {
2868 // Curly braces to ensure interpretation is consistent between
2869 // php 5 and php 7.
2870 $form->{$formvalue['name']} = $formvalue['value'];
2873 $processor->process_form($form, $preferences);
2875 if (!empty($preferences)) {
2876 set_user_preferences($preferences, $params['userid']);
2881 * Returns description of method result value
2883 * @return external_description
2884 * @since 3.2
2886 public static function message_processor_config_form_returns() {
2887 return null;
2891 * Returns description of method parameters
2893 * @return external_function_parameters
2894 * @since 3.2
2896 public static function get_message_processor_parameters() {
2897 return new external_function_parameters(
2898 array(
2899 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2900 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
2906 * Get a message processor.
2908 * @param int $userid
2909 * @param string $name the name of the processor
2910 * @return external_description
2911 * @throws moodle_exception
2912 * @since 3.2
2914 public static function get_message_processor($userid = 0, $name) {
2915 global $USER, $PAGE, $CFG;
2917 // Check if messaging is enabled.
2918 if (empty($CFG->messaging)) {
2919 throw new moodle_exception('disabled', 'message');
2922 $params = self::validate_parameters(
2923 self::get_message_processor_parameters(),
2924 array(
2925 'userid' => $userid,
2926 'name' => $name,
2930 if (empty($params['userid'])) {
2931 $params['userid'] = $USER->id;
2934 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2935 core_user::require_active_user($user);
2936 self::validate_context(context_user::instance($params['userid']));
2938 $processor = get_message_processor($params['name']);
2940 $processoroutput = new \core_message\output\processor($processor, $user);
2941 $renderer = $PAGE->get_renderer('core_message');
2943 return $processoroutput->export_for_template($renderer);
2947 * Returns description of method result value
2949 * @return external_description
2950 * @since 3.2
2952 public static function get_message_processor_returns() {
2953 return new external_function_parameters(
2954 array(
2955 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2956 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2962 * Check that the user has enough permission to retrieve message or notifications preferences.
2964 * @param int $userid the user id requesting the preferences
2965 * @return stdClass full user object
2966 * @throws moodle_exception
2967 * @since Moodle 3.2
2969 protected static function validate_preferences_permissions($userid) {
2970 global $USER;
2972 if (empty($userid)) {
2973 $user = $USER;
2974 } else {
2975 $user = core_user::get_user($userid, '*', MUST_EXIST);
2976 core_user::require_active_user($user);
2979 $systemcontext = context_system::instance();
2980 self::validate_context($systemcontext);
2982 // Check access control.
2983 if ($user->id == $USER->id) {
2984 // Editing own message profile.
2985 require_capability('moodle/user:editownmessageprofile', $systemcontext);
2986 } else {
2987 // Teachers, parents, etc.
2988 $personalcontext = context_user::instance($user->id);
2989 require_capability('moodle/user:editmessageprofile', $personalcontext);
2991 return $user;
2995 * Returns a notification or message preference structure.
2997 * @return external_single_structure the structure
2998 * @since Moodle 3.2
3000 protected static function get_preferences_structure() {
3001 return new external_single_structure(
3002 array(
3003 'userid' => new external_value(PARAM_INT, 'User id'),
3004 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3005 'processors' => new external_multiple_structure(
3006 new external_single_structure(
3007 array(
3008 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3009 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3010 'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3011 'contextid' => new external_value(PARAM_INT, 'Context id'),
3012 'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3015 'Config form values'
3017 'components' => new external_multiple_structure(
3018 new external_single_structure(
3019 array(
3020 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3021 'notifications' => new external_multiple_structure(
3022 new external_single_structure(
3023 array(
3024 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3025 'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3026 'processors' => new external_multiple_structure(
3027 new external_single_structure(
3028 array(
3029 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3030 'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3031 'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3032 'lockedmessage' => new external_value(PARAM_TEXT,
3033 'Text to display if locked', VALUE_OPTIONAL),
3034 'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3035 'loggedin' => new external_single_structure(
3036 array(
3037 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3038 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3039 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3042 'loggedoff' => new external_single_structure(
3043 array(
3044 'name' => new external_value(PARAM_NOTAGS, 'Name'),
3045 'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3046 'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3051 'Processors values for this notification'
3055 'List of notificaitons for the component'
3059 'Available components'
3066 * Returns description of method parameters
3068 * @return external_function_parameters
3069 * @since 3.2
3071 public static function get_user_notification_preferences_parameters() {
3072 return new external_function_parameters(
3073 array(
3074 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3080 * Get the notification preferences for a given user.
3082 * @param int $userid id of the user, 0 for current user
3083 * @return external_description
3084 * @throws moodle_exception
3085 * @since 3.2
3087 public static function get_user_notification_preferences($userid = 0) {
3088 global $PAGE;
3090 $params = self::validate_parameters(
3091 self::get_user_notification_preferences_parameters(),
3092 array(
3093 'userid' => $userid,
3096 $user = self::validate_preferences_permissions($params['userid']);
3098 $processors = get_message_processors();
3099 $providers = message_get_providers_for_user($user->id);
3100 $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3101 $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3103 $renderer = $PAGE->get_renderer('core_message');
3105 $result = array(
3106 'warnings' => array(),
3107 'preferences' => $notificationlist->export_for_template($renderer)
3109 return $result;
3113 * Returns description of method result value
3115 * @return external_description
3116 * @since 3.2
3118 public static function get_user_notification_preferences_returns() {
3119 return new external_function_parameters(
3120 array(
3121 'preferences' => self::get_preferences_structure(),
3122 'warnings' => new external_warnings(),
3128 * Returns description of method parameters
3130 * @return external_function_parameters
3131 * @since 3.2
3133 public static function get_user_message_preferences_parameters() {
3134 return new external_function_parameters(
3135 array(
3136 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3142 * Get the notification preferences for a given user.
3144 * @param int $userid id of the user, 0 for current user
3145 * @return external_description
3146 * @throws moodle_exception
3147 * @since 3.2
3149 public static function get_user_message_preferences($userid = 0) {
3150 global $CFG, $PAGE;
3152 $params = self::validate_parameters(
3153 self::get_user_message_preferences_parameters(),
3154 array(
3155 'userid' => $userid,
3159 $user = self::validate_preferences_permissions($params['userid']);
3161 // Filter out enabled, available system_configured and user_configured processors only.
3162 $readyprocessors = array_filter(get_message_processors(), function($processor) {
3163 return $processor->enabled &&
3164 $processor->configured &&
3165 $processor->object->is_user_configured() &&
3166 // Filter out processors that don't have and message preferences to configure.
3167 $processor->object->has_message_preferences();
3170 $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
3171 return $provider->component === 'moodle';
3173 $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
3174 $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
3175 $providers, $preferences, $user);
3177 $renderer = $PAGE->get_renderer('core_message');
3179 $entertosend = get_user_preferences('message_entertosend', $CFG->messagingdefaultpressenter, $user);
3181 $result = array(
3182 'warnings' => array(),
3183 'preferences' => $notificationlistoutput->export_for_template($renderer),
3184 'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id),
3185 'entertosend' => $entertosend
3187 return $result;
3191 * Returns description of method result value
3193 * @return external_description
3194 * @since 3.2
3196 public static function get_user_message_preferences_returns() {
3197 return new external_function_parameters(
3198 array(
3199 'preferences' => self::get_preferences_structure(),
3200 'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'),
3201 'entertosend' => new external_value(PARAM_BOOL, 'User preference for using enter to send messages'),
3202 'warnings' => new external_warnings(),
3208 * Returns description of method parameters for the favourite_conversations() method.
3210 * @return external_function_parameters
3212 public static function set_favourite_conversations_parameters() {
3213 return new external_function_parameters(
3214 array(
3215 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3216 'conversations' => new external_multiple_structure(
3217 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3224 * Favourite a conversation, or list of conversations for a user.
3226 * @param int $userid the id of the user, or 0 for the current user.
3227 * @param array $conversationids the list of conversations ids to favourite.
3228 * @return array
3229 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3231 public static function set_favourite_conversations(int $userid, array $conversationids) {
3232 global $CFG, $USER;
3234 // All the business logic checks that really shouldn't be in here.
3235 if (empty($CFG->messaging)) {
3236 throw new moodle_exception('disabled', 'message');
3238 $params = [
3239 'userid' => $userid,
3240 'conversations' => $conversationids
3242 $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params);
3243 $systemcontext = context_system::instance();
3244 self::validate_context($systemcontext);
3246 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3247 throw new moodle_exception('You do not have permission to perform this action.');
3250 foreach ($params['conversations'] as $conversationid) {
3251 \core_message\api::set_favourite_conversation($conversationid, $params['userid']);
3254 return [];
3258 * Return a description of the returns for the create_user_favourite_conversations() method.
3260 * @return external_description
3262 public static function set_favourite_conversations_returns() {
3263 return new external_warnings();
3267 * Returns description of method parameters for unfavourite_conversations() method.
3269 * @return external_function_parameters
3271 public static function unset_favourite_conversations_parameters() {
3272 return new external_function_parameters(
3273 array(
3274 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3275 'conversations' => new external_multiple_structure(
3276 new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3283 * Unfavourite a conversation, or list of conversations for a user.
3285 * @param int $userid the id of the user, or 0 for the current user.
3286 * @param array $conversationids the list of conversations ids unset as favourites.
3287 * @return array
3288 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3290 public static function unset_favourite_conversations(int $userid, array $conversationids) {
3291 global $CFG, $USER;
3293 // All the business logic checks that really shouldn't be in here.
3294 if (empty($CFG->messaging)) {
3295 throw new moodle_exception('disabled', 'message');
3297 $params = [
3298 'userid' => $userid,
3299 'conversations' => $conversationids
3301 $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params);
3302 $systemcontext = context_system::instance();
3303 self::validate_context($systemcontext);
3305 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3306 throw new moodle_exception('You do not have permission to perform this action.');
3309 foreach ($params['conversations'] as $conversationid) {
3310 \core_message\api::unset_favourite_conversation($conversationid, $params['userid']);
3313 return [];
3317 * Unset favourite conversations return description.
3319 * @return external_description
3321 public static function unset_favourite_conversations_returns() {
3322 return new external_warnings();
3326 * Returns description of method parameters for get_member_info() method.
3328 * @return external_function_parameters
3330 public static function get_member_info_parameters() {
3331 return new external_function_parameters(
3332 array(
3333 'referenceuserid' => new external_value(PARAM_INT, 'id of the user'),
3334 'userids' => new external_multiple_structure(
3335 new external_value(PARAM_INT, 'id of members to get')
3337 'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false),
3338 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'include privacy info in response', VALUE_DEFAULT, false)
3344 * Returns conversation member info for the supplied users, relative to the supplied referenceuserid.
3346 * This is the basic structure used when returning members, and includes information about the relationship between each member
3347 * and the referenceuser, such as a whether the referenceuser has marked the member as a contact, or has blocked them.
3349 * @param int $referenceuserid the id of the user which check contact and blocked status.
3350 * @param array $userids
3351 * @return array the array of objects containing member info.
3352 * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3354 public static function get_member_info(
3355 int $referenceuserid,
3356 array $userids,
3357 bool $includecontactrequests = false,
3358 bool $includeprivacyinfo = false
3360 global $CFG, $USER;
3362 // All the business logic checks that really shouldn't be in here.
3363 if (empty($CFG->messaging)) {
3364 throw new moodle_exception('disabled', 'message');
3366 $params = [
3367 'referenceuserid' => $referenceuserid,
3368 'userids' => $userids,
3369 'includecontactrequests' => $includecontactrequests,
3370 'includeprivacyinfo' => $includeprivacyinfo
3372 $params = self::validate_parameters(self::get_member_info_parameters(), $params);
3373 $systemcontext = context_system::instance();
3374 self::validate_context($systemcontext);
3376 if (($USER->id != $referenceuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3377 throw new moodle_exception('You do not have permission to perform this action.');
3380 return \core_message\helper::get_member_info(
3381 $params['referenceuserid'],
3382 $params['userids'],
3383 $params['includecontactrequests'],
3384 $params['includeprivacyinfo']
3389 * Get member info return description.
3391 * @return external_description
3393 public static function get_member_info_returns() {
3394 return new external_multiple_structure(
3395 self::get_conversation_member_structure()
3400 * Returns description of method parameters for get_conversation_counts() method.
3402 * @return external_function_parameters
3404 public static function get_conversation_counts_parameters() {
3405 return new external_function_parameters(
3407 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3413 * Returns an array of conversation counts for the various types of conversations, including favourites.
3415 * Return format:
3417 * 'favourites' => 0,
3418 * 'types' => [
3419 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3420 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3424 * @param int $userid the id of the user whose counts we are fetching.
3425 * @return array the array of conversation counts, indexed by type.
3426 * @throws moodle_exception if the current user cannot perform this action.
3428 public static function get_conversation_counts(int $userid) {
3429 global $CFG, $USER;
3431 // All the business logic checks that really shouldn't be in here.
3432 if (empty($CFG->messaging)) {
3433 throw new moodle_exception('disabled', 'message');
3436 if (empty($userid)) {
3437 $userid = $USER->id;
3440 $params = ['userid' => $userid];
3441 $params = self::validate_parameters(self::get_conversation_counts_parameters(), $params);
3443 $systemcontext = context_system::instance();
3444 self::validate_context($systemcontext);
3446 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3447 throw new moodle_exception('You do not have permission to perform this action.');
3450 return \core_message\api::get_conversation_counts($params['userid']);
3454 * Get conversation counts return description.
3456 * @return external_description
3458 public static function get_conversation_counts_returns() {
3459 return new external_single_structure(
3461 'favourites' => new external_value(PARAM_INT, 'Total number of favourite conversations'),
3462 'types' => new external_single_structure(
3464 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3465 'Total number of individual conversations'),
3466 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3467 'Total number of group conversations'),
3468 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3469 'Total number of self conversations'),
3477 * Returns description of method parameters for get_unread_conversation_counts() method.
3479 * @return external_function_parameters
3481 public static function get_unread_conversation_counts_parameters() {
3482 return new external_function_parameters(
3484 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3490 * Returns an array of unread conversation counts for the various types of conversations, including favourites.
3492 * Return format:
3494 * 'favourites' => 0,
3495 * 'types' => [
3496 * \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3497 * \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3501 * @param int $userid the id of the user whose counts we are fetching.
3502 * @return array the array of unread conversation counts, indexed by type.
3503 * @throws moodle_exception if the current user cannot perform this action.
3505 public static function get_unread_conversation_counts(int $userid) {
3506 global $CFG, $USER;
3508 // All the business logic checks that really shouldn't be in here.
3509 if (empty($CFG->messaging)) {
3510 throw new moodle_exception('disabled', 'message');
3513 if (empty($userid)) {
3514 $userid = $USER->id;
3517 $params = ['userid' => $userid];
3518 $params = self::validate_parameters(self::get_unread_conversation_counts_parameters(), $params);
3520 $systemcontext = context_system::instance();
3521 self::validate_context($systemcontext);
3523 if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3524 throw new moodle_exception('You do not have permission to perform this action.');
3527 return \core_message\api::get_unread_conversation_counts($params['userid']);
3531 * Get unread conversation counts return description.
3533 * @return external_description
3535 public static function get_unread_conversation_counts_returns() {
3536 return new external_single_structure(
3538 'favourites' => new external_value(PARAM_INT, 'Total number of unread favourite conversations'),
3539 'types' => new external_single_structure(
3541 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3542 'Total number of unread individual conversations'),
3543 \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3544 'Total number of unread group conversations'),
3545 \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3546 'Total number of unread self conversations'),
3554 * Returns description of method parameters
3556 * @return external_function_parameters
3557 * @since 3.7
3559 public static function delete_message_for_all_users_parameters() {
3560 return new external_function_parameters(
3561 array(
3562 'messageid' => new external_value(PARAM_INT, 'The message id'),
3563 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users')
3568 * Deletes a message for all users
3570 * @param int $messageid the message id
3571 * @param int $userid the user id of who we want to delete the message for all users
3572 * @return external_description
3573 * @throws moodle_exception
3574 * @since 3.7
3576 public static function delete_message_for_all_users(int $messageid, int $userid) {
3577 global $CFG;
3579 // Check if private messaging between users is allowed.
3580 if (empty($CFG->messaging)) {
3581 throw new moodle_exception('disabled', 'message');
3584 // Validate params.
3585 $params = array(
3586 'messageid' => $messageid,
3587 'userid' => $userid
3589 $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params);
3591 // Validate context.
3592 $context = context_system::instance();
3593 self::validate_context($context);
3595 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3596 core_user::require_active_user($user);
3598 // Checks if a user can delete a message for all users.
3599 if (core_message\api::can_delete_message_for_all_users($user->id, $params['messageid'])) {
3600 \core_message\api::delete_message_for_all_users($params['messageid']);
3601 } else {
3602 throw new moodle_exception('You do not have permission to delete this message for everyone.');
3605 return [];
3608 * Returns description of method result value
3610 * @return external_description
3611 * @since 3.7
3613 public static function delete_message_for_all_users_returns() {
3614 return new external_warnings();