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