Merge branch 'MDL-63974-master' of https://github.com/snake/moodle
[moodle.git] / message / externallib.php
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.
13 //
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
20  *
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
25  */
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
34  *
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
40  */
41 class core_message_external extends external_api {
42     /**
43      * Returns description of method parameters
44      *
45      * @return external_function_parameters
46      * @since Moodle 3.6
47      */
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),
57                         )
58                     )
59                 )
60             )
61         );
62     }
64     /**
65      * Send messages from the current USER to a conversation.
66      *
67      * This conversation may be any type of conversation, individual or group.
68      *
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
73      */
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');
80         }
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             $messages[] = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
94                 $message['textformat']);
95         }
97         return $messages;
98     }
100     /**
101      * Returns description of method result value.
102      *
103      * @return external_description
104      * @since Moodle 3.6
105      */
106     public static function send_messages_to_conversation_returns() {
107         return new external_multiple_structure(
108             self::get_conversation_message_structure()
109         );
110     }
113     /**
114      * Returns description of method parameters
115      *
116      * @return external_function_parameters
117      * @since Moodle 2.2
118      */
119     public static function send_instant_messages_parameters() {
120         return new external_function_parameters(
121             array(
122                 'messages' => new external_multiple_structure(
123                     new external_single_structure(
124                         array(
125                             'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
126                             'text' => new external_value(PARAM_RAW, 'the text of the message'),
127                             'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
128                             'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the message. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL),
129                         )
130                     )
131                 )
132             )
133         );
134     }
136     /**
137      * Send private messages from the current USER to other users
138      *
139      * @param array $messages An array of message to send.
140      * @return array
141      * @since Moodle 2.2
142      */
143     public static function send_instant_messages($messages = array()) {
144         global $CFG, $USER, $DB;
146         // Check if messaging is enabled.
147         if (empty($CFG->messaging)) {
148             throw new moodle_exception('disabled', 'message');
149         }
151         // Ensure the current user is allowed to run this function
152         $context = context_system::instance();
153         self::validate_context($context);
154         require_capability('moodle/site:sendmessage', $context);
156         $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
158         //retrieve all tousers of the messages
159         $receivers = array();
160         foreach($params['messages'] as $message) {
161             $receivers[] = $message['touserid'];
162         }
163         list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
164         $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
166         $resultmessages = array();
167         foreach ($params['messages'] as $message) {
168             $resultmsg = array(); //the infos about the success of the operation
170             // We are going to do some checking.
171             // Code should match /messages/index.php checks.
172             $success = true;
174             // Check the user exists.
175             if (empty($tousers[$message['touserid']])) {
176                 $success = false;
177                 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
178             }
180             // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
181             // Check if the recipient can be messaged by the sender.
182             if ($success && !\core_message\api::can_post_message($tousers[$message['touserid']], $USER)) {
183                 $success = false;
184                 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
185             }
187             // Now we can send the message (at least try).
188             if ($success) {
189                 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
190                 $success = message_post_message($USER, $tousers[$message['touserid']],
191                         $message['text'], external_validate_format($message['textformat']));
192             }
194             // Build the resultmsg.
195             if (isset($message['clientmsgid'])) {
196                 $resultmsg['clientmsgid'] = $message['clientmsgid'];
197             }
198             if ($success) {
199                 $resultmsg['msgid'] = $success;
200             } else {
201                 // WARNINGS: for backward compatibility we return this errormessage.
202                 //          We should have thrown exceptions as these errors prevent results to be returned.
203                 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
204                 $resultmsg['msgid'] = -1;
205                 $resultmsg['errormessage'] = $errormessage;
206             }
208             $resultmessages[] = $resultmsg;
209         }
211         return $resultmessages;
212     }
214     /**
215      * Returns description of method result value
216      *
217      * @return external_description
218      * @since Moodle 2.2
219      */
220     public static function send_instant_messages_returns() {
221         return new external_multiple_structure(
222             new external_single_structure(
223                 array(
224                     'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
225                     'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
226                     'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
227                 )
228             )
229         );
230     }
232     /**
233      * Create contacts parameters description.
234      *
235      * @deprecated since Moodle 3.6
236      * @return external_function_parameters
237      * @since Moodle 2.5
238      */
239     public static function create_contacts_parameters() {
240         return new external_function_parameters(
241             array(
242                 'userids' => new external_multiple_structure(
243                     new external_value(PARAM_INT, 'User ID'),
244                     'List of user IDs'
245                 ),
246                 'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
247                     current user', VALUE_DEFAULT, 0)
248             )
249         );
250     }
252     /**
253      * Create contacts.
254      *
255      * @deprecated since Moodle 3.6
256      * @param array $userids array of user IDs.
257      * @param int $userid The id of the user we are creating the contacts for
258      * @return external_description
259      * @since Moodle 2.5
260      */
261     public static function create_contacts($userids, $userid = 0) {
262         global $CFG, $USER;
264         // Check if messaging is enabled.
265         if (empty($CFG->messaging)) {
266             throw new moodle_exception('disabled', 'message');
267         }
269         if (empty($userid)) {
270             $userid = $USER->id;
271         }
273         // Validate context.
274         $context = context_system::instance();
275         self::validate_context($context);
277         $params = array('userids' => $userids, 'userid' => $userid);
278         $params = self::validate_parameters(self::create_contacts_parameters(), $params);
280         $capability = 'moodle/site:manageallmessaging';
281         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
282             throw new required_capability_exception($context, $capability, 'nopermissions', '');
283         }
285         $warnings = array();
286         foreach ($params['userids'] as $id) {
287             if (!message_add_contact($id, 0, $params['userid'])) {
288                 $warnings[] = array(
289                     'item' => 'user',
290                     'itemid' => $id,
291                     'warningcode' => 'contactnotcreated',
292                     'message' => 'The contact could not be created'
293                 );
294             }
295         }
296         return $warnings;
297     }
299     /**
300      * Create contacts return description.
301      *
302      * @deprecated since Moodle 3.6
303      * @return external_description
304      * @since Moodle 2.5
305      */
306     public static function create_contacts_returns() {
307         return new external_warnings();
308     }
310     /**
311      * Marking the method as deprecated.
312      *
313      * @return bool
314      */
315     public static function create_contacts_is_deprecated() {
316         return true;
317     }
319     /**
320      * Delete contacts parameters description.
321      *
322      * @return external_function_parameters
323      * @since Moodle 2.5
324      */
325     public static function delete_contacts_parameters() {
326         return new external_function_parameters(
327             array(
328                 'userids' => new external_multiple_structure(
329                     new external_value(PARAM_INT, 'User ID'),
330                     'List of user IDs'
331                 ),
332                 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
333                     current user', VALUE_DEFAULT, 0)
334             )
335         );
336     }
338     /**
339      * Delete contacts.
340      *
341      * @param array $userids array of user IDs.
342      * @param int $userid The id of the user we are deleting the contacts for
343      * @return null
344      * @since Moodle 2.5
345      */
346     public static function delete_contacts($userids, $userid = 0) {
347         global $CFG, $USER;
349         // Check if messaging is enabled.
350         if (empty($CFG->messaging)) {
351             throw new moodle_exception('disabled', 'message');
352         }
354         if (empty($userid)) {
355             $userid = $USER->id;
356         }
358         // Validate context.
359         $context = context_system::instance();
360         self::validate_context($context);
362         $params = array('userids' => $userids, 'userid' => $userid);
363         $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
365         $capability = 'moodle/site:manageallmessaging';
366         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
367             throw new required_capability_exception($context, $capability, 'nopermissions', '');
368         }
370         foreach ($params['userids'] as $id) {
371             \core_message\api::remove_contact($params['userid'], $id);
372         }
374         return null;
375     }
377     /**
378      * Delete contacts return description.
379      *
380      * @return external_description
381      * @since Moodle 2.5
382      */
383     public static function delete_contacts_returns() {
384         return null;
385     }
387     /**
388      * Block user parameters description.
389      *
390      * @return external_function_parameters
391      */
392     public static function block_user_parameters() {
393         return new external_function_parameters(
394             [
395                 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
396                 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
397             ]
398         );
399     }
401     /**
402      * Blocks a user.
403      *
404      * @param int $userid The id of the user who is blocking
405      * @param int $blockeduserid The id of the user being blocked
406      * @return external_description
407      */
408     public static function block_user(int $userid, int $blockeduserid) {
409         global $CFG, $USER;
411         // Check if messaging is enabled.
412         if (empty($CFG->messaging)) {
413             throw new moodle_exception('disabled', 'message');
414         }
416         // Validate context.
417         $context = context_system::instance();
418         self::validate_context($context);
420         $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
421         $params = self::validate_parameters(self::block_user_parameters(), $params);
423         $capability = 'moodle/site:manageallmessaging';
424         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
425             throw new required_capability_exception($context, $capability, 'nopermissions', '');
426         }
428         if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
429             \core_message\api::block_user($params['userid'], $params['blockeduserid']);
430         }
432         return [];
433     }
435     /**
436      * Block user return description.
437      *
438      * @return external_description
439      */
440     public static function block_user_returns() {
441         return new external_warnings();
442     }
444     /**
445      * Unblock user parameters description.
446      *
447      * @return external_function_parameters
448      */
449     public static function unblock_user_parameters() {
450         return new external_function_parameters(
451             [
452                 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
453                 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
454             ]
455         );
456     }
458     /**
459      * Unblock user.
460      *
461      * @param int $userid The id of the user who is unblocking
462      * @param int $unblockeduserid The id of the user being unblocked
463      */
464     public static function unblock_user(int $userid, int $unblockeduserid) {
465         global $CFG, $USER;
467         // Check if messaging is enabled.
468         if (empty($CFG->messaging)) {
469             throw new moodle_exception('disabled', 'message');
470         }
472         // Validate context.
473         $context = context_system::instance();
474         self::validate_context($context);
476         $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
477         $params = self::validate_parameters(self::unblock_user_parameters(), $params);
479         $capability = 'moodle/site:manageallmessaging';
480         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
481             throw new required_capability_exception($context, $capability, 'nopermissions', '');
482         }
484         \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
486         return [];
487     }
489     /**
490      * Unblock user return description.
491      *
492      * @return external_description
493      */
494     public static function unblock_user_returns() {
495         return new external_warnings();
496     }
498     /**
499      * Block contacts parameters description.
500      *
501      * @deprecated since Moodle 3.6
502      * @return external_function_parameters
503      * @since Moodle 2.5
504      */
505     public static function block_contacts_parameters() {
506         return new external_function_parameters(
507             array(
508                 'userids' => new external_multiple_structure(
509                     new external_value(PARAM_INT, 'User ID'),
510                     'List of user IDs'
511                 ),
512                 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
513                     current user', VALUE_DEFAULT, 0)
514             )
515         );
516     }
518     /**
519      * Block contacts.
520      *
521      * @deprecated since Moodle 3.6
522      * @param array $userids array of user IDs.
523      * @param int $userid The id of the user we are blocking the contacts for
524      * @return external_description
525      * @since Moodle 2.5
526      */
527     public static function block_contacts($userids, $userid = 0) {
528         global $CFG, $USER;
530         // Check if messaging is enabled.
531         if (empty($CFG->messaging)) {
532             throw new moodle_exception('disabled', 'message');
533         }
535         if (empty($userid)) {
536             $userid = $USER->id;
537         }
539         // Validate context.
540         $context = context_system::instance();
541         self::validate_context($context);
543         $params = array('userids' => $userids, 'userid' => $userid);
544         $params = self::validate_parameters(self::block_contacts_parameters(), $params);
546         $capability = 'moodle/site:manageallmessaging';
547         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
548             throw new required_capability_exception($context, $capability, 'nopermissions', '');
549         }
551         $warnings = array();
552         foreach ($params['userids'] as $id) {
553             if (!message_block_contact($id, $params['userid'])) {
554                 $warnings[] = array(
555                     'item' => 'user',
556                     'itemid' => $id,
557                     'warningcode' => 'contactnotblocked',
558                     'message' => 'The contact could not be blocked'
559                 );
560             }
561         }
562         return $warnings;
563     }
565     /**
566      * Block contacts return description.
567      *
568      * @deprecated since Moodle 3.6
569      * @return external_description
570      * @since Moodle 2.5
571      */
572     public static function block_contacts_returns() {
573         return new external_warnings();
574     }
576     /**
577      * Marking the method as deprecated.
578      *
579      * @return bool
580      */
581     public static function block_contacts_is_deprecated() {
582         return true;
583     }
585     /**
586      * Unblock contacts parameters description.
587      *
588      * @deprecated since Moodle 3.6
589      * @return external_function_parameters
590      * @since Moodle 2.5
591      */
592     public static function unblock_contacts_parameters() {
593         return new external_function_parameters(
594             array(
595                 'userids' => new external_multiple_structure(
596                     new external_value(PARAM_INT, 'User ID'),
597                     'List of user IDs'
598                 ),
599                 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
600                     current user', VALUE_DEFAULT, 0)
601             )
602         );
603     }
605     /**
606      * Unblock contacts.
607      *
608      * @param array $userids array of user IDs.
609      * @param int $userid The id of the user we are unblocking the contacts for
610      * @return null
611      * @since Moodle 2.5
612      */
613     public static function unblock_contacts($userids, $userid = 0) {
614         global $CFG, $USER;
616         // Check if messaging is enabled.
617         if (empty($CFG->messaging)) {
618             throw new moodle_exception('disabled', 'message');
619         }
621         if (empty($userid)) {
622             $userid = $USER->id;
623         }
625         // Validate context.
626         $context = context_system::instance();
627         self::validate_context($context);
629         $params = array('userids' => $userids, 'userid' => $userid);
630         $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
632         $capability = 'moodle/site:manageallmessaging';
633         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
634             throw new required_capability_exception($context, $capability, 'nopermissions', '');
635         }
637         foreach ($params['userids'] as $id) {
638             message_unblock_contact($id, $params['userid']);
639         }
641         return null;
642     }
644     /**
645      * Unblock contacts return description.
646      *
647      * @deprecated since Moodle 3.6
648      * @return external_description
649      * @since Moodle 2.5
650      */
651     public static function unblock_contacts_returns() {
652         return null;
653     }
655     /**
656      * Marking the method as deprecated.
657      *
658      * @return bool
659      */
660     public static function unblock_contacts_is_deprecated() {
661         return true;
662     }
664     /**
665      * Returns contact requests parameters description.
666      *
667      * @return external_function_parameters
668      */
669     public static function get_contact_requests_parameters() {
670         return new external_function_parameters(
671             [
672                 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
673                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
674                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
675             ]
676         );
677     }
679     /**
680      * Handles returning the contact requests for a user.
681      *
682      * This also includes the user data necessary to display information
683      * about the user.
684      *
685      * It will not include blocked users.
686      *
687      * @param int $userid The id of the user we want to get the contact requests for
688      * @param int $limitfrom
689      * @param int $limitnum
690      */
691     public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
692         global $CFG, $USER;
694         // Check if messaging is enabled.
695         if (empty($CFG->messaging)) {
696             throw new moodle_exception('disabled', 'message');
697         }
699         // Validate context.
700         $context = context_system::instance();
701         self::validate_context($context);
703         $params = [
704             'userid' => $userid,
705             'limitfrom' => $limitfrom,
706             'limitnum' => $limitnum
707         ];
708         $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
710         $capability = 'moodle/site:manageallmessaging';
711         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
712             throw new required_capability_exception($context, $capability, 'nopermissions', '');
713         }
715         return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
716     }
718     /**
719      * Returns the contact requests return description.
720      *
721      * @return external_description
722      */
723     public static function get_contact_requests_returns() {
724         return new external_multiple_structure(
725             self::get_conversation_member_structure()
726         );
727     }
729     /**
730      * Returns get conversation members parameters description.
731      *
732      * @return external_function_parameters
733      */
734     public static function get_conversation_members_parameters() {
735         return new external_function_parameters(
736             [
737                 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
738                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
739                 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
740                     VALUE_DEFAULT, false),
741                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
742                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
743             ]
744         );
745     }
747     /**
748      * Returns a list of conversation members.
749      *
750      * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
751      * @param int $conversationid The id of the conversation
752      * @param bool $includecontactrequests Do we want to include contact requests with this data?
753      * @param int $limitfrom
754      * @param int $limitnum
755      * @return array
756      */
757     public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
758                                                     int $limitfrom = 0, int $limitnum = 0) {
759         global $CFG, $USER;
761         // Check if messaging is enabled.
762         if (empty($CFG->messaging)) {
763             throw new moodle_exception('disabled', 'message');
764         }
766         // Validate context.
767         $context = context_system::instance();
768         self::validate_context($context);
770         $params = [
771             'userid' => $userid,
772             'conversationid' => $conversationid,
773             'includecontactrequests' => $includecontactrequests,
774             'limitfrom' => $limitfrom,
775             'limitnum' => $limitnum
776         ];
777         $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
779         $capability = 'moodle/site:manageallmessaging';
780         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
781             throw new required_capability_exception($context, $capability, 'nopermissions', '');
782         }
784         // The user needs to be a part of the conversation before querying who the members are.
785         if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
786             throw new moodle_exception('You are not a member of this conversation.');
787         }
790         return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
791             $params['limitfrom'], $params['limitnum']);
792     }
794     /**
795      * Returns the get conversation members return description.
796      *
797      * @return external_description
798      */
799     public static function get_conversation_members_returns() {
800         return new external_multiple_structure(
801             self::get_conversation_member_structure(true)
802         );
803     }
805     /**
806      * Creates a contact request parameters description.
807      *
808      * @return external_function_parameters
809      */
810     public static function create_contact_request_parameters() {
811         return new external_function_parameters(
812             [
813                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
814                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
815             ]
816         );
817     }
819     /**
820      * Creates a contact request.
821      *
822      * @param int $userid The id of the user who is creating the contact request
823      * @param int $requesteduserid The id of the user being requested
824      */
825     public static function create_contact_request(int $userid, int $requesteduserid) {
826         global $CFG, $USER;
828         // Check if messaging is enabled.
829         if (empty($CFG->messaging)) {
830             throw new moodle_exception('disabled', 'message');
831         }
833         // Validate context.
834         $context = context_system::instance();
835         self::validate_context($context);
837         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
838         $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
840         $capability = 'moodle/site:manageallmessaging';
841         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
842             throw new required_capability_exception($context, $capability, 'nopermissions', '');
843         }
845         if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
846             $warning[] = [
847                 'item' => 'user',
848                 'itemid' => $params['requesteduserid'],
849                 'warningcode' => 'cannotcreatecontactrequest',
850                 'message' => 'You are unable to create a contact request for this user'
851             ];
852             return $warning;
853         }
855         if (!\core_message\api::does_contact_request_exist($params['userid'], $params['requesteduserid'])) {
856             \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
857         }
859         return [];
860     }
862     /**
863      * Creates a contact request return description.
864      *
865      * @return external_description
866      */
867     public static function create_contact_request_returns() {
868         return new external_warnings();
869     }
871     /**
872      * Confirm a contact request parameters description.
873      *
874      * @return external_function_parameters
875      */
876     public static function confirm_contact_request_parameters() {
877         return new external_function_parameters(
878             [
879                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
880                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
881             ]
882         );
883     }
885     /**
886      * Confirm a contact request.
887      *
888      * @param int $userid The id of the user who is creating the contact request
889      * @param int $requesteduserid The id of the user being requested
890      */
891     public static function confirm_contact_request(int $userid, int $requesteduserid) {
892         global $CFG, $USER;
894         // Check if messaging is enabled.
895         if (empty($CFG->messaging)) {
896             throw new moodle_exception('disabled', 'message');
897         }
899         // Validate context.
900         $context = context_system::instance();
901         self::validate_context($context);
903         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
904         $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
906         $capability = 'moodle/site:manageallmessaging';
907         if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
908             throw new required_capability_exception($context, $capability, 'nopermissions', '');
909         }
911         \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
913         return [];
914     }
916     /**
917      * Confirm a contact request return description.
918      *
919      * @return external_description
920      */
921     public static function confirm_contact_request_returns() {
922         return new external_warnings();
923     }
925     /**
926      * Declines a contact request parameters description.
927      *
928      * @return external_function_parameters
929      */
930     public static function decline_contact_request_parameters() {
931         return new external_function_parameters(
932             [
933                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
934                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
935             ]
936         );
937     }
939     /**
940      * Declines a contact request.
941      *
942      * @param int $userid The id of the user who is creating the contact request
943      * @param int $requesteduserid The id of the user being requested
944      */
945     public static function decline_contact_request(int $userid, int $requesteduserid) {
946         global $CFG, $USER;
948         // Check if messaging is enabled.
949         if (empty($CFG->messaging)) {
950             throw new moodle_exception('disabled', 'message');
951         }
953         // Validate context.
954         $context = context_system::instance();
955         self::validate_context($context);
957         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
958         $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
960         $capability = 'moodle/site:manageallmessaging';
961         if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
962             throw new required_capability_exception($context, $capability, 'nopermissions', '');
963         }
965         \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
967         return [];
968     }
970     /**
971      * Declines a contact request return description.
972      *
973      * @return external_description
974      */
975     public static function decline_contact_request_returns() {
976         return new external_warnings();
977     }
979     /**
980      * Return the structure of a message area contact.
981      *
982      * @return external_single_structure
983      * @since Moodle 3.2
984      */
985     private static function get_messagearea_contact_structure() {
986         return new external_single_structure(
987             array(
988                 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
989                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
990                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
991                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
992                 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
993                 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
994                 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
995                 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
996                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
997                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
998                 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
999                 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1000                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1001                     VALUE_DEFAULT, null),
1002             )
1003         );
1004     }
1006     /**
1007      * Return the structure of a conversation.
1008      *
1009      * @return external_single_structure
1010      * @since Moodle 3.6
1011      */
1013     private static function get_conversation_structure() {
1014         return new external_single_structure(
1015             array(
1016                 'id' => new external_value(PARAM_INT, 'The conversation id'),
1017                 'name' => new external_value(PARAM_NOTAGS, 'The conversation name, if set', VALUE_DEFAULT, null),
1018                 'subname' => new external_value(PARAM_NOTAGS, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1019                 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1020                 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group)'),
1021                 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1022                 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked conversation this conversation as a favourite'),
1023                 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1024                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1025                     VALUE_DEFAULT, null),
1026                 'members' => new external_multiple_structure(
1027                     self::get_conversation_member_structure(true)
1028                 ),
1029                 'messages' => new external_multiple_structure(
1030                     self::get_conversation_message_structure()
1031                 ),
1032             )
1033         );
1034     }
1036     /**
1037      * Return the structure of a conversation member.
1038      *
1039      * @param bool $includecontactrequests Are we including contact requests?
1040      * @param bool $includeconversations Are we including conversations?
1041      * @return external_single_structure
1042      * @since Moodle 3.6
1043      */
1044     private static function get_conversation_member_structure(bool $includecontactrequests = false,
1045                                                               bool $includeconversations = false) {
1046         $result = [
1047             'id' => new external_value(PARAM_INT, 'The user id'),
1048             'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1049             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1050             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1051             'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1052             'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1053             'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1054             'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1055             'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1056             'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1057             'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1058         ];
1060         if ($includecontactrequests) {
1061             $result['contactrequests'] = new external_multiple_structure(
1062                 new external_single_structure(
1063                     [
1064                         'id' => new external_value(PARAM_INT, 'The id of the message'),
1065                         'userid' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1066                         'requesteduserid' => new external_value(PARAM_RAW, 'The text of the message'),
1067                         'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1068                     ]
1069                 ), 'The contact requests', VALUE_OPTIONAL
1070             );
1071         }
1073         if ($includeconversations) {
1074             $result['conversations'] = new external_multiple_structure(new external_single_structure(
1075                 array(
1076                     'id' => new external_value(PARAM_INT, 'Conversations id'),
1077                     'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1078                     'name' => new external_value(PARAM_TEXT, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1079                     'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1080                 ), 'information about conversation', VALUE_OPTIONAL),
1081                 'Conversations between users', VALUE_OPTIONAL
1082             );
1083         }
1085         return new external_single_structure(
1086             $result
1087         );
1088     }
1090     /**
1091      * Return the structure of a message area message.
1092      *
1093      * @return external_single_structure
1094      * @since Moodle 3.6
1095      */
1096     private static function get_conversation_message_structure() {
1097         return new external_single_structure(
1098             array(
1099                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1100                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1101                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1102                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1103             )
1104         );
1105     }
1107     /**
1108      * Return the structure of a message area message.
1109      *
1110      * @return external_single_structure
1111      * @since Moodle 3.2
1112      */
1113     private static function get_messagearea_message_structure() {
1114         return new external_single_structure(
1115             array(
1116                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1117                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1118                 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1119                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1120                 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1121                 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1122                 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1123                 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1124                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1125                 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1126             )
1127         );
1128     }
1130     /**
1131      * Get messagearea search users in course parameters.
1132      *
1133      * @deprecated since 3.6
1134      *
1135      * @return external_function_parameters
1136      * @since 3.2
1137      */
1138     public static function data_for_messagearea_search_users_in_course_parameters() {
1139         return new external_function_parameters(
1140             array(
1141                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1142                 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1143                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1144                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1145                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1146             )
1147         );
1148     }
1150     /**
1151      * Get messagearea search users in course results.
1152      *
1153      * @deprecated since 3.6
1154      *
1155      * NOTE: We are deprecating this function but not search_users_in_course API function for backwards compatibility
1156      * with messaging UI. But should be removed once new group messaging UI is in place and old messaging UI is removed.
1157      * Followup: MDL-63915
1158      *
1159      * @param int $userid The id of the user who is performing the search
1160      * @param int $courseid The id of the course
1161      * @param string $search The string being searched
1162      * @param int $limitfrom
1163      * @param int $limitnum
1164      * @return stdClass
1165      * @throws moodle_exception
1166      * @since 3.2
1167      */
1168     public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1169                                                                        $limitnum = 0) {
1170         global $CFG, $PAGE, $USER;
1172         // Check if messaging is enabled.
1173         if (empty($CFG->messaging)) {
1174             throw new moodle_exception('disabled', 'message');
1175         }
1177         $systemcontext = context_system::instance();
1179         $params = array(
1180             'userid' => $userid,
1181             'courseid' => $courseid,
1182             'search' => $search,
1183             'limitfrom' => $limitfrom,
1184             'limitnum' => $limitnum
1185         );
1186         $params = self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1187         self::validate_context($systemcontext);
1189         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1190             throw new moodle_exception('You do not have permission to perform this action.');
1191         }
1193         $users = \core_message\api::search_users_in_course(
1194             $params['userid'],
1195             $params['courseid'],
1196             $params['search'],
1197             $params['limitfrom'],
1198             $params['limitnum']
1199         );
1200         $results = new \core_message\output\messagearea\user_search_results($users);
1202         $renderer = $PAGE->get_renderer('core_message');
1203         return $results->export_for_template($renderer);
1204     }
1206     /**
1207      * Get messagearea search users in course returns.
1208      *
1209      * @deprecated since 3.6
1210      *
1211      * @return external_single_structure
1212      * @since 3.2
1213      */
1214     public static function data_for_messagearea_search_users_in_course_returns() {
1215         return new external_single_structure(
1216             array(
1217                 'contacts' => new external_multiple_structure(
1218                     self::get_messagearea_contact_structure()
1219                 ),
1220             )
1221         );
1222     }
1224     /**
1225      * Marking the method as deprecated.
1226      *
1227      * @return bool
1228      */
1229     public static function data_for_messagearea_search_users_in_course_is_deprecated() {
1230         return true;
1231     }
1233     /**
1234      * Get messagearea search users parameters.
1235      *
1236      * @deprecated since 3.6
1237      *
1238      * @return external_function_parameters
1239      * @since 3.2
1240      */
1241     public static function data_for_messagearea_search_users_parameters() {
1242         return new external_function_parameters(
1243             array(
1244                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1245                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1246                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1247             )
1248         );
1249     }
1251     /**
1252      * Get messagearea search users results.
1253      *
1254      * @deprecated since 3.6
1255      *
1256      * NOTE: We are deprecating this function but not search_users API function for backwards compatibility
1257      * with messaging UI. But should be removed once new group messaging UI is in place and old messaging UI is removed.
1258      * Followup: MDL-63915
1259      *
1260      * @param int $userid The id of the user who is performing the search
1261      * @param string $search The string being searched
1262      * @param int $limitnum
1263      * @return stdClass
1264      * @throws moodle_exception
1265      * @since 3.2
1266      */
1267     public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1268         global $CFG, $PAGE, $USER;
1270         // Check if messaging is enabled.
1271         if (empty($CFG->messaging)) {
1272             throw new moodle_exception('disabled', 'message');
1273         }
1275         $systemcontext = context_system::instance();
1277         $params = array(
1278             'userid' => $userid,
1279             'search' => $search,
1280             'limitnum' => $limitnum
1281         );
1282         $params = self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1283         self::validate_context($systemcontext);
1285         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1286             throw new moodle_exception('You do not have permission to perform this action.');
1287         }
1289         list($contacts, $courses, $noncontacts) = \core_message\api::search_users(
1290             $params['userid'],
1291             $params['search'],
1292             $params['limitnum']
1293         );
1295         $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1297         $renderer = $PAGE->get_renderer('core_message');
1298         return $search->export_for_template($renderer);
1299     }
1301     /**
1302      * Get messagearea search users returns.
1303      *
1304      * @deprecated since 3.6
1305      *
1306      * @return external_single_structure
1307      * @since 3.2
1308      */
1309     public static function data_for_messagearea_search_users_returns() {
1310         return new external_single_structure(
1311             array(
1312                 'contacts' => new external_multiple_structure(
1313                     self::get_messagearea_contact_structure()
1314                 ),
1315                 'courses' => new external_multiple_structure(
1316                     new external_single_structure(
1317                         array(
1318                             'id' => new external_value(PARAM_INT, 'The course id'),
1319                             'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1320                             'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1321                         )
1322                     )
1323                 ),
1324                 'noncontacts' => new external_multiple_structure(
1325                     self::get_messagearea_contact_structure()
1326                 )
1327             )
1328         );
1329     }
1331     /**
1332      * Marking the method as deprecated.
1333      *
1334      * @return bool
1335      */
1336     public static function data_for_messagearea_search_users_is_deprecated() {
1337         return true;
1338     }
1340     /**
1341      * Get messagearea message search users parameters.
1342      *
1343      * @return external_function_parameters
1344      * @since 3.6
1345      */
1346     public static function message_search_users_parameters() {
1347         return new external_function_parameters(
1348             array(
1349                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1350                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1351                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1352                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1353             )
1354         );
1355     }
1357     /**
1358      * Get search users results.
1359      *
1360      * @param int $userid The id of the user who is performing the search
1361      * @param string $search The string being searched
1362      * @param int $limitfrom
1363      * @param int $limitnum
1364      * @return array
1365      * @throws moodle_exception
1366      * @since 3.6
1367      */
1368     public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1369         global $USER;
1371         $systemcontext = context_system::instance();
1373         $params = array(
1374             'userid' => $userid,
1375             'search' => $search,
1376             'limitfrom' => $limitfrom,
1377             'limitnum' => $limitnum
1378         );
1379         $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1380         self::validate_context($systemcontext);
1382         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1383             throw new moodle_exception('You do not have permission to perform this action.');
1384         }
1386         list($contacts, $noncontacts) = \core_message\api::message_search_users(
1387             $params['userid'],
1388             $params['search'],
1389             $params['limitfrom'],
1390             $params['limitnum']);
1392         return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1393     }
1395     /**
1396      * Get messagearea message search users returns.
1397      *
1398      * @return external_single_structure
1399      * @since 3.2
1400      */
1401     public static function message_search_users_returns() {
1402         return new external_single_structure(
1403             array(
1404                 'contacts' => new external_multiple_structure(
1405                     self::get_conversation_member_structure(false, true)
1406                 ),
1407                 'noncontacts' => new external_multiple_structure(
1408                     self::get_conversation_member_structure(false, true)
1409                 )
1410             )
1411         );
1412     }
1414     /**
1415      * Get messagearea search messages parameters.
1416      *
1417      * @return external_function_parameters
1418      * @since 3.2
1419      */
1420     public static function data_for_messagearea_search_messages_parameters() {
1421         return new external_function_parameters(
1422             array(
1423                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1424                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1425                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1426                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1427             )
1428         );
1429     }
1431     /**
1432      * Get messagearea search messages results.
1433      *
1434      * @param int $userid The id of the user who is performing the search
1435      * @param string $search The string being searched
1436      * @param int $limitfrom
1437      * @param int $limitnum
1438      * @return stdClass
1439      * @throws moodle_exception
1440      * @since 3.2
1441      */
1442     public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1443         global $CFG, $PAGE, $USER;
1445         // Check if messaging is enabled.
1446         if (empty($CFG->messaging)) {
1447             throw new moodle_exception('disabled', 'message');
1448         }
1450         $systemcontext = context_system::instance();
1452         $params = array(
1453             'userid' => $userid,
1454             'search' => $search,
1455             'limitfrom' => $limitfrom,
1456             'limitnum' => $limitnum
1458         );
1459         $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1460         self::validate_context($systemcontext);
1462         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1463             throw new moodle_exception('You do not have permission to perform this action.');
1464         }
1466         $messages = \core_message\api::search_messages(
1467             $params['userid'],
1468             $params['search'],
1469             $params['limitfrom'],
1470             $params['limitnum']
1471         );
1472         $results = new \core_message\output\messagearea\message_search_results($messages);
1474         $renderer = $PAGE->get_renderer('core_message');
1475         return $results->export_for_template($renderer);
1476     }
1478     /**
1479      * Get messagearea search messages returns.
1480      *
1481      * @return external_single_structure
1482      * @since 3.2
1483      */
1484     public static function data_for_messagearea_search_messages_returns() {
1485         return new external_single_structure(
1486             array(
1487                 'contacts' => new external_multiple_structure(
1488                     self::get_messagearea_contact_structure()
1489                 )
1490             )
1491         );
1492     }
1494     /**
1495      * Get conversations parameters.
1496      *
1497      * @return external_function_parameters
1498      * @since 3.6
1499      */
1500     public static function get_conversations_parameters() {
1501         return new external_function_parameters(
1502             array(
1503                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1504                 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1505                 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1506                 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1507                 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1508                 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1509                     VALUE_DEFAULT, null),
1511             )
1512         );
1513     }
1515     /**
1516      * Get the list of conversations for the user.
1517      *
1518      * @param int $userid The id of the user who is performing the search
1519      * @param int $limitfrom
1520      * @param int $limitnum
1521      * @param int|null $type
1522      * @param bool|null $favourites
1523      * @return stdClass
1524      * @throws \moodle_exception if the messaging feature is disabled on the site.
1525      * @since 3.2
1526      */
1527     public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null) {
1528         global $CFG, $USER;
1530         // All the standard BL checks.
1531         if (empty($CFG->messaging)) {
1532             throw new moodle_exception('disabled', 'message');
1533         }
1535         $params = array(
1536             'userid' => $userid,
1537             'limitfrom' => $limitfrom,
1538             'limitnum' => $limitnum,
1539             'type' => $type,
1540             'favourites' => $favourites
1541         );
1542         $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1544         $systemcontext = context_system::instance();
1545         self::validate_context($systemcontext);
1547         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1548             throw new moodle_exception('You do not have permission to perform this action.');
1549         }
1551         $conversations = \core_message\api::get_conversations(
1552             $params['userid'],
1553             $params['limitfrom'],
1554             $params['limitnum'],
1555             $params['type'],
1556             $params['favourites']
1557         );
1559         return (object) ['conversations' => $conversations];
1560     }
1562     /**
1563      * Get conversations returns.
1564      *
1565      * @return external_single_structure
1566      * @since 3.6
1567      */
1568     public static function get_conversations_returns() {
1569         return new external_single_structure(
1570             [
1571                 'conversations' => new external_multiple_structure(
1572                     self::get_conversation_structure()
1573                 )
1574             ]
1575         );
1576     }
1578     /**
1579      * The messagearea conversations parameters.
1580      *
1581      * @deprecated since 3.6
1582      * @return external_function_parameters
1583      * @since 3.2
1584      */
1585     public static function data_for_messagearea_conversations_parameters() {
1586         return new external_function_parameters(
1587             array(
1588                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1589                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1590                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1591             )
1592         );
1593     }
1595     /**
1596      * Get messagearea conversations.
1597      *
1598      * NOTE FOR FINAL DEPRECATION:
1599      * When removing this method, please also consider removal of get_conversations_legacy_formatter()
1600      * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
1601      * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
1602      * removed.
1603      *
1604      * @deprecated since 3.6
1605      * @param int $userid The id of the user who we are viewing conversations for
1606      * @param int $limitfrom
1607      * @param int $limitnum
1608      * @return stdClass
1609      * @throws moodle_exception
1610      * @since 3.2
1611      */
1612     public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1613         global $CFG, $PAGE, $USER;
1615         // Check if messaging is enabled.
1616         if (empty($CFG->messaging)) {
1617             throw new moodle_exception('disabled', 'message');
1618         }
1620         $systemcontext = context_system::instance();
1622         $params = array(
1623             'userid' => $userid,
1624             'limitfrom' => $limitfrom,
1625             'limitnum' => $limitnum
1626         );
1627         $params = self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1628         self::validate_context($systemcontext);
1630         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1631             throw new moodle_exception('You do not have permission to perform this action.');
1632         }
1634         $conversations = \core_message\api::get_conversations($params['userid'], $params['limitfrom'], $params['limitnum']);
1636         // Format the conversations in the legacy style, as the get_conversations method has since been changed.
1637         $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
1639         $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1641         $renderer = $PAGE->get_renderer('core_message');
1642         return $conversations->export_for_template($renderer);
1643     }
1645     /**
1646      * The messagearea conversations return structure.
1647      *
1648      * @deprecated since 3.6
1649      * @return external_single_structure
1650      * @since 3.2
1651      */
1652     public static function data_for_messagearea_conversations_returns() {
1653         return new external_single_structure(
1654             array(
1655                 'contacts' => new external_multiple_structure(
1656                     self::get_messagearea_contact_structure()
1657                 )
1658             )
1659         );
1660     }
1662     /**
1663      * Marking the method as deprecated.
1664      *
1665      * @return bool
1666      */
1667     public static function data_for_messagearea_conversations_is_deprecated() {
1668         return true;
1669     }
1671     /**
1672      * The messagearea contacts return parameters.
1673      *
1674      * @deprecated since 3.6
1675      * @return external_function_parameters
1676      * @since 3.2
1677      */
1678     public static function data_for_messagearea_contacts_parameters() {
1679         return self::data_for_messagearea_conversations_parameters();
1680     }
1682     /**
1683      * Get messagearea contacts parameters.
1684      *
1685      * @deprecated since 3.6
1686      * @param int $userid The id of the user who we are viewing conversations for
1687      * @param int $limitfrom
1688      * @param int $limitnum
1689      * @return stdClass
1690      * @throws moodle_exception
1691      * @since 3.2
1692      */
1693     public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1694         global $CFG, $PAGE, $USER;
1696         // Check if messaging is enabled.
1697         if (empty($CFG->messaging)) {
1698             throw new moodle_exception('disabled', 'message');
1699         }
1701         $systemcontext = context_system::instance();
1703         $params = array(
1704             'userid' => $userid,
1705             'limitfrom' => $limitfrom,
1706             'limitnum' => $limitnum
1707         );
1708         $params = self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1709         self::validate_context($systemcontext);
1711         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1712             throw new moodle_exception('You do not have permission to perform this action.');
1713         }
1715         $contacts = \core_message\api::get_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1716         $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1718         $renderer = $PAGE->get_renderer('core_message');
1719         return $contacts->export_for_template($renderer);
1720     }
1722     /**
1723      * The messagearea contacts return structure.
1724      *
1725      * @deprecated since 3.6
1726      * @return external_single_structure
1727      * @since 3.2
1728      */
1729     public static function data_for_messagearea_contacts_returns() {
1730         return self::data_for_messagearea_conversations_returns();
1731     }
1733     /**
1734      * Marking the method as deprecated.
1735      *
1736      * @return bool
1737      */
1738     public static function data_for_messagearea_contacts_is_deprecated() {
1739         return true;
1740     }
1742     /**
1743      * The messagearea messages parameters.
1744      *
1745      * @deprecated since 3.6
1746      * @return external_function_parameters
1747      * @since 3.2
1748      */
1749     public static function data_for_messagearea_messages_parameters() {
1750         return new external_function_parameters(
1751             array(
1752                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1753                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1754                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1755                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1756                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1757                 'timefrom' => new external_value(PARAM_INT,
1758                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1759             )
1760         );
1761     }
1763     /**
1764      * Get messagearea messages.
1765      *
1766      * @deprecated since 3.6
1767      * @param int $currentuserid The current user's id
1768      * @param int $otheruserid The other user's id
1769      * @param int $limitfrom
1770      * @param int $limitnum
1771      * @param boolean $newest
1772      * @return stdClass
1773      * @throws moodle_exception
1774      * @since 3.2
1775      */
1776     public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1777                                                          $newest = false, $timefrom = 0) {
1778         global $CFG, $PAGE, $USER;
1780         // Check if messaging is enabled.
1781         if (empty($CFG->messaging)) {
1782             throw new moodle_exception('disabled', 'message');
1783         }
1785         $systemcontext = context_system::instance();
1787         $params = array(
1788             'currentuserid' => $currentuserid,
1789             'otheruserid' => $otheruserid,
1790             'limitfrom' => $limitfrom,
1791             'limitnum' => $limitnum,
1792             'newest' => $newest,
1793             'timefrom' => $timefrom,
1794         );
1795         $params = self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1796         self::validate_context($systemcontext);
1798         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1799             throw new moodle_exception('You do not have permission to perform this action.');
1800         }
1802         if ($params['newest']) {
1803             $sort = 'timecreated DESC';
1804         } else {
1805             $sort = 'timecreated ASC';
1806         }
1808         // We need to enforce a one second delay on messages to avoid race conditions of current
1809         // messages still being sent.
1810         //
1811         // There is a chance that we could request messages before the current time's
1812         // second has elapsed and while other messages are being sent in that same second. In which
1813         // case those messages will be lost.
1814         //
1815         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1816         if (!empty($params['timefrom'])) {
1817             $timeto = time() - 1;
1818         } else {
1819             $timeto = 0;
1820         }
1822         // No requesting messages from the current time, as stated above.
1823         if ($params['timefrom'] == time()) {
1824             $messages = [];
1825         } else {
1826             $messages = \core_message\api::get_messages($params['currentuserid'], $params['otheruserid'], $params['limitfrom'],
1827                                                         $params['limitnum'], $sort, $params['timefrom'], $timeto);
1828         }
1830         $messages = new \core_message\output\messagearea\messages($params['currentuserid'], $params['otheruserid'], $messages);
1832         $renderer = $PAGE->get_renderer('core_message');
1833         return $messages->export_for_template($renderer);
1834     }
1836     /**
1837      * The messagearea messages return structure.
1838      *
1839      * @deprecated since 3.6
1840      * @return external_single_structure
1841      * @since 3.2
1842      */
1843     public static function data_for_messagearea_messages_returns() {
1844         return new external_single_structure(
1845             array(
1846                 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1847                     the messages on behalf of?'),
1848                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1849                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1850                 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1851                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1852                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1853                 'messages' => new external_multiple_structure(
1854                     self::get_messagearea_message_structure()
1855                 ),
1856                 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1857             )
1858         );
1859     }
1861     /**
1862      * Marking the method as deprecated.
1863      *
1864      * @return bool
1865      */
1866     public static function data_for_messagearea_messages_is_deprecated() {
1867         return true;
1868     }
1870     /**
1871      * The conversation messages parameters.
1872      *
1873      * @return external_function_parameters
1874      * @since 3.6
1875      */
1876     public static function get_conversation_messages_parameters() {
1877         return new external_function_parameters(
1878             array(
1879                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1880                 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1881                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1882                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1883                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1884                 'timefrom' => new external_value(PARAM_INT,
1885                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1886             )
1887         );
1888     }
1890     /**
1891      * Get conversation messages.
1892      *
1893      * @param  int $currentuserid The current user's id.
1894      * @param  int $convid The conversation id.
1895      * @param  int $limitfrom Return a subset of records, starting at this point (optional).
1896      * @param  int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1897      * @param  bool $newest True for getting first newest messages, false otherwise.
1898      * @param  int  $timefrom The time from the conversation messages to get.
1899      * @return stdClass The messages and members who have sent some of these messages.
1900      * @throws moodle_exception
1901      * @since 3.6
1902      */
1903     public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1904                                                          bool $newest = false, int $timefrom = 0) {
1905         global $CFG, $PAGE, $USER;
1907         // Check if messaging is enabled.
1908         if (empty($CFG->messaging)) {
1909             throw new moodle_exception('disabled', 'message');
1910         }
1912         $systemcontext = context_system::instance();
1914         $params = array(
1915             'currentuserid' => $currentuserid,
1916             'convid' => $convid,
1917             'limitfrom' => $limitfrom,
1918             'limitnum' => $limitnum,
1919             'newest' => $newest,
1920             'timefrom' => $timefrom,
1921         );
1922         $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1923         self::validate_context($systemcontext);
1925         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1926             throw new moodle_exception('You do not have permission to perform this action.');
1927         }
1929         $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1931         // We need to enforce a one second delay on messages to avoid race conditions of current
1932         // messages still being sent.
1933         //
1934         // There is a chance that we could request messages before the current time's
1935         // second has elapsed and while other messages are being sent in that same second. In which
1936         // case those messages will be lost.
1937         //
1938         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1939         $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1941         // No requesting messages from the current time, as stated above.
1942         if ($params['timefrom'] == time()) {
1943             $messages = [];
1944         } else {
1945             $messages = \core_message\api::get_conversation_messages(
1946                 $params['currentuserid'],
1947                 $params['convid'],
1948                 $params['limitfrom'],
1949                 $params['limitnum'],
1950                 $sort,
1951                 $params['timefrom'],
1952                 $timeto);
1953         }
1955         return $messages;
1956     }
1958     /**
1959      * The messagearea messages return structure.
1960      *
1961      * @return external_single_structure
1962      * @since 3.6
1963      */
1964     public static function get_conversation_messages_returns() {
1965         return new external_single_structure(
1966             array(
1967                 'id' => new external_value(PARAM_INT, 'The conversation id'),
1968                 'members' => new external_multiple_structure(
1969                     self::get_conversation_member_structure()
1970                 ),
1971                 'messages' => new external_multiple_structure(
1972                     self::get_conversation_message_structure()
1973                 ),
1974             )
1975         );
1976     }
1978     /**
1979      * The get most recent message return parameters.
1980      *
1981      * @deprecated since 3.6
1982      * @return external_function_parameters
1983      * @since 3.2
1984      */
1985     public static function data_for_messagearea_get_most_recent_message_parameters() {
1986         return new external_function_parameters(
1987             array(
1988                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1989                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1990             )
1991         );
1992     }
1994     /**
1995      * Get the most recent message in a conversation.
1996      *
1997      * @deprecated since 3.6
1998      * @param int $currentuserid The current user's id
1999      * @param int $otheruserid The other user's id
2000      * @return stdClass
2001      * @throws moodle_exception
2002      * @since 3.2
2003      */
2004     public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
2005         global $CFG, $PAGE, $USER;
2007         // Check if messaging is enabled.
2008         if (empty($CFG->messaging)) {
2009             throw new moodle_exception('disabled', 'message');
2010         }
2012         $systemcontext = context_system::instance();
2014         $params = array(
2015             'currentuserid' => $currentuserid,
2016             'otheruserid' => $otheruserid
2017         );
2018         $params = self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
2019         self::validate_context($systemcontext);
2021         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2022             throw new moodle_exception('You do not have permission to perform this action.');
2023         }
2025         $message = \core_message\api::get_most_recent_message($params['currentuserid'], $params['otheruserid']);
2026         $message = new \core_message\output\messagearea\message($message);
2028         $renderer = $PAGE->get_renderer('core_message');
2029         return $message->export_for_template($renderer);
2030     }
2032     /**
2033      * The get most recent message return structure.
2034      *
2035      * @deprecated since 3.6
2036      * @return external_single_structure
2037      * @since 3.2
2038      */
2039     public static function data_for_messagearea_get_most_recent_message_returns() {
2040         return self::get_messagearea_message_structure();
2041     }
2043     /**
2044      * Marking the method as deprecated.
2045      *
2046      * @return bool
2047      */
2048     public static function data_for_messagearea_get_most_recent_message_is_deprecated() {
2049         return true;
2050     }
2052     /**
2053      * The get profile parameters.
2054      *
2055      * @deprecated since 3.6
2056      * @return external_function_parameters
2057      * @since 3.2
2058      */
2059     public static function data_for_messagearea_get_profile_parameters() {
2060         return new external_function_parameters(
2061             array(
2062                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2063                 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
2064             )
2065         );
2066     }
2068     /**
2069      * Get the profile information for a contact.
2070      *
2071      * @deprecated since 3.6
2072      * @param int $currentuserid The current user's id
2073      * @param int $otheruserid The id of the user whose profile we are viewing
2074      * @return stdClass
2075      * @throws moodle_exception
2076      * @since 3.2
2077      */
2078     public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
2079         global $CFG, $PAGE, $USER;
2081         // Check if messaging is enabled.
2082         if (empty($CFG->messaging)) {
2083             throw new moodle_exception('disabled', 'message');
2084         }
2086         $systemcontext = context_system::instance();
2088         $params = array(
2089             'currentuserid' => $currentuserid,
2090             'otheruserid' => $otheruserid
2091         );
2092         $params = self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
2093         self::validate_context($systemcontext);
2095         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2096             throw new moodle_exception('You do not have permission to perform this action.');
2097         }
2099         $profile = \core_message\api::get_profile($params['currentuserid'], $params['otheruserid']);
2100         $profile = new \core_message\output\messagearea\profile($profile);
2102         $renderer = $PAGE->get_renderer('core_message');
2103         return $profile->export_for_template($renderer);
2104     }
2106     /**
2107      * The get profile return structure.
2108      *
2109      * @deprecated since 3.6
2110      * @return external_single_structure
2111      * @since 3.2
2112      */
2113     public static function data_for_messagearea_get_profile_returns() {
2114         return new external_single_structure(
2115             array(
2116                 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
2117                 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
2118                 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
2119                 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
2120                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
2121                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
2122                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
2123                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2124                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2125                 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
2126                 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
2127             )
2128         );
2129     }
2131     /**
2132      * Marking the method as deprecated.
2133      *
2134      * @return bool
2135      */
2136     public static function data_for_messagearea_get_profile_is_deprecated() {
2137         return true;
2138     }
2140     /**
2141      * Get contacts parameters description.
2142      *
2143      * @return external_function_parameters
2144      * @since Moodle 2.5
2145      */
2146     public static function get_contacts_parameters() {
2147         return new external_function_parameters(array());
2148     }
2150     /**
2151      * Get contacts.
2152      *
2153      * @return external_description
2154      * @since Moodle 2.5
2155      */
2156     public static function get_contacts() {
2157         global $CFG, $PAGE, $USER;
2159         // Check if messaging is enabled.
2160         if (empty($CFG->messaging)) {
2161             throw new moodle_exception('disabled', 'message');
2162         }
2164         require_once($CFG->dirroot . '/user/lib.php');
2166         $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
2167         $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
2168         foreach ($contacts as $contact) {
2169             // Set the mode.
2170             $mode = 'offline';
2171             if (\core_message\helper::is_online($contact->lastaccess)) {
2172                 $mode = 'online';
2173             }
2175             $newcontact = array(
2176                 'id' => $contact->id,
2177                 'fullname' => fullname($contact),
2178                 'unread' => $contact->messagecount
2179             );
2181             $userpicture = new user_picture($contact);
2182             $userpicture->size = 1; // Size f1.
2183             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2184             $userpicture->size = 0; // Size f2.
2185             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2187             $allcontacts[$mode][$contact->id] = $newcontact;
2188         }
2190         $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
2191         foreach ($strangers as $contact) {
2192             $newcontact = array(
2193                 'id' => $contact->id,
2194                 'fullname' => fullname($contact),
2195                 'unread' => $contact->messagecount
2196             );
2198             $userpicture = new user_picture($contact);
2199             $userpicture->size = 1; // Size f1.
2200             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2201             $userpicture->size = 0; // Size f2.
2202             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2204             $allcontacts['strangers'][$contact->id] = $newcontact;
2205         }
2207         // Add noreply user and support user to the list, if they don't exist.
2208         $supportuser = core_user::get_support_user();
2209         if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
2210             $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
2211             if ($supportuser->messagecount > 0) {
2212                 $supportuser->fullname = fullname($supportuser);
2213                 $supportuser->unread = $supportuser->messagecount;
2214                 $allcontacts['strangers'][$supportuser->id] = $supportuser;
2215             }
2216         }
2218         $noreplyuser = core_user::get_noreply_user();
2219         if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
2220             $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
2221             if ($noreplyuser->messagecount > 0) {
2222                 $noreplyuser->fullname = fullname($noreplyuser);
2223                 $noreplyuser->unread = $noreplyuser->messagecount;
2224                 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
2225             }
2226         }
2228         return $allcontacts;
2229     }
2231     /**
2232      * Get contacts return description.
2233      *
2234      * @return external_description
2235      * @since Moodle 2.5
2236      */
2237     public static function get_contacts_returns() {
2238         return new external_single_structure(
2239             array(
2240                 'online' => new external_multiple_structure(
2241                     new external_single_structure(
2242                         array(
2243                             'id' => new external_value(PARAM_INT, 'User ID'),
2244                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2245                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2246                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2247                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2248                         )
2249                     ),
2250                     'List of online contacts'
2251                 ),
2252                 'offline' => new external_multiple_structure(
2253                     new external_single_structure(
2254                         array(
2255                             'id' => new external_value(PARAM_INT, 'User ID'),
2256                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2257                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2258                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2259                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2260                         )
2261                     ),
2262                     'List of offline contacts'
2263                 ),
2264                 'strangers' => new external_multiple_structure(
2265                     new external_single_structure(
2266                         array(
2267                             'id' => new external_value(PARAM_INT, 'User ID'),
2268                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2269                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2270                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2271                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2272                         )
2273                     ),
2274                     'List of users that are not in the user\'s contact list but have sent a message'
2275                 )
2276             )
2277         );
2278     }
2280     /**
2281      * Search contacts parameters description.
2282      *
2283      * @return external_function_parameters
2284      * @since Moodle 2.5
2285      */
2286     public static function search_contacts_parameters() {
2287         return new external_function_parameters(
2288             array(
2289                 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2290                 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2291                     VALUE_DEFAULT, false)
2292             )
2293         );
2294     }
2296     /**
2297      * Search contacts.
2298      *
2299      * @param string $searchtext query string.
2300      * @param bool $onlymycourses limit the search to the user's courses only.
2301      * @return external_description
2302      * @since Moodle 2.5
2303      */
2304     public static function search_contacts($searchtext, $onlymycourses = false) {
2305         global $CFG, $USER, $PAGE;
2306         require_once($CFG->dirroot . '/user/lib.php');
2308         // Check if messaging is enabled.
2309         if (empty($CFG->messaging)) {
2310             throw new moodle_exception('disabled', 'message');
2311         }
2313         require_once($CFG->libdir . '/enrollib.php');
2315         $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2316         $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2318         // Extra validation, we do not allow empty queries.
2319         if ($params['searchtext'] === '') {
2320             throw new moodle_exception('querystringcannotbeempty');
2321         }
2323         $courseids = array();
2324         if ($params['onlymycourses']) {
2325             $mycourses = enrol_get_my_courses(array('id'));
2326             foreach ($mycourses as $mycourse) {
2327                 $courseids[] = $mycourse->id;
2328             }
2329         } else {
2330             $courseids[] = SITEID;
2331         }
2333         // Retrieving the users matching the query.
2334         $users = message_search_users($courseids, $params['searchtext']);
2335         $results = array();
2336         foreach ($users as $user) {
2337             $results[$user->id] = $user;
2338         }
2340         // Reorganising information.
2341         foreach ($results as &$user) {
2342             $newuser = array(
2343                 'id' => $user->id,
2344                 'fullname' => fullname($user)
2345             );
2347             // Avoid undefined property notice as phone not specified.
2348             $user->phone1 = null;
2349             $user->phone2 = null;
2351             $userpicture = new user_picture($user);
2352             $userpicture->size = 1; // Size f1.
2353             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2354             $userpicture->size = 0; // Size f2.
2355             $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2357             $user = $newuser;
2358         }
2360         return $results;
2361     }
2363     /**
2364      * Search contacts return description.
2365      *
2366      * @return external_description
2367      * @since Moodle 2.5
2368      */
2369     public static function search_contacts_returns() {
2370         return new external_multiple_structure(
2371             new external_single_structure(
2372                 array(
2373                     'id' => new external_value(PARAM_INT, 'User ID'),
2374                     'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2375                     'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2376                     'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
2377                 )
2378             ),
2379             'List of contacts'
2380         );
2381     }
2383     /**
2384      * Get messages parameters description.
2385      *
2386      * @return external_function_parameters
2387      * @since 2.8
2388      */
2389     public static function get_messages_parameters() {
2390         return new external_function_parameters(
2391             array(
2392                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2393                 'useridfrom' => new external_value(
2394                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2395                     VALUE_DEFAULT, 0),
2396                 'type' => new external_value(
2397                     PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2398                     VALUE_DEFAULT, 'both'),
2399                 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2400                 'newestfirst' => new external_value(
2401                     PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2402                     VALUE_DEFAULT, true),
2403                 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2404                 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2405             )
2406         );
2407     }
2409     /**
2410      * Get messages function implementation.
2411      *
2412      * @since  2.8
2413      * @throws invalid_parameter_exception
2414      * @throws moodle_exception
2415      * @param  int      $useridto       the user id who received the message
2416      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2417      * @param  string   $type           type of message to return, expected values: notifications, conversations and both
2418      * @param  bool     $read           true for retreiving read messages, false for unread
2419      * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
2420      * @param  int      $limitfrom      limit from
2421      * @param  int      $limitnum       limit num
2422      * @return external_description
2423      */
2424     public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2425                                         $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2426         global $CFG, $USER;
2428         $warnings = array();
2430         $params = array(
2431             'useridto' => $useridto,
2432             'useridfrom' => $useridfrom,
2433             'type' => $type,
2434             'read' => $read,
2435             'newestfirst' => $newestfirst,
2436             'limitfrom' => $limitfrom,
2437             'limitnum' => $limitnum
2438         );
2440         $params = self::validate_parameters(self::get_messages_parameters(), $params);
2442         $context = context_system::instance();
2443         self::validate_context($context);
2445         $useridto = $params['useridto'];
2446         $useridfrom = $params['useridfrom'];
2447         $type = $params['type'];
2448         $read = $params['read'];
2449         $newestfirst = $params['newestfirst'];
2450         $limitfrom = $params['limitfrom'];
2451         $limitnum = $params['limitnum'];
2453         $allowedvalues = array('notifications', 'conversations', 'both');
2454         if (!in_array($type, $allowedvalues)) {
2455             throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2456                 'allowed values are: ' . implode(',', $allowedvalues));
2457         }
2459         // Check if private messaging between users is allowed.
2460         if (empty($CFG->messaging)) {
2461             // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2462             if ($type == "conversations") {
2463                 throw new moodle_exception('disabled', 'message');
2464             }
2465             if ($type == "both") {
2466                 $warning = array();
2467                 $warning['item'] = 'message';
2468                 $warning['itemid'] = $USER->id;
2469                 $warning['warningcode'] = '1';
2470                 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2471                     Only notifications will be returned';
2472                 $warnings[] = $warning;
2473             }
2474         }
2476         if (!empty($useridto)) {
2477             if (core_user::is_real_user($useridto)) {
2478                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2479             } else {
2480                 throw new moodle_exception('invaliduser');
2481             }
2482         }
2484         if (!empty($useridfrom)) {
2485             // We use get_user here because the from user can be the noreply or support user.
2486             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2487         }
2489         // Check if the current user is the sender/receiver or just a privileged user.
2490         if ($useridto != $USER->id and $useridfrom != $USER->id and
2491              !has_capability('moodle/site:readallmessages', $context)) {
2492             throw new moodle_exception('accessdenied', 'admin');
2493         }
2495         // Which type of messages to retrieve.
2496         $notifications = -1;
2497         if ($type != 'both') {
2498             $notifications = ($type == 'notifications') ? 1 : 0;
2499         }
2501         $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2502         $sort = "mr.timecreated $orderdirection";
2504         if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2505             $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2507             // In some cases, we don't need to get the to/from user objects from the sql query.
2508             $userfromfullname = '';
2509             $usertofullname = '';
2511             // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2512             if (!empty($useridto)) {
2513                 $usertofullname = fullname($userto, $canviewfullname);
2514                 // The user from may or may not be filled.
2515                 if (!empty($useridfrom)) {
2516                     $userfromfullname = fullname($userfrom, $canviewfullname);
2517                 }
2518             } else {
2519                 // If the useridto field is empty, the useridfrom must be filled.
2520                 $userfromfullname = fullname($userfrom, $canviewfullname);
2521             }
2522             foreach ($messages as $mid => $message) {
2524                 // Do not return deleted messages.
2525                 if (!$message->notification) {
2526                     if (($useridto == $USER->id and $message->timeusertodeleted) or
2527                         ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2528                         unset($messages[$mid]);
2529                         continue;
2530                     }
2531                 }
2533                 // We need to get the user from the query.
2534                 if (empty($userfromfullname)) {
2535                     // Check for non-reply and support users.
2536                     if (core_user::is_real_user($message->useridfrom)) {
2537                         $user = new stdClass();
2538                         $user = username_load_fields_from_object($user, $message, 'userfrom');
2539                         $message->userfromfullname = fullname($user, $canviewfullname);
2540                     } else {
2541                         $user = core_user::get_user($message->useridfrom);
2542                         $message->userfromfullname = fullname($user, $canviewfullname);
2543                     }
2544                 } else {
2545                     $message->userfromfullname = $userfromfullname;
2546                 }
2548                 // We need to get the user from the query.
2549                 if (empty($usertofullname)) {
2550                     $user = new stdClass();
2551                     $user = username_load_fields_from_object($user, $message, 'userto');
2552                     $message->usertofullname = fullname($user, $canviewfullname);
2553                 } else {
2554                     $message->usertofullname = $usertofullname;
2555                 }
2557                 $message->text = message_format_message_text($message);
2558                 $messages[$mid] = (array) $message;
2559             }
2560         }
2562         $results = array(
2563             'messages' => $messages,
2564             'warnings' => $warnings
2565         );
2567         return $results;
2568     }
2570     /**
2571      * Get messages return description.
2572      *
2573      * @return external_single_structure
2574      * @since 2.8
2575      */
2576     public static function get_messages_returns() {
2577         return new external_single_structure(
2578             array(
2579                 'messages' => new external_multiple_structure(
2580                     new external_single_structure(
2581                         array(
2582                             'id' => new external_value(PARAM_INT, 'Message id'),
2583                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2584                             'useridto' => new external_value(PARAM_INT, 'User to id'),
2585                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2586                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
2587                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2588                             'fullmessageformat' => new external_format_value('fullmessage'),
2589                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2590                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2591                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2592                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2593                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2594                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
2595                             'timeread' => new external_value(PARAM_INT, 'Time read'),
2596                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2597                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2598                         ), 'message'
2599                     )
2600                 ),
2601                 'warnings' => new external_warnings()
2602             )
2603         );
2604     }
2606     /**
2607      * Mark all notifications as read parameters description.
2608      *
2609      * @return external_function_parameters
2610      * @since 3.2
2611      */
2612     public static function mark_all_notifications_as_read_parameters() {
2613         return new external_function_parameters(
2614             array(
2615                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2616                 'useridfrom' => new external_value(
2617                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2618                     VALUE_DEFAULT, 0),
2619             )
2620         );
2621     }
2623     /**
2624      * Mark all notifications as read function.
2625      *
2626      * @since  3.2
2627      * @throws invalid_parameter_exception
2628      * @throws moodle_exception
2629      * @param  int      $useridto       the user id who received the message
2630      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2631      * @return external_description
2632      */
2633     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2634         global $USER;
2636         $params = self::validate_parameters(
2637             self::mark_all_notifications_as_read_parameters(),
2638             array(
2639                 'useridto' => $useridto,
2640                 'useridfrom' => $useridfrom,
2641             )
2642         );
2644         $context = context_system::instance();
2645         self::validate_context($context);
2647         $useridto = $params['useridto'];
2648         $useridfrom = $params['useridfrom'];
2650         if (!empty($useridto)) {
2651             if (core_user::is_real_user($useridto)) {
2652                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2653             } else {
2654                 throw new moodle_exception('invaliduser');
2655             }
2656         }
2658         if (!empty($useridfrom)) {
2659             // We use get_user here because the from user can be the noreply or support user.
2660             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2661         }
2663         // Check if the current user is the sender/receiver or just a privileged user.
2664         if ($useridto != $USER->id and $useridfrom != $USER->id and
2665             // The deleteanymessage cap seems more reasonable here than readallmessages.
2666              !has_capability('moodle/site:deleteanymessage', $context)) {
2667             throw new moodle_exception('accessdenied', 'admin');
2668         }
2670         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2672         return true;
2673     }
2675     /**
2676      * Mark all notifications as read return description.
2677      *
2678      * @return external_single_structure
2679      * @since 3.2
2680      */
2681     public static function mark_all_notifications_as_read_returns() {
2682         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2683     }
2685     /**
2686      * Get unread conversations count parameters description.
2687      *
2688      * @return external_function_parameters
2689      * @since 3.2
2690      */
2691     public static function get_unread_conversations_count_parameters() {
2692         return new external_function_parameters(
2693             array(
2694                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2695             )
2696         );
2697     }
2699     /**
2700      * Get unread messages count function.
2701      *
2702      * @since  3.2
2703      * @throws invalid_parameter_exception
2704      * @throws moodle_exception
2705      * @param  int      $useridto       the user id who received the message
2706      * @return external_description
2707      */
2708     public static function get_unread_conversations_count($useridto) {
2709         global $USER, $CFG;
2711         // Check if messaging is enabled.
2712         if (empty($CFG->messaging)) {
2713             throw new moodle_exception('disabled', 'message');
2714         }
2716         $params = self::validate_parameters(
2717             self::get_unread_conversations_count_parameters(),
2718             array('useridto' => $useridto)
2719         );
2721         $context = context_system::instance();
2722         self::validate_context($context);
2724         $useridto = $params['useridto'];
2726         if (!empty($useridto)) {
2727             if (core_user::is_real_user($useridto)) {
2728                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2729             } else {
2730                 throw new moodle_exception('invaliduser');
2731             }
2732         } else {
2733             $useridto = $USER->id;
2734         }
2736         // Check if the current user is the receiver or just a privileged user.
2737         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2738             throw new moodle_exception('accessdenied', 'admin');
2739         }
2741         return \core_message\api::count_unread_conversations($userto);
2742     }
2744     /**
2745      * Get unread conversations count return description.
2746      *
2747      * @return external_single_structure
2748      * @since 3.2
2749      */
2750     public static function get_unread_conversations_count_returns() {
2751         return new external_value(PARAM_INT, 'The count of unread messages for the user');
2752     }
2754     /**
2755      * Get blocked users parameters description.
2756      *
2757      * @return external_function_parameters
2758      * @since 2.9
2759      */
2760     public static function get_blocked_users_parameters() {
2761         return new external_function_parameters(
2762             array(
2763                 'userid' => new external_value(PARAM_INT,
2764                                 'the user whose blocked users we want to retrieve',
2765                                 VALUE_REQUIRED),
2766             )
2767         );
2768     }
2770     /**
2771      * Retrieve a list of users blocked
2772      *
2773      * @param  int $userid the user whose blocked users we want to retrieve
2774      * @return external_description
2775      * @since 2.9
2776      */
2777     public static function get_blocked_users($userid) {
2778         global $CFG, $USER, $PAGE;
2780         // Warnings array, it can be empty at the end but is mandatory.
2781         $warnings = array();
2783         // Validate params.
2784         $params = array(
2785             'userid' => $userid
2786         );
2787         $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2788         $userid = $params['userid'];
2790         // Validate context.
2791         $context = context_system::instance();
2792         self::validate_context($context);
2794         // Check if private messaging between users is allowed.
2795         if (empty($CFG->messaging)) {
2796             throw new moodle_exception('disabled', 'message');
2797         }
2799         $user = core_user::get_user($userid, '*', MUST_EXIST);
2800         core_user::require_active_user($user);
2802         // Check if we have permissions for retrieve the information.
2803         $capability = 'moodle/site:manageallmessaging';
2804         if (($USER->id != $userid) && !has_capability($capability, $context)) {
2805             throw new required_capability_exception($context, $capability, 'nopermissions', '');
2806         }
2808         // Now, we can get safely all the blocked users.
2809         $users = \core_message\api::get_blocked_users($user->id);
2811         $blockedusers = array();
2812         foreach ($users as $user) {
2813             $newuser = array(
2814                 'id' => $user->id,
2815                 'fullname' => fullname($user),
2816             );
2818             $userpicture = new user_picture($user);
2819             $userpicture->size = 1; // Size f1.
2820             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2822             $blockedusers[] = $newuser;
2823         }
2825         $results = array(
2826             'users' => $blockedusers,
2827             'warnings' => $warnings
2828         );
2829         return $results;
2830     }
2832     /**
2833      * Get blocked users return description.
2834      *
2835      * @return external_single_structure
2836      * @since 2.9
2837      */
2838     public static function get_blocked_users_returns() {
2839         return new external_single_structure(
2840             array(
2841                 'users' => new external_multiple_structure(
2842                     new external_single_structure(
2843                         array(
2844                             'id' => new external_value(PARAM_INT, 'User ID'),
2845                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2846                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2847                         )
2848                     ),
2849                     'List of blocked users'
2850                 ),
2851                 'warnings' => new external_warnings()
2852             )
2853         );
2854     }
2856     /**
2857      * Returns description of method parameters
2858      *
2859      * @return external_function_parameters
2860      * @since 2.9
2861      */
2862     public static function mark_message_read_parameters() {
2863         return new external_function_parameters(
2864             array(
2865                 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2866                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2867                     VALUE_DEFAULT, 0)
2868             )
2869         );
2870     }
2872     /**
2873      * Mark a single message as read, trigger message_viewed event
2874      *
2875      * @param  int $messageid id of the message (in the message table)
2876      * @param  int $timeread timestamp for when the message should be marked read
2877      * @return external_description
2878      * @throws invalid_parameter_exception
2879      * @throws moodle_exception
2880      * @since 2.9
2881      */
2882     public static function mark_message_read($messageid, $timeread) {
2883         global $CFG, $DB, $USER;
2885         // Check if private messaging between users is allowed.
2886         if (empty($CFG->messaging)) {
2887             throw new moodle_exception('disabled', 'message');
2888         }
2890         // Warnings array, it can be empty at the end but is mandatory.
2891         $warnings = array();
2893         // Validate params.
2894         $params = array(
2895             'messageid' => $messageid,
2896             'timeread' => $timeread
2897         );
2898         $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2900         if (empty($params['timeread'])) {
2901             $timeread = time();
2902         } else {
2903             $timeread = $params['timeread'];
2904         }
2906         // Validate context.
2907         $context = context_system::instance();
2908         self::validate_context($context);
2910         $sql = "SELECT m.*, mcm.userid as useridto
2911                   FROM {messages} m
2912             INNER JOIN {message_conversations} mc
2913                     ON m.conversationid = mc.id
2914             INNER JOIN {message_conversation_members} mcm
2915                     ON mcm.conversationid = mc.id
2916              LEFT JOIN {message_user_actions} mua
2917                     ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2918                  WHERE mua.id is NULL
2919                    AND mcm.userid != m.useridfrom
2920                    AND m.id = ?";
2921         $messageparams = [];
2922         $messageparams[] = $USER->id;
2923         $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2924         $messageparams[] = $params['messageid'];
2925         $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2927         if ($message->useridto != $USER->id) {
2928             throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2929         }
2931         \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2933         $results = array(
2934             'messageid' => $message->id,
2935             'warnings' => $warnings
2936         );
2937         return $results;
2938     }
2940     /**
2941      * Returns description of method result value
2942      *
2943      * @return external_description
2944      * @since 2.9
2945      */
2946     public static function mark_message_read_returns() {
2947         return new external_single_structure(
2948             array(
2949                 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2950                 'warnings' => new external_warnings()
2951             )
2952         );
2953     }
2955     /**
2956      * Returns description of method parameters
2957      *
2958      * @return external_function_parameters
2959      */
2960     public static function mark_notification_read_parameters() {
2961         return new external_function_parameters(
2962             array(
2963                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2964                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2965                     VALUE_DEFAULT, 0)
2966             )
2967         );
2968     }
2970     /**
2971      * Mark a single notification as read.
2972      *
2973      * This will trigger a 'notification_viewed' event.
2974      *
2975      * @param int $notificationid id of the notification
2976      * @param int $timeread timestamp for when the notification should be marked read
2977      * @return external_description
2978      * @throws invalid_parameter_exception
2979      * @throws moodle_exception
2980      */
2981     public static function mark_notification_read($notificationid, $timeread) {
2982         global $CFG, $DB, $USER;
2984         // Check if private messaging between users is allowed.
2985         if (empty($CFG->messaging)) {
2986             throw new moodle_exception('disabled', 'message');
2987         }
2989         // Warnings array, it can be empty at the end but is mandatory.
2990         $warnings = array();
2992         // Validate params.
2993         $params = array(
2994             'notificationid' => $notificationid,
2995             'timeread' => $timeread
2996         );
2997         $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2999         if (empty($params['timeread'])) {
3000             $timeread = time();
3001         } else {
3002             $timeread = $params['timeread'];
3003         }
3005         // Validate context.
3006         $context = context_system::instance();
3007         self::validate_context($context);
3009         $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
3011         if ($notification->useridto != $USER->id) {
3012             throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
3013                 'notification as read');
3014         }
3016         \core_message\api::mark_notification_as_read($notification, $timeread);
3018         $results = array(
3019             'notificationid' => $notification->id,
3020             'warnings' => $warnings
3021         );
3023         return $results;
3024     }
3026     /**
3027      * Returns description of method result value
3028      *
3029      * @return external_description
3030      */
3031     public static function mark_notification_read_returns() {
3032         return new external_single_structure(
3033             array(
3034                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
3035                 'warnings' => new external_warnings()
3036             )
3037         );
3038     }
3040     /**
3041      * Mark all messages as read parameters description.
3042      *
3043      * @deprecated since 3.6
3044      * @return external_function_parameters
3045      * @since 3.2
3046      */
3047     public static function mark_all_messages_as_read_parameters() {
3048         return new external_function_parameters(
3049             array(
3050                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3051                 'useridfrom' => new external_value(
3052                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
3053                     VALUE_DEFAULT, 0),
3054             )
3055         );
3056     }
3058     /**
3059      * Mark all messages as read function.
3060      *
3061      * @deprecated since 3.6
3062      * @throws invalid_parameter_exception
3063      * @throws moodle_exception
3064      * @param  int      $useridto       the user id who received the message
3065      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
3066      * @return external_description
3067      * @since  3.2
3068      */
3069     public static function mark_all_messages_as_read($useridto, $useridfrom) {
3070         global $USER, $CFG;
3072         // Check if messaging is enabled.
3073         if (empty($CFG->messaging)) {
3074             throw new moodle_exception('disabled', 'message');
3075         }
3077         $params = self::validate_parameters(
3078             self::mark_all_messages_as_read_parameters(),
3079             array(
3080                 'useridto' => $useridto,
3081                 'useridfrom' => $useridfrom,
3082             )
3083         );
3085         $context = context_system::instance();
3086         self::validate_context($context);
3088         $useridto = $params['useridto'];
3089         $useridfrom = $params['useridfrom'];
3091         if (!empty($useridto)) {
3092             if (core_user::is_real_user($useridto)) {
3093                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3094             } else {
3095                 throw new moodle_exception('invaliduser');
3096             }
3097         }
3099         if (!empty($useridfrom)) {
3100             // We use get_user here because the from user can be the noreply or support user.
3101             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3102         }
3104         // Check if the current user is the sender/receiver or just a privileged user.
3105         if ($useridto != $USER->id and $useridfrom != $USER->id and
3106             // The deleteanymessage cap seems more reasonable here than readallmessages.
3107              !has_capability('moodle/site:deleteanymessage', $context)) {
3108             throw new moodle_exception('accessdenied', 'admin');
3109         }
3111         if ($useridfrom) {
3112             if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
3113                 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
3114             }
3115         } else {
3116             \core_message\api::mark_all_messages_as_read($useridto);
3117         }
3119         return true;
3120     }
3122     /**
3123      * Mark all messages as read return description.
3124      *
3125      * @deprecated since 3.6
3126      * @return external_single_structure
3127      * @since 3.2
3128      */
3129     public static function mark_all_messages_as_read_returns() {
3130         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
3131     }
3133     /**
3134      * Marking the method as deprecated.
3135      *
3136      * @return bool
3137      */
3138     public static function mark_all_messages_as_read_is_deprecated() {
3139         return true;
3140     }
3142     /**
3143      * Mark all conversation messages as read parameters description.
3144      *
3145      * @return external_function_parameters
3146      * @since 3.6
3147      */
3148     public static function mark_all_conversation_messages_as_read_parameters() {
3149         return new external_function_parameters(
3150             array(
3151                 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
3152                 'conversationid' =>
3153                     new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
3154             )
3155         );
3156     }
3158     /**
3159      * Mark all conversation messages as read function.
3160      *
3161      * @param int $userid The user id of who we want to delete the conversation for
3162      * @param int $conversationid The id of the conversations
3163      * @since 3.6
3164      */
3165     public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
3166         global $CFG;
3168         // Check if messaging is enabled.
3169         if (empty($CFG->messaging)) {
3170             throw new moodle_exception('disabled', 'message');
3171         }
3173         $params = array(
3174             'userid' => $userid,
3175             'conversationid' => $conversationid,
3176         );
3177         $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
3179         $context = context_system::instance();
3180         self::validate_context($context);
3182         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3183         core_user::require_active_user($user);
3185         if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
3186             \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
3187         } else {
3188             throw new moodle_exception('accessdenied', 'admin');
3189         }
3190     }
3192     /**
3193      * Mark all conversation messages as read return description.
3194      *
3195      * @return external_warnings
3196      * @since 3.6
3197      */
3198     public static function mark_all_conversation_messages_as_read_returns() {
3199         return new external_warnings();
3200     }
3202     /**
3203      * Returns description of method parameters.
3204      *
3205      * @deprecated since 3.6
3206      * @return external_function_parameters
3207      * @since 3.2
3208      */
3209     public static function delete_conversation_parameters() {
3210         return new external_function_parameters(
3211             array(
3212                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3213                 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
3214             )
3215         );
3216     }
3218     /**
3219      * Deletes a conversation.
3220      *
3221      * @deprecated since 3.6
3222      * @param int $userid The user id of who we want to delete the conversation for
3223      * @param int $otheruserid The user id of the other user in the conversation
3224      * @return array
3225      * @throws moodle_exception
3226      * @since 3.2
3227      */
3228     public static function delete_conversation($userid, $otheruserid) {
3229         global $CFG;
3231         // Check if private messaging between users is allowed.
3232         if (empty($CFG->messaging)) {
3233             throw new moodle_exception('disabled', 'message');
3234         }
3236         // Warnings array, it can be empty at the end but is mandatory.
3237         $warnings = array();
3239         // Validate params.
3240         $params = array(
3241             'userid' => $userid,
3242             'otheruserid' => $otheruserid,
3243         );
3244         $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
3246         // Validate context.
3247         $context = context_system::instance();
3248         self::validate_context($context);
3250         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3251         core_user::require_active_user($user);
3253         if (!$conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']])) {
3254             return [];
3255         }
3257         if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3258             \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3259             $status = true;
3260         } else {
3261             throw new moodle_exception('You do not have permission to delete messages');
3262         }
3264         $results = array(
3265             'status' => $status,
3266             'warnings' => $warnings
3267         );
3269         return $results;
3270     }
3272     /**
3273      * Returns description of method result value.
3274      *
3275      * @deprecated since 3.6
3276      * @return external_description
3277      * @since 3.2
3278      */
3279     public static function delete_conversation_returns() {
3280         return new external_single_structure(
3281             array(
3282                 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
3283                 'warnings' => new external_warnings()
3284             )
3285         );
3286     }
3288     /**
3289      * Marking the method as deprecated.
3290      *
3291      * @return bool
3292      */
3293     public static function delete_conversation_is_deprecated() {
3294         return true;
3295     }
3297     /**
3298      * Returns description of method parameters.
3299      *
3300      * @return external_function_parameters
3301      * @since 3.6
3302      */
3303     public static function delete_conversations_by_id_parameters() {
3304         return new external_function_parameters(
3305             array(
3306                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3307                 'conversationids' => new external_multiple_structure(
3308                     new external_value(PARAM_INT, 'The id of the conversation'),
3309                     'List of conversation IDs'
3310                 ),
3311             )
3312         );
3313     }
3315     /**
3316      * Deletes a conversation.
3317      *
3318      * @param int $userid The user id of who we want to delete the conversation for
3319      * @param int[] $conversationids The ids of the conversations
3320      * @return array
3321      * @throws moodle_exception
3322      * @since 3.6
3323      */
3324     public static function delete_conversations_by_id($userid, array $conversationids) {
3325         global $CFG;
3327         // Check if private messaging between users is allowed.
3328         if (empty($CFG->messaging)) {
3329             throw new moodle_exception('disabled', 'message');
3330         }
3332         // Validate params.
3333         $params = [
3334             'userid' => $userid,
3335             'conversationids' => $conversationids,
3336         ];
3337         $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
3339         // Validate context.
3340         $context = context_system::instance();
3341         self::validate_context($context);
3343         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3344         core_user::require_active_user($user);
3346         foreach ($params['conversationids'] as $conversationid) {
3347             if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3348                 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3349             } else {
3350                 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
3351             }
3352         }
3354         return [];
3355     }
3357     /**
3358      * Returns description of method result value.
3359      *
3360      * @return external_description
3361      * @since 3.6
3362      */
3363     public static function delete_conversations_by_id_returns() {
3364         return new external_warnings();
3365     }
3367     /**
3368      * Returns description of method parameters
3369      *
3370      * @return external_function_parameters
3371      * @since 3.1
3372      */
3373     public static function delete_message_parameters() {
3374         return new external_function_parameters(
3375             array(
3376                 'messageid' => new external_value(PARAM_INT, 'The message id'),
3377                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
3378                 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
3379             )
3380         );
3381     }
3383     /**
3384      * Deletes a message
3385      *
3386      * @param  int $messageid the message id
3387      * @param  int $userid the user id of who we want to delete the message for
3388      * @param  bool $read if is a message read (default to true)
3389      * @return external_description
3390      * @throws moodle_exception
3391      * @since 3.1
3392      */
3393     public static function delete_message($messageid, $userid, $read = true) {
3394         global $CFG;
3396         // Check if private messaging between users is allowed.
3397         if (empty($CFG->messaging)) {
3398             throw new moodle_exception('disabled', 'message');
3399         }
3401         // Warnings array, it can be empty at the end but is mandatory.
3402         $warnings = array();
3404         // Validate params.
3405         $params = array(
3406             'messageid' => $messageid,
3407             'userid' => $userid,
3408             'read' => $read
3409         );
3410         $params = self::validate_parameters(self::delete_message_parameters(), $params);
3412         // Validate context.
3413         $context = context_system::instance();
3414         self::validate_context($context);
3416         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3417         core_user::require_active_user($user);
3419         if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
3420             $status = \core_message\api::delete_message($user->id, $params['messageid']);
3421         } else {
3422             throw new moodle_exception('You do not have permission to delete this message');
3423         }
3425         $results = array(
3426             'status' => $status,
3427             'warnings' => $warnings
3428         );
3429         return $results;
3430     }
3432     /**
3433      * Returns description of method result value
3434      *