MDL-64140 core_message: add get_unread_conversation_counts() web service
[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             $createdmessage = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
94                 $message['textformat']);
95             $createdmessage->text = message_format_message_text((object) [
96                 'smallmessage' => $createdmessage->text,
97                 'fullmessageformat' => external_validate_format($message['textformat'])
98             ]);
99             $messages[] = $createdmessage;
100         }
102         return $messages;
103     }
105     /**
106      * Returns description of method result value.
107      *
108      * @return external_description
109      * @since Moodle 3.6
110      */
111     public static function send_messages_to_conversation_returns() {
112         return new external_multiple_structure(
113             self::get_conversation_message_structure()
114         );
115     }
118     /**
119      * Returns description of method parameters
120      *
121      * @return external_function_parameters
122      * @since Moodle 2.2
123      */
124     public static function send_instant_messages_parameters() {
125         return new external_function_parameters(
126             array(
127                 'messages' => new external_multiple_structure(
128                     new external_single_structure(
129                         array(
130                             'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
131                             'text' => new external_value(PARAM_RAW, 'the text of the message'),
132                             'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
133                             '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),
134                         )
135                     )
136                 )
137             )
138         );
139     }
141     /**
142      * Send private messages from the current USER to other users
143      *
144      * @param array $messages An array of message to send.
145      * @return array
146      * @since Moodle 2.2
147      */
148     public static function send_instant_messages($messages = array()) {
149         global $CFG, $USER, $DB;
151         // Check if messaging is enabled.
152         if (empty($CFG->messaging)) {
153             throw new moodle_exception('disabled', 'message');
154         }
156         // Ensure the current user is allowed to run this function
157         $context = context_system::instance();
158         self::validate_context($context);
159         require_capability('moodle/site:sendmessage', $context);
161         $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
163         //retrieve all tousers of the messages
164         $receivers = array();
165         foreach($params['messages'] as $message) {
166             $receivers[] = $message['touserid'];
167         }
168         list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
169         $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
171         $resultmessages = array();
172         $messageids = array();
173         foreach ($params['messages'] as $message) {
174             $resultmsg = array(); //the infos about the success of the operation
176             // We are going to do some checking.
177             // Code should match /messages/index.php checks.
178             $success = true;
180             // Check the user exists.
181             if (empty($tousers[$message['touserid']])) {
182                 $success = false;
183                 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
184             }
186             // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
187             // Check if the recipient can be messaged by the sender.
188             if ($success && !\core_message\api::can_post_message($tousers[$message['touserid']], $USER)) {
189                 $success = false;
190                 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
191             }
193             // Now we can send the message (at least try).
194             if ($success) {
195                 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
196                 $success = message_post_message($USER, $tousers[$message['touserid']],
197                         $message['text'], external_validate_format($message['textformat']));
198             }
200             // Build the resultmsg.
201             if (isset($message['clientmsgid'])) {
202                 $resultmsg['clientmsgid'] = $message['clientmsgid'];
203             }
204             if ($success) {
205                 $resultmsg['msgid'] = $success;
206                 $resultmsg['text'] = message_format_message_text((object) [
207                     'smallmessage' => $message['text'],
208                     'fullmessageformat' => external_validate_format($message['textformat'])
209                 ]);
210                 $resultmsg['timecreated'] = time();
211                 $messageids[] = $success;
212             } else {
213                 // WARNINGS: for backward compatibility we return this errormessage.
214                 //          We should have thrown exceptions as these errors prevent results to be returned.
215                 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
216                 $resultmsg['msgid'] = -1;
217                 $resultmsg['errormessage'] = $errormessage;
218             }
220             $resultmessages[] = $resultmsg;
221         }
223         if (!empty($messageids)) {
224             $messagerecords = $DB->get_records_list('messages', 'id', $messageids, '', 'id, conversationid');
225             $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) {
226                 $id = $resultmessage['msgid'];
227                 $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null;
228                 $resultmessage['useridfrom'] = $USER->id;
229                 return $resultmessage;
230             }, $resultmessages);
231         }
233         return $resultmessages;
234     }
236     /**
237      * Returns description of method result value
238      *
239      * @return external_description
240      * @since Moodle 2.2
241      */
242     public static function send_instant_messages_returns() {
243         return new external_multiple_structure(
244             new external_single_structure(
245                 array(
246                     'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
247                     'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
248                     'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL),
249                     'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL),
250                     'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
251                     'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
252                     'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
253                 )
254             )
255         );
256     }
258     /**
259      * Create contacts parameters description.
260      *
261      * @deprecated since Moodle 3.6
262      * @return external_function_parameters
263      * @since Moodle 2.5
264      */
265     public static function create_contacts_parameters() {
266         return new external_function_parameters(
267             array(
268                 'userids' => new external_multiple_structure(
269                     new external_value(PARAM_INT, 'User ID'),
270                     'List of user IDs'
271                 ),
272                 'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
273                     current user', VALUE_DEFAULT, 0)
274             )
275         );
276     }
278     /**
279      * Create contacts.
280      *
281      * @deprecated since Moodle 3.6
282      * @param array $userids array of user IDs.
283      * @param int $userid The id of the user we are creating the contacts for
284      * @return external_description
285      * @since Moodle 2.5
286      */
287     public static function create_contacts($userids, $userid = 0) {
288         global $CFG, $USER;
290         // Check if messaging is enabled.
291         if (empty($CFG->messaging)) {
292             throw new moodle_exception('disabled', 'message');
293         }
295         if (empty($userid)) {
296             $userid = $USER->id;
297         }
299         // Validate context.
300         $context = context_system::instance();
301         self::validate_context($context);
303         $params = array('userids' => $userids, 'userid' => $userid);
304         $params = self::validate_parameters(self::create_contacts_parameters(), $params);
306         $capability = 'moodle/site:manageallmessaging';
307         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
308             throw new required_capability_exception($context, $capability, 'nopermissions', '');
309         }
311         $warnings = array();
312         foreach ($params['userids'] as $id) {
313             if (!message_add_contact($id, 0, $params['userid'])) {
314                 $warnings[] = array(
315                     'item' => 'user',
316                     'itemid' => $id,
317                     'warningcode' => 'contactnotcreated',
318                     'message' => 'The contact could not be created'
319                 );
320             }
321         }
322         return $warnings;
323     }
325     /**
326      * Create contacts return description.
327      *
328      * @deprecated since Moodle 3.6
329      * @return external_description
330      * @since Moodle 2.5
331      */
332     public static function create_contacts_returns() {
333         return new external_warnings();
334     }
336     /**
337      * Marking the method as deprecated.
338      *
339      * @return bool
340      */
341     public static function create_contacts_is_deprecated() {
342         return true;
343     }
345     /**
346      * Delete contacts parameters description.
347      *
348      * @return external_function_parameters
349      * @since Moodle 2.5
350      */
351     public static function delete_contacts_parameters() {
352         return new external_function_parameters(
353             array(
354                 'userids' => new external_multiple_structure(
355                     new external_value(PARAM_INT, 'User ID'),
356                     'List of user IDs'
357                 ),
358                 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
359                     current user', VALUE_DEFAULT, 0)
360             )
361         );
362     }
364     /**
365      * Delete contacts.
366      *
367      * @param array $userids array of user IDs.
368      * @param int $userid The id of the user we are deleting the contacts for
369      * @return null
370      * @since Moodle 2.5
371      */
372     public static function delete_contacts($userids, $userid = 0) {
373         global $CFG, $USER;
375         // Check if messaging is enabled.
376         if (empty($CFG->messaging)) {
377             throw new moodle_exception('disabled', 'message');
378         }
380         if (empty($userid)) {
381             $userid = $USER->id;
382         }
384         // Validate context.
385         $context = context_system::instance();
386         self::validate_context($context);
388         $params = array('userids' => $userids, 'userid' => $userid);
389         $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
391         $capability = 'moodle/site:manageallmessaging';
392         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
393             throw new required_capability_exception($context, $capability, 'nopermissions', '');
394         }
396         foreach ($params['userids'] as $id) {
397             \core_message\api::remove_contact($params['userid'], $id);
398         }
400         return null;
401     }
403     /**
404      * Delete contacts return description.
405      *
406      * @return external_description
407      * @since Moodle 2.5
408      */
409     public static function delete_contacts_returns() {
410         return null;
411     }
413     /**
414      * Block user parameters description.
415      *
416      * @return external_function_parameters
417      */
418     public static function block_user_parameters() {
419         return new external_function_parameters(
420             [
421                 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
422                 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
423             ]
424         );
425     }
427     /**
428      * Blocks a user.
429      *
430      * @param int $userid The id of the user who is blocking
431      * @param int $blockeduserid The id of the user being blocked
432      * @return external_description
433      */
434     public static function block_user(int $userid, int $blockeduserid) {
435         global $CFG, $USER;
437         // Check if messaging is enabled.
438         if (empty($CFG->messaging)) {
439             throw new moodle_exception('disabled', 'message');
440         }
442         // Validate context.
443         $context = context_system::instance();
444         self::validate_context($context);
446         $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
447         $params = self::validate_parameters(self::block_user_parameters(), $params);
449         $capability = 'moodle/site:manageallmessaging';
450         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
451             throw new required_capability_exception($context, $capability, 'nopermissions', '');
452         }
454         if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
455             \core_message\api::block_user($params['userid'], $params['blockeduserid']);
456         }
458         return [];
459     }
461     /**
462      * Block user return description.
463      *
464      * @return external_description
465      */
466     public static function block_user_returns() {
467         return new external_warnings();
468     }
470     /**
471      * Unblock user parameters description.
472      *
473      * @return external_function_parameters
474      */
475     public static function unblock_user_parameters() {
476         return new external_function_parameters(
477             [
478                 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
479                 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
480             ]
481         );
482     }
484     /**
485      * Unblock user.
486      *
487      * @param int $userid The id of the user who is unblocking
488      * @param int $unblockeduserid The id of the user being unblocked
489      */
490     public static function unblock_user(int $userid, int $unblockeduserid) {
491         global $CFG, $USER;
493         // Check if messaging is enabled.
494         if (empty($CFG->messaging)) {
495             throw new moodle_exception('disabled', 'message');
496         }
498         // Validate context.
499         $context = context_system::instance();
500         self::validate_context($context);
502         $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
503         $params = self::validate_parameters(self::unblock_user_parameters(), $params);
505         $capability = 'moodle/site:manageallmessaging';
506         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
507             throw new required_capability_exception($context, $capability, 'nopermissions', '');
508         }
510         \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
512         return [];
513     }
515     /**
516      * Unblock user return description.
517      *
518      * @return external_description
519      */
520     public static function unblock_user_returns() {
521         return new external_warnings();
522     }
524     /**
525      * Block contacts parameters description.
526      *
527      * @deprecated since Moodle 3.6
528      * @return external_function_parameters
529      * @since Moodle 2.5
530      */
531     public static function block_contacts_parameters() {
532         return new external_function_parameters(
533             array(
534                 'userids' => new external_multiple_structure(
535                     new external_value(PARAM_INT, 'User ID'),
536                     'List of user IDs'
537                 ),
538                 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
539                     current user', VALUE_DEFAULT, 0)
540             )
541         );
542     }
544     /**
545      * Block contacts.
546      *
547      * @deprecated since Moodle 3.6
548      * @param array $userids array of user IDs.
549      * @param int $userid The id of the user we are blocking the contacts for
550      * @return external_description
551      * @since Moodle 2.5
552      */
553     public static function block_contacts($userids, $userid = 0) {
554         global $CFG, $USER;
556         // Check if messaging is enabled.
557         if (empty($CFG->messaging)) {
558             throw new moodle_exception('disabled', 'message');
559         }
561         if (empty($userid)) {
562             $userid = $USER->id;
563         }
565         // Validate context.
566         $context = context_system::instance();
567         self::validate_context($context);
569         $params = array('userids' => $userids, 'userid' => $userid);
570         $params = self::validate_parameters(self::block_contacts_parameters(), $params);
572         $capability = 'moodle/site:manageallmessaging';
573         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
574             throw new required_capability_exception($context, $capability, 'nopermissions', '');
575         }
577         $warnings = array();
578         foreach ($params['userids'] as $id) {
579             if (!message_block_contact($id, $params['userid'])) {
580                 $warnings[] = array(
581                     'item' => 'user',
582                     'itemid' => $id,
583                     'warningcode' => 'contactnotblocked',
584                     'message' => 'The contact could not be blocked'
585                 );
586             }
587         }
588         return $warnings;
589     }
591     /**
592      * Block contacts return description.
593      *
594      * @deprecated since Moodle 3.6
595      * @return external_description
596      * @since Moodle 2.5
597      */
598     public static function block_contacts_returns() {
599         return new external_warnings();
600     }
602     /**
603      * Marking the method as deprecated.
604      *
605      * @return bool
606      */
607     public static function block_contacts_is_deprecated() {
608         return true;
609     }
611     /**
612      * Unblock contacts parameters description.
613      *
614      * @deprecated since Moodle 3.6
615      * @return external_function_parameters
616      * @since Moodle 2.5
617      */
618     public static function unblock_contacts_parameters() {
619         return new external_function_parameters(
620             array(
621                 'userids' => new external_multiple_structure(
622                     new external_value(PARAM_INT, 'User ID'),
623                     'List of user IDs'
624                 ),
625                 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
626                     current user', VALUE_DEFAULT, 0)
627             )
628         );
629     }
631     /**
632      * Unblock contacts.
633      *
634      * @param array $userids array of user IDs.
635      * @param int $userid The id of the user we are unblocking the contacts for
636      * @return null
637      * @since Moodle 2.5
638      */
639     public static function unblock_contacts($userids, $userid = 0) {
640         global $CFG, $USER;
642         // Check if messaging is enabled.
643         if (empty($CFG->messaging)) {
644             throw new moodle_exception('disabled', 'message');
645         }
647         if (empty($userid)) {
648             $userid = $USER->id;
649         }
651         // Validate context.
652         $context = context_system::instance();
653         self::validate_context($context);
655         $params = array('userids' => $userids, 'userid' => $userid);
656         $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
658         $capability = 'moodle/site:manageallmessaging';
659         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
660             throw new required_capability_exception($context, $capability, 'nopermissions', '');
661         }
663         foreach ($params['userids'] as $id) {
664             message_unblock_contact($id, $params['userid']);
665         }
667         return null;
668     }
670     /**
671      * Unblock contacts return description.
672      *
673      * @deprecated since Moodle 3.6
674      * @return external_description
675      * @since Moodle 2.5
676      */
677     public static function unblock_contacts_returns() {
678         return null;
679     }
681     /**
682      * Marking the method as deprecated.
683      *
684      * @return bool
685      */
686     public static function unblock_contacts_is_deprecated() {
687         return true;
688     }
690     /**
691      * Returns contact requests parameters description.
692      *
693      * @return external_function_parameters
694      */
695     public static function get_contact_requests_parameters() {
696         return new external_function_parameters(
697             [
698                 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
699                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
700                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
701             ]
702         );
703     }
705     /**
706      * Handles returning the contact requests for a user.
707      *
708      * This also includes the user data necessary to display information
709      * about the user.
710      *
711      * It will not include blocked users.
712      *
713      * @param int $userid The id of the user we want to get the contact requests for
714      * @param int $limitfrom
715      * @param int $limitnum
716      */
717     public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
718         global $CFG, $USER;
720         // Check if messaging is enabled.
721         if (empty($CFG->messaging)) {
722             throw new moodle_exception('disabled', 'message');
723         }
725         // Validate context.
726         $context = context_system::instance();
727         self::validate_context($context);
729         $params = [
730             'userid' => $userid,
731             'limitfrom' => $limitfrom,
732             'limitnum' => $limitnum
733         ];
734         $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
736         $capability = 'moodle/site:manageallmessaging';
737         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
738             throw new required_capability_exception($context, $capability, 'nopermissions', '');
739         }
741         return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
742     }
744     /**
745      * Returns the contact requests return description.
746      *
747      * @return external_description
748      */
749     public static function get_contact_requests_returns() {
750         return new external_multiple_structure(
751             self::get_conversation_member_structure()
752         );
753     }
755     /**
756      * Returns the number of contact requests the user has received parameters description.
757      *
758      * @return external_function_parameters
759      */
760     public static function get_received_contact_requests_count_parameters() {
761         return new external_function_parameters(
762             array(
763                 'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' .
764                     'received contact requests for', VALUE_REQUIRED),
765             )
766         );
767     }
769     /**
770      * Returns the number of contact requests the user has received.
771      *
772      * @param int $userid The ID of the user we want to return the number of received contact requests for
773      * @return external_value
774      */
775     public static function get_received_contact_requests_count(int $userid) {
776         global $CFG, $USER;
778         // Check if messaging is enabled.
779         if (empty($CFG->messaging)) {
780             throw new moodle_exception('disabled', 'message');
781         }
783         // Validate context.
784         $context = context_system::instance();
785         self::validate_context($context);
787         $params = [
788             'userid' => $userid,
789         ];
790         $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params);
792         $capability = 'moodle/site:manageallmessaging';
793         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
794             throw new required_capability_exception($context, $capability, 'nopermissions', '');
795         }
797         return \core_message\api::get_received_contact_requests_count($params['userid']);
798     }
800     /**
801      * Returns the number of contact requests the user has received return description.
802      *
803      * @return external_value
804      */
805     public static function get_received_contact_requests_count_returns() {
806         return new external_value(PARAM_INT, 'The number of received contact requests');
807     }
809     /**
810      * Returns get conversation members parameters description.
811      *
812      * @return external_function_parameters
813      */
814     public static function get_conversation_members_parameters() {
815         return new external_function_parameters(
816             [
817                 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
818                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
819                 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
820                     VALUE_DEFAULT, false),
821                 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?',
822                     VALUE_DEFAULT, false),
823                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
824                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
825             ]
826         );
827     }
829     /**
830      * Returns a list of conversation members.
831      *
832      * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
833      * @param int $conversationid The id of the conversation
834      * @param bool $includecontactrequests Do we want to include contact requests with this data?
835      * @param bool $includeprivacyinfo Do we want to include privacy info?
836      * @param int $limitfrom
837      * @param int $limitnum
838      * @return array
839      */
840     public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
841                                                     bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) {
842         global $CFG, $USER;
844         // Check if messaging is enabled.
845         if (empty($CFG->messaging)) {
846             throw new moodle_exception('disabled', 'message');
847         }
849         // Validate context.
850         $context = context_system::instance();
851         self::validate_context($context);
853         $params = [
854             'userid' => $userid,
855             'conversationid' => $conversationid,
856             'includecontactrequests' => $includecontactrequests,
857             'includeprivacyinfo' => $includeprivacyinfo,
858             'limitfrom' => $limitfrom,
859             'limitnum' => $limitnum
860         ];
861         $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
863         $capability = 'moodle/site:manageallmessaging';
864         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
865             throw new required_capability_exception($context, $capability, 'nopermissions', '');
866         }
868         // The user needs to be a part of the conversation before querying who the members are.
869         if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
870             throw new moodle_exception('You are not a member of this conversation.');
871         }
873         return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
874             $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']);
875     }
877     /**
878      * Returns the get conversation members return description.
879      *
880      * @return external_description
881      */
882     public static function get_conversation_members_returns() {
883         return new external_multiple_structure(
884             self::get_conversation_member_structure()
885         );
886     }
888     /**
889      * Creates a contact request parameters description.
890      *
891      * @return external_function_parameters
892      */
893     public static function create_contact_request_parameters() {
894         return new external_function_parameters(
895             [
896                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
897                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
898             ]
899         );
900     }
902     /**
903      * Creates a contact request.
904      *
905      * @param int $userid The id of the user who is creating the contact request
906      * @param int $requesteduserid The id of the user being requested
907      */
908     public static function create_contact_request(int $userid, int $requesteduserid) {
909         global $CFG, $USER;
911         // Check if messaging is enabled.
912         if (empty($CFG->messaging)) {
913             throw new moodle_exception('disabled', 'message');
914         }
916         // Validate context.
917         $context = context_system::instance();
918         self::validate_context($context);
920         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
921         $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
923         $capability = 'moodle/site:manageallmessaging';
924         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
925             throw new required_capability_exception($context, $capability, 'nopermissions', '');
926         }
928         $result = [
929             'warnings' => []
930         ];
932         if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
933             $result['warnings'][] = [
934                 'item' => 'user',
935                 'itemid' => $params['requesteduserid'],
936                 'warningcode' => 'cannotcreatecontactrequest',
937                 'message' => 'You are unable to create a contact request for this user'
938             ];
939         } else {
940             if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
941                 // There should only ever be one but just in case there are multiple then we can return the first.
942                 $result['request'] = array_shift($requests);
943             } else {
944                 $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
945             }
946         }
948         return $result;
949     }
951     /**
952      * Creates a contact request return description.
953      *
954      * @return external_description
955      */
956     public static function create_contact_request_returns() {
957         return new external_single_structure(
958             array(
959                 'request' => new external_single_structure(
960                     array(
961                         'id' => new external_value(PARAM_INT, 'Message id'),
962                         'userid' => new external_value(PARAM_INT, 'User from id'),
963                         'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
964                         'timecreated' => new external_value(PARAM_INT, 'Time created'),
965                     ),
966                     'request record',
967                     VALUE_OPTIONAL
968                 ),
969                 'warnings' => new external_warnings()
970             )
971         );
972     }
974     /**
975      * Confirm a contact request parameters description.
976      *
977      * @return external_function_parameters
978      */
979     public static function confirm_contact_request_parameters() {
980         return new external_function_parameters(
981             [
982                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
983                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
984             ]
985         );
986     }
988     /**
989      * Confirm a contact request.
990      *
991      * @param int $userid The id of the user who is creating the contact request
992      * @param int $requesteduserid The id of the user being requested
993      */
994     public static function confirm_contact_request(int $userid, int $requesteduserid) {
995         global $CFG, $USER;
997         // Check if messaging is enabled.
998         if (empty($CFG->messaging)) {
999             throw new moodle_exception('disabled', 'message');
1000         }
1002         // Validate context.
1003         $context = context_system::instance();
1004         self::validate_context($context);
1006         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
1007         $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
1009         $capability = 'moodle/site:manageallmessaging';
1010         if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
1011             throw new required_capability_exception($context, $capability, 'nopermissions', '');
1012         }
1014         \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
1016         return [];
1017     }
1019     /**
1020      * Confirm a contact request return description.
1021      *
1022      * @return external_description
1023      */
1024     public static function confirm_contact_request_returns() {
1025         return new external_warnings();
1026     }
1028     /**
1029      * Declines a contact request parameters description.
1030      *
1031      * @return external_function_parameters
1032      */
1033     public static function decline_contact_request_parameters() {
1034         return new external_function_parameters(
1035             [
1036                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
1037                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
1038             ]
1039         );
1040     }
1042     /**
1043      * Declines a contact request.
1044      *
1045      * @param int $userid The id of the user who is creating the contact request
1046      * @param int $requesteduserid The id of the user being requested
1047      */
1048     public static function decline_contact_request(int $userid, int $requesteduserid) {
1049         global $CFG, $USER;
1051         // Check if messaging is enabled.
1052         if (empty($CFG->messaging)) {
1053             throw new moodle_exception('disabled', 'message');
1054         }
1056         // Validate context.
1057         $context = context_system::instance();
1058         self::validate_context($context);
1060         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
1061         $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
1063         $capability = 'moodle/site:manageallmessaging';
1064         if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
1065             throw new required_capability_exception($context, $capability, 'nopermissions', '');
1066         }
1068         \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
1070         return [];
1071     }
1073     /**
1074      * Declines a contact request return description.
1075      *
1076      * @return external_description
1077      */
1078     public static function decline_contact_request_returns() {
1079         return new external_warnings();
1080     }
1082     /**
1083      * Return the structure of a message area contact.
1084      *
1085      * @return external_single_structure
1086      * @since Moodle 3.2
1087      */
1088     private static function get_messagearea_contact_structure() {
1089         return new external_single_structure(
1090             array(
1091                 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
1092                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1093                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1094                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1095                 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
1096                 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
1097                 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
1098                 'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null),
1099                 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
1100                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1101                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1102                 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
1103                 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1104                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1105                     VALUE_DEFAULT, null),
1106                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null),
1107             )
1108         );
1109     }
1111     /**
1112      * Return the structure of a conversation.
1113      *
1114      * @return external_single_structure
1115      * @since Moodle 3.6
1116      */
1117     private static function get_conversation_structure() {
1118         return new external_single_structure(
1119             array(
1120                 'id' => new external_value(PARAM_INT, 'The conversation id'),
1121                 'name' => new external_value(PARAM_NOTAGS, 'The conversation name, if set', VALUE_DEFAULT, null),
1122                 'subname' => new external_value(PARAM_NOTAGS, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1123                 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1124                 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group)'),
1125                 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1126                 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked conversation this conversation as a favourite'),
1127                 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1128                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1129                     VALUE_DEFAULT, null),
1130                 'members' => new external_multiple_structure(
1131                     self::get_conversation_member_structure()
1132                 ),
1133                 'messages' => new external_multiple_structure(
1134                     self::get_conversation_message_structure()
1135                 ),
1136             )
1137         );
1138     }
1140     /**
1141      * Return the structure of a conversation member.
1142      *
1143      * @return external_single_structure
1144      * @since Moodle 3.6
1145      */
1146     private static function get_conversation_member_structure() {
1147         $result = [
1148             'id' => new external_value(PARAM_INT, 'The user id'),
1149             'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1150             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1151             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1152             'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1153             'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1154             'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1155             'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1156             'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1157             'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1158             'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1159         ];
1161         $result['contactrequests'] = new external_multiple_structure(
1162             new external_single_structure(
1163                 [
1164                     'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1165                     'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1166                     'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1167                     'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1168                 ]
1169             ), 'The contact requests', VALUE_OPTIONAL
1170         );
1172         $result['conversations'] = new external_multiple_structure(new external_single_structure(
1173             array(
1174                 'id' => new external_value(PARAM_INT, 'Conversations id'),
1175                 'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1176                 'name' => new external_value(PARAM_TEXT, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1177                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1178             ), 'information about conversation', VALUE_OPTIONAL),
1179             'Conversations between users', VALUE_OPTIONAL
1180         );
1182         return new external_single_structure(
1183             $result
1184         );
1185     }
1187     /**
1188      * Return the structure of a message area message.
1189      *
1190      * @return external_single_structure
1191      * @since Moodle 3.6
1192      */
1193     private static function get_conversation_message_structure() {
1194         return new external_single_structure(
1195             array(
1196                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1197                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1198                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1199                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1200             )
1201         );
1202     }
1204     /**
1205      * Return the structure of a message area message.
1206      *
1207      * @return external_single_structure
1208      * @since Moodle 3.2
1209      */
1210     private static function get_messagearea_message_structure() {
1211         return new external_single_structure(
1212             array(
1213                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1214                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1215                 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1216                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1217                 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1218                 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1219                 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1220                 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1221                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1222                 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1223             )
1224         );
1225     }
1227     /**
1228      * Get messagearea search users in course parameters.
1229      *
1230      * @deprecated since 3.6
1231      *
1232      * @return external_function_parameters
1233      * @since 3.2
1234      */
1235     public static function data_for_messagearea_search_users_in_course_parameters() {
1236         return new external_function_parameters(
1237             array(
1238                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1239                 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1240                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1241                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1242                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1243             )
1244         );
1245     }
1247     /**
1248      * Get messagearea search users in course results.
1249      *
1250      * @deprecated since 3.6
1251      *
1252      * NOTE: We are deprecating this function but not search_users_in_course API function for backwards compatibility
1253      * with messaging UI. But should be removed once new group messaging UI is in place and old messaging UI is removed.
1254      * Followup: MDL-63915
1255      *
1256      * @param int $userid The id of the user who is performing the search
1257      * @param int $courseid The id of the course
1258      * @param string $search The string being searched
1259      * @param int $limitfrom
1260      * @param int $limitnum
1261      * @return stdClass
1262      * @throws moodle_exception
1263      * @since 3.2
1264      */
1265     public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1266                                                                        $limitnum = 0) {
1267         global $CFG, $PAGE, $USER;
1269         // Check if messaging is enabled.
1270         if (empty($CFG->messaging)) {
1271             throw new moodle_exception('disabled', 'message');
1272         }
1274         $systemcontext = context_system::instance();
1276         $params = array(
1277             'userid' => $userid,
1278             'courseid' => $courseid,
1279             'search' => $search,
1280             'limitfrom' => $limitfrom,
1281             'limitnum' => $limitnum
1282         );
1283         $params = self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1284         self::validate_context($systemcontext);
1286         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1287             throw new moodle_exception('You do not have permission to perform this action.');
1288         }
1290         $users = \core_message\api::search_users_in_course(
1291             $params['userid'],
1292             $params['courseid'],
1293             $params['search'],
1294             $params['limitfrom'],
1295             $params['limitnum']
1296         );
1297         $results = new \core_message\output\messagearea\user_search_results($users);
1299         $renderer = $PAGE->get_renderer('core_message');
1300         return $results->export_for_template($renderer);
1301     }
1303     /**
1304      * Get messagearea search users in course returns.
1305      *
1306      * @deprecated since 3.6
1307      *
1308      * @return external_single_structure
1309      * @since 3.2
1310      */
1311     public static function data_for_messagearea_search_users_in_course_returns() {
1312         return new external_single_structure(
1313             array(
1314                 'contacts' => new external_multiple_structure(
1315                     self::get_messagearea_contact_structure()
1316                 ),
1317             )
1318         );
1319     }
1321     /**
1322      * Marking the method as deprecated.
1323      *
1324      * @return bool
1325      */
1326     public static function data_for_messagearea_search_users_in_course_is_deprecated() {
1327         return true;
1328     }
1330     /**
1331      * Get messagearea search users parameters.
1332      *
1333      * @deprecated since 3.6
1334      *
1335      * @return external_function_parameters
1336      * @since 3.2
1337      */
1338     public static function data_for_messagearea_search_users_parameters() {
1339         return new external_function_parameters(
1340             array(
1341                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1342                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1343                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1344             )
1345         );
1346     }
1348     /**
1349      * Get messagearea search users results.
1350      *
1351      * @deprecated since 3.6
1352      *
1353      * NOTE: We are deprecating this function but not search_users API function for backwards compatibility
1354      * with messaging UI. But should be removed once new group messaging UI is in place and old messaging UI is removed.
1355      * Followup: MDL-63915
1356      *
1357      * @param int $userid The id of the user who is performing the search
1358      * @param string $search The string being searched
1359      * @param int $limitnum
1360      * @return stdClass
1361      * @throws moodle_exception
1362      * @since 3.2
1363      */
1364     public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1365         global $CFG, $PAGE, $USER;
1367         // Check if messaging is enabled.
1368         if (empty($CFG->messaging)) {
1369             throw new moodle_exception('disabled', 'message');
1370         }
1372         $systemcontext = context_system::instance();
1374         $params = array(
1375             'userid' => $userid,
1376             'search' => $search,
1377             'limitnum' => $limitnum
1378         );
1379         $params = self::validate_parameters(self::data_for_messagearea_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, $courses, $noncontacts) = \core_message\api::search_users(
1387             $params['userid'],
1388             $params['search'],
1389             $params['limitnum']
1390         );
1392         $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1394         $renderer = $PAGE->get_renderer('core_message');
1395         return $search->export_for_template($renderer);
1396     }
1398     /**
1399      * Get messagearea search users returns.
1400      *
1401      * @deprecated since 3.6
1402      *
1403      * @return external_single_structure
1404      * @since 3.2
1405      */
1406     public static function data_for_messagearea_search_users_returns() {
1407         return new external_single_structure(
1408             array(
1409                 'contacts' => new external_multiple_structure(
1410                     self::get_messagearea_contact_structure()
1411                 ),
1412                 'courses' => new external_multiple_structure(
1413                     new external_single_structure(
1414                         array(
1415                             'id' => new external_value(PARAM_INT, 'The course id'),
1416                             'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1417                             'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1418                         )
1419                     )
1420                 ),
1421                 'noncontacts' => new external_multiple_structure(
1422                     self::get_messagearea_contact_structure()
1423                 )
1424             )
1425         );
1426     }
1428     /**
1429      * Marking the method as deprecated.
1430      *
1431      * @return bool
1432      */
1433     public static function data_for_messagearea_search_users_is_deprecated() {
1434         return true;
1435     }
1437     /**
1438      * Get messagearea message search users parameters.
1439      *
1440      * @return external_function_parameters
1441      * @since 3.6
1442      */
1443     public static function message_search_users_parameters() {
1444         return new external_function_parameters(
1445             array(
1446                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1447                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1448                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1449                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1450             )
1451         );
1452     }
1454     /**
1455      * Get search users results.
1456      *
1457      * @param int $userid The id of the user who is performing the search
1458      * @param string $search The string being searched
1459      * @param int $limitfrom
1460      * @param int $limitnum
1461      * @return array
1462      * @throws moodle_exception
1463      * @since 3.6
1464      */
1465     public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1466         global $USER;
1468         $systemcontext = context_system::instance();
1470         $params = array(
1471             'userid' => $userid,
1472             'search' => $search,
1473             'limitfrom' => $limitfrom,
1474             'limitnum' => $limitnum
1475         );
1476         $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1477         self::validate_context($systemcontext);
1479         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1480             throw new moodle_exception('You do not have permission to perform this action.');
1481         }
1483         list($contacts, $noncontacts) = \core_message\api::message_search_users(
1484             $params['userid'],
1485             $params['search'],
1486             $params['limitfrom'],
1487             $params['limitnum']);
1489         return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1490     }
1492     /**
1493      * Get messagearea message search users returns.
1494      *
1495      * @return external_single_structure
1496      * @since 3.2
1497      */
1498     public static function message_search_users_returns() {
1499         return new external_single_structure(
1500             array(
1501                 'contacts' => new external_multiple_structure(
1502                     self::get_conversation_member_structure()
1503                 ),
1504                 'noncontacts' => new external_multiple_structure(
1505                     self::get_conversation_member_structure()
1506                 )
1507             )
1508         );
1509     }
1511     /**
1512      * Get messagearea search messages parameters.
1513      *
1514      * @return external_function_parameters
1515      * @since 3.2
1516      */
1517     public static function data_for_messagearea_search_messages_parameters() {
1518         return new external_function_parameters(
1519             array(
1520                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1521                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1522                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1523                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1524             )
1525         );
1526     }
1528     /**
1529      * Get messagearea search messages results.
1530      *
1531      * @param int $userid The id of the user who is performing the search
1532      * @param string $search The string being searched
1533      * @param int $limitfrom
1534      * @param int $limitnum
1535      * @return stdClass
1536      * @throws moodle_exception
1537      * @since 3.2
1538      */
1539     public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1540         global $CFG, $PAGE, $USER;
1542         // Check if messaging is enabled.
1543         if (empty($CFG->messaging)) {
1544             throw new moodle_exception('disabled', 'message');
1545         }
1547         $systemcontext = context_system::instance();
1549         $params = array(
1550             'userid' => $userid,
1551             'search' => $search,
1552             'limitfrom' => $limitfrom,
1553             'limitnum' => $limitnum
1555         );
1556         $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1557         self::validate_context($systemcontext);
1559         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1560             throw new moodle_exception('You do not have permission to perform this action.');
1561         }
1563         $messages = \core_message\api::search_messages(
1564             $params['userid'],
1565             $params['search'],
1566             $params['limitfrom'],
1567             $params['limitnum']
1568         );
1569         $results = new \core_message\output\messagearea\message_search_results($messages);
1571         $renderer = $PAGE->get_renderer('core_message');
1572         return $results->export_for_template($renderer);
1573     }
1575     /**
1576      * Get messagearea search messages returns.
1577      *
1578      * @return external_single_structure
1579      * @since 3.2
1580      */
1581     public static function data_for_messagearea_search_messages_returns() {
1582         return new external_single_structure(
1583             array(
1584                 'contacts' => new external_multiple_structure(
1585                     self::get_messagearea_contact_structure()
1586                 )
1587             )
1588         );
1589     }
1591     /**
1592      * Get conversations parameters.
1593      *
1594      * @return external_function_parameters
1595      * @since 3.6
1596      */
1597     public static function get_conversations_parameters() {
1598         return new external_function_parameters(
1599             array(
1600                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1601                 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1602                 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1603                 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1604                 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1605                 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1606                     VALUE_DEFAULT, null),
1608             )
1609         );
1610     }
1612     /**
1613      * Get the list of conversations for the user.
1614      *
1615      * @param int $userid The id of the user who is performing the search
1616      * @param int $limitfrom
1617      * @param int $limitnum
1618      * @param int|null $type
1619      * @param bool|null $favourites
1620      * @return stdClass
1621      * @throws \moodle_exception if the messaging feature is disabled on the site.
1622      * @since 3.2
1623      */
1624     public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null) {
1625         global $CFG, $USER;
1627         // All the standard BL checks.
1628         if (empty($CFG->messaging)) {
1629             throw new moodle_exception('disabled', 'message');
1630         }
1632         $params = array(
1633             'userid' => $userid,
1634             'limitfrom' => $limitfrom,
1635             'limitnum' => $limitnum,
1636             'type' => $type,
1637             'favourites' => $favourites
1638         );
1639         $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1641         $systemcontext = context_system::instance();
1642         self::validate_context($systemcontext);
1644         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1645             throw new moodle_exception('You do not have permission to perform this action.');
1646         }
1648         $conversations = \core_message\api::get_conversations(
1649             $params['userid'],
1650             $params['limitfrom'],
1651             $params['limitnum'],
1652             $params['type'],
1653             $params['favourites']
1654         );
1656         return (object) ['conversations' => $conversations];
1657     }
1659     /**
1660      * Get conversations returns.
1661      *
1662      * @return external_single_structure
1663      * @since 3.6
1664      */
1665     public static function get_conversations_returns() {
1666         return new external_single_structure(
1667             [
1668                 'conversations' => new external_multiple_structure(
1669                     self::get_conversation_structure(true)
1670                 )
1671             ]
1672         );
1673     }
1675     /**
1676      * Get conversation parameters.
1677      *
1678      * @return external_function_parameters
1679      */
1680     public static function get_conversation_parameters() {
1681         return new external_function_parameters(
1682             array(
1683                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1684                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1685                 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1686                 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1687                 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1688                 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1689                 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1690                 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1691                 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1692             )
1693         );
1694     }
1696     /**
1697      * Get a single conversation.
1698      *
1699      * @param int $userid The user id to get the conversation for
1700      * @param int $conversationid The id of the conversation to fetch
1701      * @param bool $includecontactrequests Should contact requests be included between members
1702      * @param bool $includeprivacyinfo Should privacy info be included between members
1703      * @param int $memberlimit Limit number of members to load
1704      * @param int $memberoffset Offset members by this amount
1705      * @param int $messagelimit Limit number of messages to load
1706      * @param int $messageoffset Offset the messages
1707      * @param bool $newestmessagesfirst Order messages by newest first
1708      * @return stdClass
1709      * @throws \moodle_exception if the messaging feature is disabled on the site.
1710      */
1711     public static function get_conversation(
1712         int $userid,
1713         int $conversationid,
1714         bool $includecontactrequests = false,
1715         bool $includeprivacyinfo = false,
1716         int $memberlimit = 0,
1717         int $memberoffset = 0,
1718         int $messagelimit = 0,
1719         int $messageoffset = 0,
1720         bool $newestmessagesfirst = true
1721     ) {
1722         global $CFG, $DB, $USER;
1724         // All the standard BL checks.
1725         if (empty($CFG->messaging)) {
1726             throw new moodle_exception('disabled', 'message');
1727         }
1729         $params = [
1730             'userid' => $userid,
1731             'conversationid' => $conversationid,
1732             'includecontactrequests' => $includecontactrequests,
1733             'includeprivacyinfo' => $includeprivacyinfo,
1734             'memberlimit' => $memberlimit,
1735             'memberoffset' => $memberoffset,
1736             'messagelimit' => $messagelimit,
1737             'messageoffset' => $messageoffset,
1738             'newestmessagesfirst' => $newestmessagesfirst
1739         ];
1740         self::validate_parameters(self::get_conversation_parameters(), $params);
1742         $systemcontext = context_system::instance();
1743         self::validate_context($systemcontext);
1745         $conversation = \core_message\api::get_conversation(
1746             $params['userid'],
1747             $params['conversationid'],
1748             $params['includecontactrequests'],
1749             $params['includeprivacyinfo'],
1750             $params['memberlimit'],
1751             $params['memberoffset'],
1752             $params['messagelimit'],
1753             $params['messageoffset'],
1754             $params['newestmessagesfirst']
1755         );
1757         if ($conversation) {
1758             return $conversation;
1759         } else {
1760             // We have to throw an exception here because the external functions annoyingly
1761             // don't accept null to be returned for a single structure.
1762             throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1763         }
1764     }
1766     /**
1767      * Get conversation returns.
1768      *
1769      * @return external_single_structure
1770      */
1771     public static function get_conversation_returns() {
1772         return self::get_conversation_structure();
1773     }
1775     /**
1776      * Get conversation parameters.
1777      *
1778      * @return external_function_parameters
1779      */
1780     public static function get_conversation_between_users_parameters() {
1781         return new external_function_parameters(
1782             array(
1783                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1784                 'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1785                 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1786                 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1787                 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1788                 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1789                 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1790                 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1791                 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1792             )
1793         );
1794     }
1796     /**
1797      * Get a single conversation between users.
1798      *
1799      * @param int $userid The user id to get the conversation for
1800      * @param int $otheruserid The other user id
1801      * @param bool $includecontactrequests Should contact requests be included between members
1802      * @param bool $includeprivacyinfo Should privacy info be included between members
1803      * @param int $memberlimit Limit number of members to load
1804      * @param int $memberoffset Offset members by this amount
1805      * @param int $messagelimit Limit number of messages to load
1806      * @param int $messageoffset Offset the messages
1807      * @param bool $newestmessagesfirst Order messages by newest first
1808      * @return stdClass
1809      * @throws \moodle_exception if the messaging feature is disabled on the site.
1810      */
1811     public static function get_conversation_between_users(
1812         int $userid,
1813         int $otheruserid,
1814         bool $includecontactrequests = false,
1815         bool $includeprivacyinfo = false,
1816         int $memberlimit = 0,
1817         int $memberoffset = 0,
1818         int $messagelimit = 0,
1819         int $messageoffset = 0,
1820         bool $newestmessagesfirst = true
1821     ) {
1822         global $CFG, $DB, $USER;
1824         // All the standard BL checks.
1825         if (empty($CFG->messaging)) {
1826             throw new moodle_exception('disabled', 'message');
1827         }
1829         $params = [
1830             'userid' => $userid,
1831             'otheruserid' => $otheruserid,
1832             'includecontactrequests' => $includecontactrequests,
1833             'includeprivacyinfo' => $includeprivacyinfo,
1834             'memberlimit' => $memberlimit,
1835             'memberoffset' => $memberoffset,
1836             'messagelimit' => $messagelimit,
1837             'messageoffset' => $messageoffset,
1838             'newestmessagesfirst' => $newestmessagesfirst
1839         ];
1840         self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
1842         $systemcontext = context_system::instance();
1843         self::validate_context($systemcontext);
1845         $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
1846         $conversation = null;
1848         if ($conversationid) {
1849             $conversation = \core_message\api::get_conversation(
1850                 $params['userid'],
1851                 $conversationid,
1852                 $params['includecontactrequests'],
1853                 $params['includeprivacyinfo'],
1854                 $params['memberlimit'],
1855                 $params['memberoffset'],
1856                 $params['messagelimit'],
1857                 $params['messageoffset'],
1858                 $params['newestmessagesfirst']
1859             );
1860         }
1862         if ($conversation) {
1863             return $conversation;
1864         } else {
1865             // We have to throw an exception here because the external functions annoyingly
1866             // don't accept null to be returned for a single structure.
1867             throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1868         }
1869     }
1871     /**
1872      * Get conversation returns.
1873      *
1874      * @return external_single_structure
1875      */
1876     public static function get_conversation_between_users_returns() {
1877         return self::get_conversation_structure(true);
1878     }
1880     /**
1881      * The messagearea conversations parameters.
1882      *
1883      * @deprecated since 3.6
1884      * @return external_function_parameters
1885      * @since 3.2
1886      */
1887     public static function data_for_messagearea_conversations_parameters() {
1888         return new external_function_parameters(
1889             array(
1890                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1891                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1892                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1893             )
1894         );
1895     }
1897     /**
1898      * Get messagearea conversations.
1899      *
1900      * NOTE FOR FINAL DEPRECATION:
1901      * When removing this method, please also consider removal of get_conversations_legacy_formatter()
1902      * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
1903      * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
1904      * removed.
1905      *
1906      * @deprecated since 3.6
1907      * @param int $userid The id of the user who we are viewing conversations for
1908      * @param int $limitfrom
1909      * @param int $limitnum
1910      * @return stdClass
1911      * @throws moodle_exception
1912      * @since 3.2
1913      */
1914     public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1915         global $CFG, $PAGE, $USER;
1917         // Check if messaging is enabled.
1918         if (empty($CFG->messaging)) {
1919             throw new moodle_exception('disabled', 'message');
1920         }
1922         $systemcontext = context_system::instance();
1924         $params = array(
1925             'userid' => $userid,
1926             'limitfrom' => $limitfrom,
1927             'limitnum' => $limitnum
1928         );
1929         $params = self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1930         self::validate_context($systemcontext);
1932         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1933             throw new moodle_exception('You do not have permission to perform this action.');
1934         }
1936         $conversations = \core_message\api::get_conversations($params['userid'], $params['limitfrom'], $params['limitnum']);
1938         // Format the conversations in the legacy style, as the get_conversations method has since been changed.
1939         $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
1941         $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1943         $renderer = $PAGE->get_renderer('core_message');
1944         return $conversations->export_for_template($renderer);
1945     }
1947     /**
1948      * The messagearea conversations return structure.
1949      *
1950      * @deprecated since 3.6
1951      * @return external_single_structure
1952      * @since 3.2
1953      */
1954     public static function data_for_messagearea_conversations_returns() {
1955         return new external_single_structure(
1956             array(
1957                 'contacts' => new external_multiple_structure(
1958                     self::get_messagearea_contact_structure()
1959                 )
1960             )
1961         );
1962     }
1964     /**
1965      * Marking the method as deprecated.
1966      *
1967      * @return bool
1968      */
1969     public static function data_for_messagearea_conversations_is_deprecated() {
1970         return true;
1971     }
1973     /**
1974      * The messagearea contacts return parameters.
1975      *
1976      * @deprecated since 3.6
1977      * @return external_function_parameters
1978      * @since 3.2
1979      */
1980     public static function data_for_messagearea_contacts_parameters() {
1981         return self::data_for_messagearea_conversations_parameters();
1982     }
1984     /**
1985      * Get messagearea contacts parameters.
1986      *
1987      * @deprecated since 3.6
1988      * @param int $userid The id of the user who we are viewing conversations for
1989      * @param int $limitfrom
1990      * @param int $limitnum
1991      * @return stdClass
1992      * @throws moodle_exception
1993      * @since 3.2
1994      */
1995     public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1996         global $CFG, $PAGE, $USER;
1998         // Check if messaging is enabled.
1999         if (empty($CFG->messaging)) {
2000             throw new moodle_exception('disabled', 'message');
2001         }
2003         $systemcontext = context_system::instance();
2005         $params = array(
2006             'userid' => $userid,
2007             'limitfrom' => $limitfrom,
2008             'limitnum' => $limitnum
2009         );
2010         $params = self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
2011         self::validate_context($systemcontext);
2013         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2014             throw new moodle_exception('You do not have permission to perform this action.');
2015         }
2017         $contacts = \core_message\api::get_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
2018         $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
2020         $renderer = $PAGE->get_renderer('core_message');
2021         return $contacts->export_for_template($renderer);
2022     }
2024     /**
2025      * The messagearea contacts return structure.
2026      *
2027      * @deprecated since 3.6
2028      * @return external_single_structure
2029      * @since 3.2
2030      */
2031     public static function data_for_messagearea_contacts_returns() {
2032         return self::data_for_messagearea_conversations_returns();
2033     }
2035     /**
2036      * Marking the method as deprecated.
2037      *
2038      * @return bool
2039      */
2040     public static function data_for_messagearea_contacts_is_deprecated() {
2041         return true;
2042     }
2044     /**
2045      * The messagearea messages parameters.
2046      *
2047      * @deprecated since 3.6
2048      * @return external_function_parameters
2049      * @since 3.2
2050      */
2051     public static function data_for_messagearea_messages_parameters() {
2052         return new external_function_parameters(
2053             array(
2054                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2055                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2056                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2057                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
2058                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
2059                 'timefrom' => new external_value(PARAM_INT,
2060                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
2061             )
2062         );
2063     }
2065     /**
2066      * Get messagearea messages.
2067      *
2068      * @deprecated since 3.6
2069      * @param int $currentuserid The current user's id
2070      * @param int $otheruserid The other user's id
2071      * @param int $limitfrom
2072      * @param int $limitnum
2073      * @param boolean $newest
2074      * @return stdClass
2075      * @throws moodle_exception
2076      * @since 3.2
2077      */
2078     public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
2079                                                          $newest = false, $timefrom = 0) {
2080         global $CFG, $PAGE, $USER;
2082         // Check if messaging is enabled.
2083         if (empty($CFG->messaging)) {
2084             throw new moodle_exception('disabled', 'message');
2085         }
2087         $systemcontext = context_system::instance();
2089         $params = array(
2090             'currentuserid' => $currentuserid,
2091             'otheruserid' => $otheruserid,
2092             'limitfrom' => $limitfrom,
2093             'limitnum' => $limitnum,
2094             'newest' => $newest,
2095             'timefrom' => $timefrom,
2096         );
2097         $params = self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
2098         self::validate_context($systemcontext);
2100         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2101             throw new moodle_exception('You do not have permission to perform this action.');
2102         }
2104         if ($params['newest']) {
2105             $sort = 'timecreated DESC';
2106         } else {
2107             $sort = 'timecreated ASC';
2108         }
2110         // We need to enforce a one second delay on messages to avoid race conditions of current
2111         // messages still being sent.
2112         //
2113         // There is a chance that we could request messages before the current time's
2114         // second has elapsed and while other messages are being sent in that same second. In which
2115         // case those messages will be lost.
2116         //
2117         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
2118         if (!empty($params['timefrom'])) {
2119             $timeto = time() - 1;
2120         } else {
2121             $timeto = 0;
2122         }
2124         // No requesting messages from the current time, as stated above.
2125         if ($params['timefrom'] == time()) {
2126             $messages = [];
2127         } else {
2128             $messages = \core_message\api::get_messages($params['currentuserid'], $params['otheruserid'], $params['limitfrom'],
2129                                                         $params['limitnum'], $sort, $params['timefrom'], $timeto);
2130         }
2132         $messages = new \core_message\output\messagearea\messages($params['currentuserid'], $params['otheruserid'], $messages);
2134         $renderer = $PAGE->get_renderer('core_message');
2135         return $messages->export_for_template($renderer);
2136     }
2138     /**
2139      * The messagearea messages return structure.
2140      *
2141      * @deprecated since 3.6
2142      * @return external_single_structure
2143      * @since 3.2
2144      */
2145     public static function data_for_messagearea_messages_returns() {
2146         return new external_single_structure(
2147             array(
2148                 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
2149                     the messages on behalf of?'),
2150                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2151                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2152                 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
2153                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2154                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2155                 'messages' => new external_multiple_structure(
2156                     self::get_messagearea_message_structure()
2157                 ),
2158                 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
2159             )
2160         );
2161     }
2163     /**
2164      * Marking the method as deprecated.
2165      *
2166      * @return bool
2167      */
2168     public static function data_for_messagearea_messages_is_deprecated() {
2169         return true;
2170     }
2172     /**
2173      * The conversation messages parameters.
2174      *
2175      * @return external_function_parameters
2176      * @since 3.6
2177      */
2178     public static function get_conversation_messages_parameters() {
2179         return new external_function_parameters(
2180             array(
2181                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2182                 'convid' => new external_value(PARAM_INT, 'The conversation id'),
2183                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2184                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
2185                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
2186                 'timefrom' => new external_value(PARAM_INT,
2187                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
2188             )
2189         );
2190     }
2192     /**
2193      * Get conversation messages.
2194      *
2195      * @param  int $currentuserid The current user's id.
2196      * @param  int $convid The conversation id.
2197      * @param  int $limitfrom Return a subset of records, starting at this point (optional).
2198      * @param  int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
2199      * @param  bool $newest True for getting first newest messages, false otherwise.
2200      * @param  int  $timefrom The time from the conversation messages to get.
2201      * @return stdClass The messages and members who have sent some of these messages.
2202      * @throws moodle_exception
2203      * @since 3.6
2204      */
2205     public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
2206                                                          bool $newest = false, int $timefrom = 0) {
2207         global $CFG, $PAGE, $USER;
2209         // Check if messaging is enabled.
2210         if (empty($CFG->messaging)) {
2211             throw new moodle_exception('disabled', 'message');
2212         }
2214         $systemcontext = context_system::instance();
2216         $params = array(
2217             'currentuserid' => $currentuserid,
2218             'convid' => $convid,
2219             'limitfrom' => $limitfrom,
2220             'limitnum' => $limitnum,
2221             'newest' => $newest,
2222             'timefrom' => $timefrom,
2223         );
2224         $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
2225         self::validate_context($systemcontext);
2227         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2228             throw new moodle_exception('You do not have permission to perform this action.');
2229         }
2231         $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
2233         // We need to enforce a one second delay on messages to avoid race conditions of current
2234         // messages still being sent.
2235         //
2236         // There is a chance that we could request messages before the current time's
2237         // second has elapsed and while other messages are being sent in that same second. In which
2238         // case those messages will be lost.
2239         //
2240         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
2241         $timeto = empty($params['timefrom']) ? 0 : time() - 1;
2243         // No requesting messages from the current time, as stated above.
2244         if ($params['timefrom'] == time()) {
2245             $messages = [];
2246         } else {
2247             $messages = \core_message\api::get_conversation_messages(
2248                 $params['currentuserid'],
2249                 $params['convid'],
2250                 $params['limitfrom'],
2251                 $params['limitnum'],
2252                 $sort,
2253                 $params['timefrom'],
2254                 $timeto);
2255         }
2257         return $messages;
2258     }
2260     /**
2261      * The messagearea messages return structure.
2262      *
2263      * @return external_single_structure
2264      * @since 3.6
2265      */
2266     public static function get_conversation_messages_returns() {
2267         return new external_single_structure(
2268             array(
2269                 'id' => new external_value(PARAM_INT, 'The conversation id'),
2270                 'members' => new external_multiple_structure(
2271                     self::get_conversation_member_structure()
2272                 ),
2273                 'messages' => new external_multiple_structure(
2274                     self::get_conversation_message_structure()
2275                 ),
2276             )
2277         );
2278     }
2280     /**
2281      * The user contacts return parameters.
2282      *
2283      * @return external_function_parameters
2284      */
2285     public static function get_user_contacts_parameters() {
2286         return new external_function_parameters(
2287             array(
2288                 'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
2289                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2290                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
2291             )
2292         );
2293     }
2295     /**
2296      * Get user contacts.
2297      *
2298      * @param int $userid The id of the user who we are viewing conversations for
2299      * @param int $limitfrom
2300      * @param int $limitnum
2301      * @return array
2302      * @throws moodle_exception
2303      */
2304     public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
2305         global $CFG, $USER;
2307         // Check if messaging is enabled.
2308         if (empty($CFG->messaging)) {
2309             throw new moodle_exception('disabled', 'message');
2310         }
2312         $systemcontext = context_system::instance();
2314         $params = array(
2315             'userid' => $userid,
2316             'limitfrom' => $limitfrom,
2317             'limitnum' => $limitnum
2318         );
2319         $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
2320         self::validate_context($systemcontext);
2322         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2323             throw new moodle_exception('You do not have permission to perform this action.');
2324         }
2326         return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
2327     }
2329     /**
2330      * The user contacts return structure.
2331      *
2332      * @return external_multiple_structure
2333      */
2334     public static function get_user_contacts_returns() {
2335         return new external_multiple_structure(
2336             self::get_conversation_member_structure()
2337         );
2338     }
2340     /**
2341      * The get most recent message return parameters.
2342      *
2343      * @deprecated since 3.6
2344      * @return external_function_parameters
2345      * @since 3.2
2346      */
2347     public static function data_for_messagearea_get_most_recent_message_parameters() {
2348         return new external_function_parameters(
2349             array(
2350                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2351                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2352             )
2353         );
2354     }
2356     /**
2357      * Get the most recent message in a conversation.
2358      *
2359      * @deprecated since 3.6
2360      * @param int $currentuserid The current user's id
2361      * @param int $otheruserid The other user's id
2362      * @return stdClass
2363      * @throws moodle_exception
2364      * @since 3.2
2365      */
2366     public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
2367         global $CFG, $PAGE, $USER;
2369         // Check if messaging is enabled.
2370         if (empty($CFG->messaging)) {
2371             throw new moodle_exception('disabled', 'message');
2372         }
2374         $systemcontext = context_system::instance();
2376         $params = array(
2377             'currentuserid' => $currentuserid,
2378             'otheruserid' => $otheruserid
2379         );
2380         $params = self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
2381         self::validate_context($systemcontext);
2383         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2384             throw new moodle_exception('You do not have permission to perform this action.');
2385         }
2387         $message = \core_message\api::get_most_recent_message($params['currentuserid'], $params['otheruserid']);
2388         $message = new \core_message\output\messagearea\message($message);
2390         $renderer = $PAGE->get_renderer('core_message');
2391         return $message->export_for_template($renderer);
2392     }
2394     /**
2395      * The get most recent message return structure.
2396      *
2397      * @deprecated since 3.6
2398      * @return external_single_structure
2399      * @since 3.2
2400      */
2401     public static function data_for_messagearea_get_most_recent_message_returns() {
2402         return self::get_messagearea_message_structure();
2403     }
2405     /**
2406      * Marking the method as deprecated.
2407      *
2408      * @return bool
2409      */
2410     public static function data_for_messagearea_get_most_recent_message_is_deprecated() {
2411         return true;
2412     }
2414     /**
2415      * The get profile parameters.
2416      *
2417      * @deprecated since 3.6
2418      * @return external_function_parameters
2419      * @since 3.2
2420      */
2421     public static function data_for_messagearea_get_profile_parameters() {
2422         return new external_function_parameters(
2423             array(
2424                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2425                 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
2426             )
2427         );
2428     }
2430     /**
2431      * Get the profile information for a contact.
2432      *
2433      * @deprecated since 3.6
2434      * @param int $currentuserid The current user's id
2435      * @param int $otheruserid The id of the user whose profile we are viewing
2436      * @return stdClass
2437      * @throws moodle_exception
2438      * @since 3.2
2439      */
2440     public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
2441         global $CFG, $PAGE, $USER;
2443         // Check if messaging is enabled.
2444         if (empty($CFG->messaging)) {
2445             throw new moodle_exception('disabled', 'message');
2446         }
2448         $systemcontext = context_system::instance();
2450         $params = array(
2451             'currentuserid' => $currentuserid,
2452             'otheruserid' => $otheruserid
2453         );
2454         $params = self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
2455         self::validate_context($systemcontext);
2457         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2458             throw new moodle_exception('You do not have permission to perform this action.');
2459         }
2461         $profile = \core_message\api::get_profile($params['currentuserid'], $params['otheruserid']);
2462         $profile = new \core_message\output\messagearea\profile($profile);
2464         $renderer = $PAGE->get_renderer('core_message');
2465         return $profile->export_for_template($renderer);
2466     }
2468     /**
2469      * The get profile return structure.
2470      *
2471      * @deprecated since 3.6
2472      * @return external_single_structure
2473      * @since 3.2
2474      */
2475     public static function data_for_messagearea_get_profile_returns() {
2476         return new external_single_structure(
2477             array(
2478                 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
2479                 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
2480                 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
2481                 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
2482                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
2483                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
2484                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
2485                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2486                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2487                 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
2488                 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
2489             )
2490         );
2491     }
2493     /**
2494      * Marking the method as deprecated.
2495      *
2496      * @return bool
2497      */
2498     public static function data_for_messagearea_get_profile_is_deprecated() {
2499         return true;
2500     }
2502     /**
2503      * Get contacts parameters description.
2504      *
2505      * @deprecated since 3.6
2506      * @return external_function_parameters
2507      * @since Moodle 2.5
2508      */
2509     public static function get_contacts_parameters() {
2510         return new external_function_parameters(array());
2511     }
2513     /**
2514      * Get contacts.
2515      *
2516      * @deprecated since 3.6
2517      * @return external_description
2518      * @since Moodle 2.5
2519      */
2520     public static function get_contacts() {
2521         global $CFG, $PAGE, $USER;
2523         // Check if messaging is enabled.
2524         if (empty($CFG->messaging)) {
2525             throw new moodle_exception('disabled', 'message');
2526         }
2528         require_once($CFG->dirroot . '/user/lib.php');
2530         $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
2531         $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
2532         foreach ($contacts as $contact) {
2533             // Set the mode.
2534             $mode = 'offline';
2535             if (\core_message\helper::is_online($contact->lastaccess)) {
2536                 $mode = 'online';
2537             }
2539             $newcontact = array(
2540                 'id' => $contact->id,
2541                 'fullname' => fullname($contact),
2542                 'unread' => $contact->messagecount
2543             );
2545             $userpicture = new user_picture($contact);
2546             $userpicture->size = 1; // Size f1.
2547             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2548             $userpicture->size = 0; // Size f2.
2549             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2551             $allcontacts[$mode][$contact->id] = $newcontact;
2552         }
2554         $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
2555         foreach ($strangers as $contact) {
2556             $newcontact = array(
2557                 'id' => $contact->id,
2558                 'fullname' => fullname($contact),
2559                 'unread' => $contact->messagecount
2560             );
2562             $userpicture = new user_picture($contact);
2563             $userpicture->size = 1; // Size f1.
2564             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2565             $userpicture->size = 0; // Size f2.
2566             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2568             $allcontacts['strangers'][$contact->id] = $newcontact;
2569         }
2571         // Add noreply user and support user to the list, if they don't exist.
2572         $supportuser = core_user::get_support_user();
2573         if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
2574             $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
2575             if ($supportuser->messagecount > 0) {
2576                 $supportuser->fullname = fullname($supportuser);
2577                 $supportuser->unread = $supportuser->messagecount;
2578                 $allcontacts['strangers'][$supportuser->id] = $supportuser;
2579             }
2580         }
2582         $noreplyuser = core_user::get_noreply_user();
2583         if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
2584             $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
2585             if ($noreplyuser->messagecount > 0) {
2586                 $noreplyuser->fullname = fullname($noreplyuser);
2587                 $noreplyuser->unread = $noreplyuser->messagecount;
2588                 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
2589             }
2590         }
2592         return $allcontacts;
2593     }
2595     /**
2596      * Get contacts return description.
2597      *
2598      * @deprecated since 3.6
2599      * @return external_description
2600      * @since Moodle 2.5
2601      */
2602     public static function get_contacts_returns() {
2603         return new external_single_structure(
2604             array(
2605                 'online' => new external_multiple_structure(
2606                     new external_single_structure(
2607                         array(
2608                             'id' => new external_value(PARAM_INT, 'User ID'),
2609                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2610                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2611                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2612                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2613                         )
2614                     ),
2615                     'List of online contacts'
2616                 ),
2617                 'offline' => new external_multiple_structure(
2618                     new external_single_structure(
2619                         array(
2620                             'id' => new external_value(PARAM_INT, 'User ID'),
2621                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2622                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2623                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2624                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2625                         )
2626                     ),
2627                     'List of offline contacts'
2628                 ),
2629                 'strangers' => new external_multiple_structure(
2630                     new external_single_structure(
2631                         array(
2632                             'id' => new external_value(PARAM_INT, 'User ID'),
2633                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2634                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2635                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2636                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2637                         )
2638                     ),
2639                     'List of users that are not in the user\'s contact list but have sent a message'
2640                 )
2641             )
2642         );
2643     }
2645     /**
2646      * Marking the method as deprecated.
2647      *
2648      * @return bool
2649      */
2650     public static function get_contacts_is_deprecated() {
2651         return true;
2652     }
2654     /**
2655      * Search contacts parameters description.
2656      *
2657      * @return external_function_parameters
2658      * @since Moodle 2.5
2659      */
2660     public static function search_contacts_parameters() {
2661         return new external_function_parameters(
2662             array(
2663                 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2664                 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2665                     VALUE_DEFAULT, false)
2666             )
2667         );
2668     }
2670     /**
2671      * Search contacts.
2672      *
2673      * @param string $searchtext query string.
2674      * @param bool $onlymycourses limit the search to the user's courses only.
2675      * @return external_description
2676      * @since Moodle 2.5
2677      */
2678     public static function search_contacts($searchtext, $onlymycourses = false) {
2679         global $CFG, $USER, $PAGE;
2680         require_once($CFG->dirroot . '/user/lib.php');
2682         // Check if messaging is enabled.
2683         if (empty($CFG->messaging)) {
2684             throw new moodle_exception('disabled', 'message');
2685         }
2687         require_once($CFG->libdir . '/enrollib.php');
2689         $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2690         $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2692         // Extra validation, we do not allow empty queries.
2693         if ($params['searchtext'] === '') {
2694             throw new moodle_exception('querystringcannotbeempty');
2695         }
2697         $courseids = array();
2698         if ($params['onlymycourses']) {
2699             $mycourses = enrol_get_my_courses(array('id'));
2700             foreach ($mycourses as $mycourse) {
2701                 $courseids[] = $mycourse->id;
2702             }
2703         } else {
2704             $courseids[] = SITEID;
2705         }
2707         // Retrieving the users matching the query.
2708         $users = message_search_users($courseids, $params['searchtext']);
2709         $results = array();
2710         foreach ($users as $user) {
2711             $results[$user->id] = $user;
2712         }
2714         // Reorganising information.
2715         foreach ($results as &$user) {
2716             $newuser = array(
2717                 'id' => $user->id,
2718                 'fullname' => fullname($user)
2719             );
2721             // Avoid undefined property notice as phone not specified.
2722             $user->phone1 = null;
2723             $user->phone2 = null;
2725             $userpicture = new user_picture($user);
2726             $userpicture->size = 1; // Size f1.
2727             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2728             $userpicture->size = 0; // Size f2.
2729             $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2731             $user = $newuser;
2732         }
2734         return $results;
2735     }
2737     /**
2738      * Search contacts return description.
2739      *
2740      * @return external_description
2741      * @since Moodle 2.5
2742      */
2743     public static function search_contacts_returns() {
2744         return new external_multiple_structure(
2745             new external_single_structure(
2746                 array(
2747                     'id' => new external_value(PARAM_INT, 'User ID'),
2748                     'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2749                     'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2750                     'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
2751                 )
2752             ),
2753             'List of contacts'
2754         );
2755     }
2757     /**
2758      * Get messages parameters description.
2759      *
2760      * @return external_function_parameters
2761      * @since 2.8
2762      */
2763     public static function get_messages_parameters() {
2764         return new external_function_parameters(
2765             array(
2766                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2767                 'useridfrom' => new external_value(
2768                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2769                     VALUE_DEFAULT, 0),
2770                 'type' => new external_value(
2771                     PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2772                     VALUE_DEFAULT, 'both'),
2773                 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2774                 'newestfirst' => new external_value(
2775                     PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2776                     VALUE_DEFAULT, true),
2777                 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2778                 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2779             )
2780         );
2781     }
2783     /**
2784      * Get messages function implementation.
2785      *
2786      * @since  2.8
2787      * @throws invalid_parameter_exception
2788      * @throws moodle_exception
2789      * @param  int      $useridto       the user id who received the message
2790      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2791      * @param  string   $type           type of message to return, expected values: notifications, conversations and both
2792      * @param  bool     $read           true for retreiving read messages, false for unread
2793      * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
2794      * @param  int      $limitfrom      limit from
2795      * @param  int      $limitnum       limit num
2796      * @return external_description
2797      */
2798     public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2799                                         $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2800         global $CFG, $USER;
2802         $warnings = array();
2804         $params = array(
2805             'useridto' => $useridto,
2806             'useridfrom' => $useridfrom,
2807             'type' => $type,
2808             'read' => $read,
2809             'newestfirst' => $newestfirst,
2810             'limitfrom' => $limitfrom,
2811             'limitnum' => $limitnum
2812         );
2814         $params = self::validate_parameters(self::get_messages_parameters(), $params);
2816         $context = context_system::instance();
2817         self::validate_context($context);
2819         $useridto = $params['useridto'];
2820         $useridfrom = $params['useridfrom'];
2821         $type = $params['type'];
2822         $read = $params['read'];
2823         $newestfirst = $params['newestfirst'];
2824         $limitfrom = $params['limitfrom'];
2825         $limitnum = $params['limitnum'];
2827         $allowedvalues = array('notifications', 'conversations', 'both');
2828         if (!in_array($type, $allowedvalues)) {
2829             throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2830                 'allowed values are: ' . implode(',', $allowedvalues));
2831         }
2833         // Check if private messaging between users is allowed.
2834         if (empty($CFG->messaging)) {
2835             // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2836             if ($type == "conversations") {
2837                 throw new moodle_exception('disabled', 'message');
2838             }
2839             if ($type == "both") {
2840                 $warning = array();
2841                 $warning['item'] = 'message';
2842                 $warning['itemid'] = $USER->id;
2843                 $warning['warningcode'] = '1';
2844                 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2845                     Only notifications will be returned';
2846                 $warnings[] = $warning;
2847             }
2848         }
2850         if (!empty($useridto)) {
2851             if (core_user::is_real_user($useridto)) {
2852                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2853             } else {
2854                 throw new moodle_exception('invaliduser');
2855             }
2856         }
2858         if (!empty($useridfrom)) {
2859             // We use get_user here because the from user can be the noreply or support user.
2860             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2861         }
2863         // Check if the current user is the sender/receiver or just a privileged user.
2864         if ($useridto != $USER->id and $useridfrom != $USER->id and
2865              !has_capability('moodle/site:readallmessages', $context)) {
2866             throw new moodle_exception('accessdenied', 'admin');
2867         }
2869         // Which type of messages to retrieve.
2870         $notifications = -1;
2871         if ($type != 'both') {
2872             $notifications = ($type == 'notifications') ? 1 : 0;
2873         }
2875         $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2876         $sort = "mr.timecreated $orderdirection";
2878         if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2879             $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2881             // In some cases, we don't need to get the to/from user objects from the sql query.
2882             $userfromfullname = '';
2883             $usertofullname = '';
2885             // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2886             if (!empty($useridto)) {
2887                 $usertofullname = fullname($userto, $canviewfullname);
2888                 // The user from may or may not be filled.
2889                 if (!empty($useridfrom)) {
2890                     $userfromfullname = fullname($userfrom, $canviewfullname);
2891                 }
2892             } else {
2893                 // If the useridto field is empty, the useridfrom must be filled.
2894                 $userfromfullname = fullname($userfrom, $canviewfullname);
2895             }
2896             foreach ($messages as $mid => $message) {
2898                 // Do not return deleted messages.
2899                 if (!$message->notification) {
2900                     if (($useridto == $USER->id and $message->timeusertodeleted) or
2901                         ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2902                         unset($messages[$mid]);
2903                         continue;
2904                     }
2905                 }
2907                 // We need to get the user from the query.
2908                 if (empty($userfromfullname)) {
2909                     // Check for non-reply and support users.
2910                     if (core_user::is_real_user($message->useridfrom)) {
2911                         $user = new stdClass();
2912                         $user = username_load_fields_from_object($user, $message, 'userfrom');
2913                         $message->userfromfullname = fullname($user, $canviewfullname);
2914                     } else {
2915                         $user = core_user::get_user($message->useridfrom);
2916                         $message->userfromfullname = fullname($user, $canviewfullname);
2917                     }
2918                 } else {
2919                     $message->userfromfullname = $userfromfullname;
2920                 }
2922                 // We need to get the user from the query.
2923                 if (empty($usertofullname)) {
2924                     $user = new stdClass();
2925                     $user = username_load_fields_from_object($user, $message, 'userto');
2926                     $message->usertofullname = fullname($user, $canviewfullname);
2927                 } else {
2928                     $message->usertofullname = $usertofullname;
2929                 }
2931                 $message->text = message_format_message_text($message);
2932                 $messages[$mid] = (array) $message;
2933             }
2934         }
2936         $results = array(
2937             'messages' => $messages,
2938             'warnings' => $warnings
2939         );
2941         return $results;
2942     }
2944     /**
2945      * Get messages return description.
2946      *
2947      * @return external_single_structure
2948      * @since 2.8
2949      */
2950     public static function get_messages_returns() {
2951         return new external_single_structure(
2952             array(
2953                 'messages' => new external_multiple_structure(
2954                     new external_single_structure(
2955                         array(
2956                             'id' => new external_value(PARAM_INT, 'Message id'),
2957                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2958                             'useridto' => new external_value(PARAM_INT, 'User to id'),
2959                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2960                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
2961                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2962                             'fullmessageformat' => new external_format_value('fullmessage'),
2963                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2964                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2965                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2966                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2967                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2968                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
2969                             'timeread' => new external_value(PARAM_INT, 'Time read'),
2970                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2971                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2972                         ), 'message'
2973                     )
2974                 ),
2975                 'warnings' => new external_warnings()
2976             )
2977         );
2978     }
2980     /**
2981      * Mark all notifications as read parameters description.
2982      *
2983      * @return external_function_parameters
2984      * @since 3.2
2985      */
2986     public static function mark_all_notifications_as_read_parameters() {
2987         return new external_function_parameters(
2988             array(
2989                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2990                 'useridfrom' => new external_value(
2991                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2992                     VALUE_DEFAULT, 0),
2993             )
2994         );
2995     }
2997     /**
2998      * Mark all notifications as read function.
2999      *
3000      * @since  3.2
3001      * @throws invalid_parameter_exception
3002      * @throws moodle_exception
3003      * @param  int      $useridto       the user id who received the message
3004      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
3005      * @return external_description
3006      */
3007     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
3008         global $USER;
3010         $params = self::validate_parameters(
3011             self::mark_all_notifications_as_read_parameters(),
3012             array(
3013                 'useridto' => $useridto,
3014                 'useridfrom' => $useridfrom,
3015             )
3016         );
3018         $context = context_system::instance();
3019         self::validate_context($context);
3021         $useridto = $params['useridto'];
3022         $useridfrom = $params['useridfrom'];
3024         if (!empty($useridto)) {
3025             if (core_user::is_real_user($useridto)) {
3026                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3027             } else {
3028                 throw new moodle_exception('invaliduser');
3029             }
3030         }
3032         if (!empty($useridfrom)) {
3033             // We use get_user here because the from user can be the noreply or support user.
3034             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3035         }
3037         // Check if the current user is the sender/receiver or just a privileged user.
3038         if ($useridto != $USER->id and $useridfrom != $USER->id and
3039             // The deleteanymessage cap seems more reasonable here than readallmessages.
3040              !has_capability('moodle/site:deleteanymessage', $context)) {
3041             throw new moodle_exception('accessdenied', 'admin');
3042         }
3044         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
3046         return true;
3047     }
3049     /**
3050      * Mark all notifications as read return description.
3051      *
3052      * @return external_single_structure
3053      * @since 3.2
3054      */
3055     public static function mark_all_notifications_as_read_returns() {
3056         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
3057     }
3059     /**
3060      * Get unread conversations count parameters description.
3061      *
3062      * @return external_function_parameters
3063      * @since 3.2
3064      */
3065     public static function get_unread_conversations_count_parameters() {
3066         return new external_function_parameters(
3067             array(
3068                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3069             )
3070         );
3071     }
3073     /**
3074      * Get unread messages count function.
3075      *
3076      * @since  3.2
3077      * @throws invalid_parameter_exception
3078      * @throws moodle_exception
3079      * @param  int      $useridto       the user id who received the message
3080      * @return external_description
3081      */
3082     public static function get_unread_conversations_count($useridto) {
3083         global $USER, $CFG;
3085         // Check if messaging is enabled.
3086         if (empty($CFG->messaging)) {
3087             throw new moodle_exception('disabled', 'message');
3088         }
3090         $params = self::validate_parameters(
3091             self::get_unread_conversations_count_parameters(),
3092             array('useridto' => $useridto)
3093         );
3095         $context = context_system::instance();
3096         self::validate_context($context);
3098         $useridto = $params['useridto'];
3100         if (!empty($useridto)) {
3101             if (core_user::is_real_user($useridto)) {
3102                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3103             } else {
3104                 throw new moodle_exception('invaliduser');
3105             }
3106         } else {
3107             $useridto = $USER->id;
3108         }
3110         // Check if the current user is the receiver or just a privileged user.
3111         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
3112             throw new moodle_exception('accessdenied', 'admin');
3113         }
3115         return \core_message\api::count_unread_conversations($userto);
3116     }
3118     /**
3119      * Get unread conversations count return description.
3120      *
3121      * @return external_single_structure
3122      * @since 3.2
3123      */
3124     public static function get_unread_conversations_count_returns() {
3125         return new external_value(PARAM_INT, 'The count of unread messages for the user');
3126     }
3128     /**
3129      * Get blocked users parameters description.
3130      *
3131      * @return external_function_parameters
3132      * @since 2.9
3133      */
3134     public static function get_blocked_users_parameters() {
3135         return new external_function_parameters(
3136             array(
3137                 'userid' => new external_value(PARAM_INT,
3138                                 'the user whose blocked users we want to retrieve',
3139                                 VALUE_REQUIRED),
3140             )
3141         );
3142     }
3144     /**
3145      * Retrieve a list of users blocked
3146      *
3147      * @param  int $userid the user whose blocked users we want to retrieve
3148      * @return external_description
3149      * @since 2.9
3150      */
3151     public static function get_blocked_users($userid) {
3152         global $CFG, $USER, $PAGE;
3154         // Warnings array, it can be empty at the end but is mandatory.
3155         $warnings = array();
3157         // Validate params.
3158         $params = array(
3159             'userid' => $userid
3160         );
3161         $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
3162         $userid = $params['userid'];
3164         // Validate context.
3165         $context = context_system::instance();
3166         self::validate_context($context);
3168         // Check if private messaging between users is allowed.
3169         if (empty($CFG->messaging)) {
3170             throw new moodle_exception('disabled', 'message');
3171         }
3173         $user = core_user::get_user($userid, '*', MUST_EXIST);
3174         core_user::require_active_user($user);
3176         // Check if we have permissions for retrieve the information.
3177         $capability = 'moodle/site:manageallmessaging';
3178         if (($USER->id != $userid) && !has_capability($capability, $context)) {
3179             throw new required_capability_exception($context, $capability, 'nopermissions', '');
3180         }
3182         // Now, we can get safely all the blocked users.
3183         $users = \core_message\api::get_blocked_users($user->id);
3185         $blockedusers = array();
3186         foreach ($users as $user) {
3187             $newuser = array(
3188                 'id' => $user->id,
3189                 'fullname' => fullname($user),
3190             );
3192             $userpicture = new user_picture($user);
3193             $userpicture->size = 1; // Size f1.
3194             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
3196             $blockedusers[] = $newuser;
3197         }
3199         $results = array(
3200             'users' => $blockedusers,
3201             'warnings' => $warnings
3202         );
3203         return $results;
3204     }
3206     /**
3207      * Get blocked users return description.
3208      *
3209      * @return external_single_structure
3210      * @since 2.9
3211      */
3212     public static function get_blocked_users_returns() {
3213         return new external_single_structure(
3214             array(
3215                 'users' => new external_multiple_structure(
3216                     new external_single_structure(
3217                         array(
3218                             'id' => new external_value(PARAM_INT, 'User ID'),
3219                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
3220                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
3221                         )
3222                     ),
3223                     'List of blocked users'
3224                 ),
3225                 'warnings' => new external_warnings()
3226             )
3227         );
3228     }
3230     /**
3231      * Returns description of method parameters
3232      *
3233      * @return external_function_parameters
3234      * @since 2.9
3235      */
3236     public static function mark_message_read_parameters() {
3237         return new external_function_parameters(
3238             array(
3239                 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
3240                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
3241                     VALUE_DEFAULT, 0)
3242             )
3243         );
3244     }
3246     /**
3247      * Mark a single message as read, trigger message_viewed event
3248      *
3249      * @param  int $messageid id of the message (in the message table)
3250      * @param  int $timeread timestamp for when the message should be marked read
3251      * @return external_description
3252      * @throws invalid_parameter_exception
3253      * @throws moodle_exception
3254      * @since 2.9
3255      */
3256     public static function mark_message_read($messageid, $timeread) {
3257         global $CFG, $DB, $USER;
3259         // Check if private messaging between users is allowed.
3260         if (empty($CFG->messaging)) {
3261             throw new moodle_exception('disabled', 'message');
3262         }
3264         // Warnings array, it can be empty at the end but is mandatory.
3265         $warnings = array();
3267         // Validate params.
3268         $params = array(
3269             'messageid' => $messageid,
3270             'timeread' => $timeread
3271         );
3272         $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
3274         if (empty($params['timeread'])) {
3275             $timeread = time();
3276         } else {
3277             $timeread = $params['timeread'];
3278         }
3280         // Validate context.
3281         $context = context_system::instance();
3282         self::validate_context($context);
3284         $sql = "SELECT m.*, mcm.userid as useridto
3285                   FROM {messages} m
3286             INNER JOIN {message_conversations} mc
3287                     ON m.conversationid = mc.id
3288             INNER JOIN {message_conversation_members} mcm
3289                     ON mcm.conversationid = mc.id
3290              LEFT JOIN {message_user_actions} mua
3291                     ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
3292                  WHERE mua.id is NULL
3293                    AND mcm.userid != m.useridfrom
3294                    AND m.id = ?";
3295         $messageparams = [];
3296         $messageparams[] = $USER->id;
3297         $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
3298         $messageparams[] = $params['messageid'];
3299         $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
3301         if ($message->useridto != $USER->id) {
3302             throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
3303         }
3305         \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
3307         $results = array(
3308             'messageid' => $message->id,
3309             'warnings' => $warnings
3310         );
3311         return $results;
3312     }
3314     /**
3315      * Returns description of method result value
3316      *
3317      * @return external_description
3318      * @since 2.9
3319      */
3320     public static function mark_message_read_returns() {
3321         return new external_single_structure(
3322             array(
3323                 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
3324                 'warnings' => new external_warnings()
3325             )
3326         );
3327     }
3329     /**
3330      * Returns description of method parameters
3331      *
3332      * @return external_function_parameters
3333      */
3334     public static function mark_notification_read_parameters() {
3335         return new external_function_parameters(
3336             array(
3337                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
3338                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
3339                     VALUE_DEFAULT, 0)
3340             )
3341         );
3342     }
3344     /**
3345      * Mark a single notification as read.
3346      *
3347      * This will trigger a 'notification_viewed' event.
3348      *
3349      * @param int $notificationid id of the notification
3350      * @param int $timeread timestamp for when the notification should be marked read
3351      * @return external_description
3352      * @throws invalid_parameter_exception
3353      * @throws moodle_exception
3354      */
3355     public static function mark_notification_read($notificationid, $timeread) {
3356         global $CFG, $DB, $USER;
3358         // Check if private messaging between users is allowed.
3359         if (empty($CFG->messaging)) {
3360             throw new moodle_exception('disabled', 'message');
3361         }
3363         // Warnings array, it can be empty at the end but is mandatory.
3364         $warnings = array();
3366         // Validate params.
3367         $params = array(
3368             'notificationid' => $notificationid,
3369             'timeread' => $timeread
3370         );
3371         $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
3373         if (empty($params['timeread'])) {
3374             $timeread = time();
3375         } else {
3376             $timeread = $params['timeread'];
3377         }
3379         // Validate context.
3380         $context = context_system::instance();
3381         self::validate_context($context);
3383         $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
3385         if ($notification->useridto != $USER->id) {
3386             throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
3387                 'notification as read');
3388         }
3390         \core_message\api::mark_notification_as_read($notification, $timeread);
3392         $results = array(
3393             'notificationid' => $notification->id,
3394             'warnings' => $warnings
3395         );
3397         return $results;
3398     }
3400     /**
3401      * Returns description of method result value
3402      *
3403      * @return external_description
3404      */
3405     public static function mark_notification_read_returns() {
3406         return new external_single_structure(
3407             array(
3408                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),