42c4491055f8370eecaddb9dd7bb394237fe78b7
[moodle.git] / message / externallib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * External message API
20  *
21  * @package    core_message
22  * @category   external
23  * @copyright  2011 Jerome Mouneyrac
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die();
29 require_once("$CFG->libdir/externallib.php");
30 require_once($CFG->dirroot . "/message/lib.php");
32 /**
33  * Message external functions
34  *
35  * @package    core_message
36  * @category   external
37  * @copyright  2011 Jerome Mouneyrac
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  * @since Moodle 2.2
40  */
41 class core_message_external extends external_api {
42     /**
43      * Returns description of method parameters
44      *
45      * @return external_function_parameters
46      * @since Moodle 3.6
47      */
48     public static function send_messages_to_conversation_parameters() {
49         return new external_function_parameters(
50             array(
51                 'conversationid' => new external_value(PARAM_INT, 'id of the conversation'),
52                 'messages' => new external_multiple_structure(
53                     new external_single_structure(
54                         array(
55                             'text' => new external_value(PARAM_RAW, 'the text of the message'),
56                             'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
57                         )
58                     )
59                 )
60             )
61         );
62     }
64     /**
65      * Send messages from the current USER to a conversation.
66      *
67      * This conversation may be any type of conversation, individual or group.
68      *
69      * @param int $conversationid the id of the conversation to which the messages will be sent.
70      * @param array $messages An array of message to send.
71      * @return array the array of messages which were sent (created).
72      * @since Moodle 3.6
73      */
74     public static function send_messages_to_conversation(int $conversationid, array $messages = []) {
75         global $CFG, $USER;
77         // Check if messaging is enabled.
78         if (empty($CFG->messaging)) {
79             throw new moodle_exception('disabled', 'message');
80         }
82         // Ensure the current user is allowed to run this function.
83         $context = context_system::instance();
84         self::validate_context($context);
86         $params = self::validate_parameters(self::send_messages_to_conversation_parameters(), [
87             'conversationid' => $conversationid,
88             'messages' => $messages
89         ]);
91         $messages = [];
92         foreach ($params['messages'] as $message) {
93             $messages[] = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
94                 $message['textformat']);
95         }
97         return $messages;
98     }
100     /**
101      * Returns description of method result value.
102      *
103      * @return external_description
104      * @since Moodle 3.6
105      */
106     public static function send_messages_to_conversation_returns() {
107         return new external_multiple_structure(
108             self::get_conversation_message_structure()
109         );
110     }
113     /**
114      * Returns description of method parameters
115      *
116      * @return external_function_parameters
117      * @since Moodle 2.2
118      */
119     public static function send_instant_messages_parameters() {
120         return new external_function_parameters(
121             array(
122                 'messages' => new external_multiple_structure(
123                     new external_single_structure(
124                         array(
125                             'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
126                             'text' => new external_value(PARAM_RAW, 'the text of the message'),
127                             'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
128                             'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the message. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL),
129                         )
130                     )
131                 )
132             )
133         );
134     }
136     /**
137      * Send private messages from the current USER to other users
138      *
139      * @param array $messages An array of message to send.
140      * @return array
141      * @since Moodle 2.2
142      */
143     public static function send_instant_messages($messages = array()) {
144         global $CFG, $USER, $DB;
146         // Check if messaging is enabled.
147         if (empty($CFG->messaging)) {
148             throw new moodle_exception('disabled', 'message');
149         }
151         // Ensure the current user is allowed to run this function
152         $context = context_system::instance();
153         self::validate_context($context);
154         require_capability('moodle/site:sendmessage', $context);
156         $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
158         //retrieve all tousers of the messages
159         $receivers = array();
160         foreach($params['messages'] as $message) {
161             $receivers[] = $message['touserid'];
162         }
163         list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
164         $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
166         $resultmessages = array();
167         foreach ($params['messages'] as $message) {
168             $resultmsg = array(); //the infos about the success of the operation
170             // We are going to do some checking.
171             // Code should match /messages/index.php checks.
172             $success = true;
174             // Check the user exists.
175             if (empty($tousers[$message['touserid']])) {
176                 $success = false;
177                 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
178             }
180             // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
181             // Check if the recipient can be messaged by the sender.
182             if ($success && !\core_message\api::can_post_message($tousers[$message['touserid']], $USER)) {
183                 $success = false;
184                 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
185             }
187             // Now we can send the message (at least try).
188             if ($success) {
189                 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
190                 $success = message_post_message($USER, $tousers[$message['touserid']],
191                         $message['text'], external_validate_format($message['textformat']));
192             }
194             // Build the resultmsg.
195             if (isset($message['clientmsgid'])) {
196                 $resultmsg['clientmsgid'] = $message['clientmsgid'];
197             }
198             if ($success) {
199                 $resultmsg['msgid'] = $success;
200             } else {
201                 // WARNINGS: for backward compatibility we return this errormessage.
202                 //          We should have thrown exceptions as these errors prevent results to be returned.
203                 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
204                 $resultmsg['msgid'] = -1;
205                 $resultmsg['errormessage'] = $errormessage;
206             }
208             $resultmessages[] = $resultmsg;
209         }
211         return $resultmessages;
212     }
214     /**
215      * Returns description of method result value
216      *
217      * @return external_description
218      * @since Moodle 2.2
219      */
220     public static function send_instant_messages_returns() {
221         return new external_multiple_structure(
222             new external_single_structure(
223                 array(
224                     'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
225                     'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
226                     'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
227                 )
228             )
229         );
230     }
232     /**
233      * Create contacts parameters description.
234      *
235      * @deprecated since Moodle 3.6
236      * @return external_function_parameters
237      * @since Moodle 2.5
238      */
239     public static function create_contacts_parameters() {
240         return new external_function_parameters(
241             array(
242                 'userids' => new external_multiple_structure(
243                     new external_value(PARAM_INT, 'User ID'),
244                     'List of user IDs'
245                 ),
246                 'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
247                     current user', VALUE_DEFAULT, 0)
248             )
249         );
250     }
252     /**
253      * Create contacts.
254      *
255      * @deprecated since Moodle 3.6
256      * @param array $userids array of user IDs.
257      * @param int $userid The id of the user we are creating the contacts for
258      * @return external_description
259      * @since Moodle 2.5
260      */
261     public static function create_contacts($userids, $userid = 0) {
262         global $CFG, $USER;
264         // Check if messaging is enabled.
265         if (empty($CFG->messaging)) {
266             throw new moodle_exception('disabled', 'message');
267         }
269         if (empty($userid)) {
270             $userid = $USER->id;
271         }
273         // Validate context.
274         $context = context_system::instance();
275         self::validate_context($context);
277         $params = array('userids' => $userids, 'userid' => $userid);
278         $params = self::validate_parameters(self::create_contacts_parameters(), $params);
280         $capability = 'moodle/site:manageallmessaging';
281         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
282             throw new required_capability_exception($context, $capability, 'nopermissions', '');
283         }
285         $warnings = array();
286         foreach ($params['userids'] as $id) {
287             if (!message_add_contact($id, 0, $params['userid'])) {
288                 $warnings[] = array(
289                     'item' => 'user',
290                     'itemid' => $id,
291                     'warningcode' => 'contactnotcreated',
292                     'message' => 'The contact could not be created'
293                 );
294             }
295         }
296         return $warnings;
297     }
299     /**
300      * Create contacts return description.
301      *
302      * @deprecated since Moodle 3.6
303      * @return external_description
304      * @since Moodle 2.5
305      */
306     public static function create_contacts_returns() {
307         return new external_warnings();
308     }
310     /**
311      * Marking the method as deprecated.
312      *
313      * @return bool
314      */
315     public static function create_contacts_is_deprecated() {
316         return true;
317     }
319     /**
320      * Delete contacts parameters description.
321      *
322      * @return external_function_parameters
323      * @since Moodle 2.5
324      */
325     public static function delete_contacts_parameters() {
326         return new external_function_parameters(
327             array(
328                 'userids' => new external_multiple_structure(
329                     new external_value(PARAM_INT, 'User ID'),
330                     'List of user IDs'
331                 ),
332                 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
333                     current user', VALUE_DEFAULT, 0)
334             )
335         );
336     }
338     /**
339      * Delete contacts.
340      *
341      * @param array $userids array of user IDs.
342      * @param int $userid The id of the user we are deleting the contacts for
343      * @return null
344      * @since Moodle 2.5
345      */
346     public static function delete_contacts($userids, $userid = 0) {
347         global $CFG, $USER;
349         // Check if messaging is enabled.
350         if (empty($CFG->messaging)) {
351             throw new moodle_exception('disabled', 'message');
352         }
354         if (empty($userid)) {
355             $userid = $USER->id;
356         }
358         // Validate context.
359         $context = context_system::instance();
360         self::validate_context($context);
362         $params = array('userids' => $userids, 'userid' => $userid);
363         $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
365         $capability = 'moodle/site:manageallmessaging';
366         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
367             throw new required_capability_exception($context, $capability, 'nopermissions', '');
368         }
370         foreach ($params['userids'] as $id) {
371             \core_message\api::remove_contact($params['userid'], $id);
372         }
374         return null;
375     }
377     /**
378      * Delete contacts return description.
379      *
380      * @return external_description
381      * @since Moodle 2.5
382      */
383     public static function delete_contacts_returns() {
384         return null;
385     }
387     /**
388      * Block user parameters description.
389      *
390      * @return external_function_parameters
391      */
392     public static function block_user_parameters() {
393         return new external_function_parameters(
394             [
395                 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
396                 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
397             ]
398         );
399     }
401     /**
402      * Blocks a user.
403      *
404      * @param int $userid The id of the user who is blocking
405      * @param int $blockeduserid The id of the user being blocked
406      * @return external_description
407      */
408     public static function block_user(int $userid, int $blockeduserid) {
409         global $CFG, $USER;
411         // Check if messaging is enabled.
412         if (empty($CFG->messaging)) {
413             throw new moodle_exception('disabled', 'message');
414         }
416         // Validate context.
417         $context = context_system::instance();
418         self::validate_context($context);
420         $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
421         $params = self::validate_parameters(self::block_user_parameters(), $params);
423         $capability = 'moodle/site:manageallmessaging';
424         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
425             throw new required_capability_exception($context, $capability, 'nopermissions', '');
426         }
428         if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
429             \core_message\api::block_user($params['userid'], $params['blockeduserid']);
430         }
432         return [];
433     }
435     /**
436      * Block user return description.
437      *
438      * @return external_description
439      */
440     public static function block_user_returns() {
441         return new external_warnings();
442     }
444     /**
445      * Unblock user parameters description.
446      *
447      * @return external_function_parameters
448      */
449     public static function unblock_user_parameters() {
450         return new external_function_parameters(
451             [
452                 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
453                 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
454             ]
455         );
456     }
458     /**
459      * Unblock user.
460      *
461      * @param int $userid The id of the user who is unblocking
462      * @param int $unblockeduserid The id of the user being unblocked
463      */
464     public static function unblock_user(int $userid, int $unblockeduserid) {
465         global $CFG, $USER;
467         // Check if messaging is enabled.
468         if (empty($CFG->messaging)) {
469             throw new moodle_exception('disabled', 'message');
470         }
472         // Validate context.
473         $context = context_system::instance();
474         self::validate_context($context);
476         $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
477         $params = self::validate_parameters(self::unblock_user_parameters(), $params);
479         $capability = 'moodle/site:manageallmessaging';
480         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
481             throw new required_capability_exception($context, $capability, 'nopermissions', '');
482         }
484         \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
486         return [];
487     }
489     /**
490      * Unblock user return description.
491      *
492      * @return external_description
493      */
494     public static function unblock_user_returns() {
495         return new external_warnings();
496     }
498     /**
499      * Block contacts parameters description.
500      *
501      * @deprecated since Moodle 3.6
502      * @return external_function_parameters
503      * @since Moodle 2.5
504      */
505     public static function block_contacts_parameters() {
506         return new external_function_parameters(
507             array(
508                 'userids' => new external_multiple_structure(
509                     new external_value(PARAM_INT, 'User ID'),
510                     'List of user IDs'
511                 ),
512                 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
513                     current user', VALUE_DEFAULT, 0)
514             )
515         );
516     }
518     /**
519      * Block contacts.
520      *
521      * @deprecated since Moodle 3.6
522      * @param array $userids array of user IDs.
523      * @param int $userid The id of the user we are blocking the contacts for
524      * @return external_description
525      * @since Moodle 2.5
526      */
527     public static function block_contacts($userids, $userid = 0) {
528         global $CFG, $USER;
530         // Check if messaging is enabled.
531         if (empty($CFG->messaging)) {
532             throw new moodle_exception('disabled', 'message');
533         }
535         if (empty($userid)) {
536             $userid = $USER->id;
537         }
539         // Validate context.
540         $context = context_system::instance();
541         self::validate_context($context);
543         $params = array('userids' => $userids, 'userid' => $userid);
544         $params = self::validate_parameters(self::block_contacts_parameters(), $params);
546         $capability = 'moodle/site:manageallmessaging';
547         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
548             throw new required_capability_exception($context, $capability, 'nopermissions', '');
549         }
551         $warnings = array();
552         foreach ($params['userids'] as $id) {
553             if (!message_block_contact($id, $params['userid'])) {
554                 $warnings[] = array(
555                     'item' => 'user',
556                     'itemid' => $id,
557                     'warningcode' => 'contactnotblocked',
558                     'message' => 'The contact could not be blocked'
559                 );
560             }
561         }
562         return $warnings;
563     }
565     /**
566      * Block contacts return description.
567      *
568      * @deprecated since Moodle 3.6
569      * @return external_description
570      * @since Moodle 2.5
571      */
572     public static function block_contacts_returns() {
573         return new external_warnings();
574     }
576     /**
577      * Marking the method as deprecated.
578      *
579      * @return bool
580      */
581     public static function block_contacts_is_deprecated() {
582         return true;
583     }
585     /**
586      * Unblock contacts parameters description.
587      *
588      * @deprecated since Moodle 3.6
589      * @return external_function_parameters
590      * @since Moodle 2.5
591      */
592     public static function unblock_contacts_parameters() {
593         return new external_function_parameters(
594             array(
595                 'userids' => new external_multiple_structure(
596                     new external_value(PARAM_INT, 'User ID'),
597                     'List of user IDs'
598                 ),
599                 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
600                     current user', VALUE_DEFAULT, 0)
601             )
602         );
603     }
605     /**
606      * Unblock contacts.
607      *
608      * @param array $userids array of user IDs.
609      * @param int $userid The id of the user we are unblocking the contacts for
610      * @return null
611      * @since Moodle 2.5
612      */
613     public static function unblock_contacts($userids, $userid = 0) {
614         global $CFG, $USER;
616         // Check if messaging is enabled.
617         if (empty($CFG->messaging)) {
618             throw new moodle_exception('disabled', 'message');
619         }
621         if (empty($userid)) {
622             $userid = $USER->id;
623         }
625         // Validate context.
626         $context = context_system::instance();
627         self::validate_context($context);
629         $params = array('userids' => $userids, 'userid' => $userid);
630         $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
632         $capability = 'moodle/site:manageallmessaging';
633         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
634             throw new required_capability_exception($context, $capability, 'nopermissions', '');
635         }
637         foreach ($params['userids'] as $id) {
638             message_unblock_contact($id, $params['userid']);
639         }
641         return null;
642     }
644     /**
645      * Unblock contacts return description.
646      *
647      * @deprecated since Moodle 3.6
648      * @return external_description
649      * @since Moodle 2.5
650      */
651     public static function unblock_contacts_returns() {
652         return null;
653     }
655     /**
656      * Marking the method as deprecated.
657      *
658      * @return bool
659      */
660     public static function unblock_contacts_is_deprecated() {
661         return true;
662     }
664     /**
665      * Returns contact requests parameters description.
666      *
667      * @return external_function_parameters
668      */
669     public static function get_contact_requests_parameters() {
670         return new external_function_parameters(
671             [
672                 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
673                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
674                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
675             ]
676         );
677     }
679     /**
680      * Handles returning the contact requests for a user.
681      *
682      * This also includes the user data necessary to display information
683      * about the user.
684      *
685      * It will not include blocked users.
686      *
687      * @param int $userid The id of the user we want to get the contact requests for
688      * @param int $limitfrom
689      * @param int $limitnum
690      */
691     public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
692         global $CFG, $USER;
694         // Check if messaging is enabled.
695         if (empty($CFG->messaging)) {
696             throw new moodle_exception('disabled', 'message');
697         }
699         // Validate context.
700         $context = context_system::instance();
701         self::validate_context($context);
703         $params = [
704             'userid' => $userid,
705             'limitfrom' => $limitfrom,
706             'limitnum' => $limitnum
707         ];
708         $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
710         $capability = 'moodle/site:manageallmessaging';
711         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
712             throw new required_capability_exception($context, $capability, 'nopermissions', '');
713         }
715         return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
716     }
718     /**
719      * Returns the contact requests return description.
720      *
721      * @return external_description
722      */
723     public static function get_contact_requests_returns() {
724         return new external_multiple_structure(
725             self::get_conversation_member_structure()
726         );
727     }
729     /**
730      * Returns get conversation members parameters description.
731      *
732      * @return external_function_parameters
733      */
734     public static function get_conversation_members_parameters() {
735         return new external_function_parameters(
736             [
737                 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
738                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
739                 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
740                     VALUE_DEFAULT, false),
741                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
742                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
743             ]
744         );
745     }
747     /**
748      * Returns a list of conversation members.
749      *
750      * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
751      * @param int $conversationid The id of the conversation
752      * @param bool $includecontactrequests Do we want to include contact requests with this data?
753      * @param int $limitfrom
754      * @param int $limitnum
755      * @return array
756      */
757     public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
758                                                     int $limitfrom = 0, int $limitnum = 0) {
759         global $CFG, $USER;
761         // Check if messaging is enabled.
762         if (empty($CFG->messaging)) {
763             throw new moodle_exception('disabled', 'message');
764         }
766         // Validate context.
767         $context = context_system::instance();
768         self::validate_context($context);
770         $params = [
771             'userid' => $userid,
772             'conversationid' => $conversationid,
773             'includecontactrequests' => $includecontactrequests,
774             'limitfrom' => $limitfrom,
775             'limitnum' => $limitnum
776         ];
777         $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
779         $capability = 'moodle/site:manageallmessaging';
780         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
781             throw new required_capability_exception($context, $capability, 'nopermissions', '');
782         }
784         // The user needs to be a part of the conversation before querying who the members are.
785         if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
786             throw new moodle_exception('You are not a member of this conversation.');
787         }
790         return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
791             $params['limitfrom'], $params['limitnum']);
792     }
794     /**
795      * Returns the get conversation members return description.
796      *
797      * @return external_description
798      */
799     public static function get_conversation_members_returns() {
800         return new external_multiple_structure(
801             self::get_conversation_member_structure(true)
802         );
803     }
805     /**
806      * Creates a contact request parameters description.
807      *
808      * @return external_function_parameters
809      */
810     public static function create_contact_request_parameters() {
811         return new external_function_parameters(
812             [
813                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
814                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
815             ]
816         );
817     }
819     /**
820      * Creates a contact request.
821      *
822      * @param int $userid The id of the user who is creating the contact request
823      * @param int $requesteduserid The id of the user being requested
824      */
825     public static function create_contact_request(int $userid, int $requesteduserid) {
826         global $CFG, $USER;
828         // Check if messaging is enabled.
829         if (empty($CFG->messaging)) {
830             throw new moodle_exception('disabled', 'message');
831         }
833         // Validate context.
834         $context = context_system::instance();
835         self::validate_context($context);
837         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
838         $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
840         $capability = 'moodle/site:manageallmessaging';
841         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
842             throw new required_capability_exception($context, $capability, 'nopermissions', '');
843         }
845         $result = [
846             'warnings' => []
847         ];
849         if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
850             $result['warnings'][] = [
851                 'item' => 'user',
852                 'itemid' => $params['requesteduserid'],
853                 'warningcode' => 'cannotcreatecontactrequest',
854                 'message' => 'You are unable to create a contact request for this user'
855             ];
856         } else {
857             if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
858                 // There should only ever be one but just in case there are multiple then we can return the first.
859                 $result['request'] = array_shift($requests);
860             } else {
861                 $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
862             }
863         }
865         return $result;
866     }
868     /**
869      * Creates a contact request return description.
870      *
871      * @return external_description
872      */
873     public static function create_contact_request_returns() {
874         return new external_single_structure(
875             array(
876                 'request' => new external_single_structure(
877                     array(
878                         'id' => new external_value(PARAM_INT, 'Message id'),
879                         'userid' => new external_value(PARAM_INT, 'User from id'),
880                         'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
881                         'timecreated' => new external_value(PARAM_INT, 'Time created'),
882                     ),
883                     'request record',
884                     VALUE_OPTIONAL
885                 ),
886                 'warnings' => new external_warnings()
887             )
888         );
889     }
891     /**
892      * Confirm a contact request parameters description.
893      *
894      * @return external_function_parameters
895      */
896     public static function confirm_contact_request_parameters() {
897         return new external_function_parameters(
898             [
899                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
900                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
901             ]
902         );
903     }
905     /**
906      * Confirm a contact request.
907      *
908      * @param int $userid The id of the user who is creating the contact request
909      * @param int $requesteduserid The id of the user being requested
910      */
911     public static function confirm_contact_request(int $userid, int $requesteduserid) {
912         global $CFG, $USER;
914         // Check if messaging is enabled.
915         if (empty($CFG->messaging)) {
916             throw new moodle_exception('disabled', 'message');
917         }
919         // Validate context.
920         $context = context_system::instance();
921         self::validate_context($context);
923         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
924         $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
926         $capability = 'moodle/site:manageallmessaging';
927         if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
928             throw new required_capability_exception($context, $capability, 'nopermissions', '');
929         }
931         \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
933         return [];
934     }
936     /**
937      * Confirm a contact request return description.
938      *
939      * @return external_description
940      */
941     public static function confirm_contact_request_returns() {
942         return new external_warnings();
943     }
945     /**
946      * Declines a contact request parameters description.
947      *
948      * @return external_function_parameters
949      */
950     public static function decline_contact_request_parameters() {
951         return new external_function_parameters(
952             [
953                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
954                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
955             ]
956         );
957     }
959     /**
960      * Declines a contact request.
961      *
962      * @param int $userid The id of the user who is creating the contact request
963      * @param int $requesteduserid The id of the user being requested
964      */
965     public static function decline_contact_request(int $userid, int $requesteduserid) {
966         global $CFG, $USER;
968         // Check if messaging is enabled.
969         if (empty($CFG->messaging)) {
970             throw new moodle_exception('disabled', 'message');
971         }
973         // Validate context.
974         $context = context_system::instance();
975         self::validate_context($context);
977         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
978         $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
980         $capability = 'moodle/site:manageallmessaging';
981         if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
982             throw new required_capability_exception($context, $capability, 'nopermissions', '');
983         }
985         \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
987         return [];
988     }
990     /**
991      * Declines a contact request return description.
992      *
993      * @return external_description
994      */
995     public static function decline_contact_request_returns() {
996         return new external_warnings();
997     }
999     /**
1000      * Return the structure of a message area contact.
1001      *
1002      * @return external_single_structure
1003      * @since Moodle 3.2
1004      */
1005     private static function get_messagearea_contact_structure() {
1006         return new external_single_structure(
1007             array(
1008                 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
1009                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1010                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1011                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1012                 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
1013                 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
1014                 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
1015                 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
1016                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1017                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1018                 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
1019                 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1020                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1021                     VALUE_DEFAULT, null),
1022             )
1023         );
1024     }
1026     /**
1027      * Return the structure of a conversation.
1028      *
1029      * @return external_single_structure
1030      * @since Moodle 3.6
1031      */
1033     private static function get_conversation_structure() {
1034         return new external_single_structure(
1035             array(
1036                 'id' => new external_value(PARAM_INT, 'The conversation id'),
1037                 'name' => new external_value(PARAM_NOTAGS, 'The conversation name, if set', VALUE_DEFAULT, null),
1038                 'subname' => new external_value(PARAM_NOTAGS, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1039                 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1040                 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group)'),
1041                 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1042                 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked conversation this conversation as a favourite'),
1043                 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1044                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1045                     VALUE_DEFAULT, null),
1046                 'members' => new external_multiple_structure(
1047                     self::get_conversation_member_structure(true)
1048                 ),
1049                 'messages' => new external_multiple_structure(
1050                     self::get_conversation_message_structure()
1051                 ),
1052             )
1053         );
1054     }
1056     /**
1057      * Return the structure of a conversation member.
1058      *
1059      * @param bool $includecontactrequests Are we including contact requests?
1060      * @param bool $includeconversations Are we including conversations?
1061      * @return external_single_structure
1062      * @since Moodle 3.6
1063      */
1064     private static function get_conversation_member_structure(bool $includecontactrequests = false,
1065                                                               bool $includeconversations = false) {
1066         $result = [
1067             'id' => new external_value(PARAM_INT, 'The user id'),
1068             'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1069             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1070             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1071             'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1072             'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1073             'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1074             'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1075             'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1076             'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1077             'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1078         ];
1080         if ($includecontactrequests) {
1081             $result['contactrequests'] = new external_multiple_structure(
1082                 new external_single_structure(
1083                     [
1084                         'id' => new external_value(PARAM_INT, 'The id of the message'),
1085                         'userid' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1086                         'requesteduserid' => new external_value(PARAM_RAW, 'The text of the message'),
1087                         'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1088                     ]
1089                 ), 'The contact requests', VALUE_OPTIONAL
1090             );
1091         }
1093         if ($includeconversations) {
1094             $result['conversations'] = new external_multiple_structure(new external_single_structure(
1095                 array(
1096                     'id' => new external_value(PARAM_INT, 'Conversations id'),
1097                     'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1098                     'name' => new external_value(PARAM_TEXT, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1099                     'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1100                 ), 'information about conversation', VALUE_OPTIONAL),
1101                 'Conversations between users', VALUE_OPTIONAL
1102             );
1103         }
1105         return new external_single_structure(
1106             $result
1107         );
1108     }
1110     /**
1111      * Return the structure of a message area message.
1112      *
1113      * @return external_single_structure
1114      * @since Moodle 3.6
1115      */
1116     private static function get_conversation_message_structure() {
1117         return new external_single_structure(
1118             array(
1119                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1120                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1121                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1122                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1123             )
1124         );
1125     }
1127     /**
1128      * Return the structure of a message area message.
1129      *
1130      * @return external_single_structure
1131      * @since Moodle 3.2
1132      */
1133     private static function get_messagearea_message_structure() {
1134         return new external_single_structure(
1135             array(
1136                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1137                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1138                 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1139                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1140                 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1141                 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1142                 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1143                 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1144                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1145                 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1146             )
1147         );
1148     }
1150     /**
1151      * Get messagearea search users in course parameters.
1152      *
1153      * @deprecated since 3.6
1154      *
1155      * @return external_function_parameters
1156      * @since 3.2
1157      */
1158     public static function data_for_messagearea_search_users_in_course_parameters() {
1159         return new external_function_parameters(
1160             array(
1161                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1162                 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1163                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1164                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1165                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1166             )
1167         );
1168     }
1170     /**
1171      * Get messagearea search users in course results.
1172      *
1173      * @deprecated since 3.6
1174      *
1175      * NOTE: We are deprecating this function but not search_users_in_course API function for backwards compatibility
1176      * with messaging UI. But should be removed once new group messaging UI is in place and old messaging UI is removed.
1177      * Followup: MDL-63915
1178      *
1179      * @param int $userid The id of the user who is performing the search
1180      * @param int $courseid The id of the course
1181      * @param string $search The string being searched
1182      * @param int $limitfrom
1183      * @param int $limitnum
1184      * @return stdClass
1185      * @throws moodle_exception
1186      * @since 3.2
1187      */
1188     public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1189                                                                        $limitnum = 0) {
1190         global $CFG, $PAGE, $USER;
1192         // Check if messaging is enabled.
1193         if (empty($CFG->messaging)) {
1194             throw new moodle_exception('disabled', 'message');
1195         }
1197         $systemcontext = context_system::instance();
1199         $params = array(
1200             'userid' => $userid,
1201             'courseid' => $courseid,
1202             'search' => $search,
1203             'limitfrom' => $limitfrom,
1204             'limitnum' => $limitnum
1205         );
1206         $params = self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1207         self::validate_context($systemcontext);
1209         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1210             throw new moodle_exception('You do not have permission to perform this action.');
1211         }
1213         $users = \core_message\api::search_users_in_course(
1214             $params['userid'],
1215             $params['courseid'],
1216             $params['search'],
1217             $params['limitfrom'],
1218             $params['limitnum']
1219         );
1220         $results = new \core_message\output\messagearea\user_search_results($users);
1222         $renderer = $PAGE->get_renderer('core_message');
1223         return $results->export_for_template($renderer);
1224     }
1226     /**
1227      * Get messagearea search users in course returns.
1228      *
1229      * @deprecated since 3.6
1230      *
1231      * @return external_single_structure
1232      * @since 3.2
1233      */
1234     public static function data_for_messagearea_search_users_in_course_returns() {
1235         return new external_single_structure(
1236             array(
1237                 'contacts' => new external_multiple_structure(
1238                     self::get_messagearea_contact_structure()
1239                 ),
1240             )
1241         );
1242     }
1244     /**
1245      * Marking the method as deprecated.
1246      *
1247      * @return bool
1248      */
1249     public static function data_for_messagearea_search_users_in_course_is_deprecated() {
1250         return true;
1251     }
1253     /**
1254      * Get messagearea search users parameters.
1255      *
1256      * @deprecated since 3.6
1257      *
1258      * @return external_function_parameters
1259      * @since 3.2
1260      */
1261     public static function data_for_messagearea_search_users_parameters() {
1262         return new external_function_parameters(
1263             array(
1264                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1265                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1266                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1267             )
1268         );
1269     }
1271     /**
1272      * Get messagearea search users results.
1273      *
1274      * @deprecated since 3.6
1275      *
1276      * NOTE: We are deprecating this function but not search_users API function for backwards compatibility
1277      * with messaging UI. But should be removed once new group messaging UI is in place and old messaging UI is removed.
1278      * Followup: MDL-63915
1279      *
1280      * @param int $userid The id of the user who is performing the search
1281      * @param string $search The string being searched
1282      * @param int $limitnum
1283      * @return stdClass
1284      * @throws moodle_exception
1285      * @since 3.2
1286      */
1287     public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1288         global $CFG, $PAGE, $USER;
1290         // Check if messaging is enabled.
1291         if (empty($CFG->messaging)) {
1292             throw new moodle_exception('disabled', 'message');
1293         }
1295         $systemcontext = context_system::instance();
1297         $params = array(
1298             'userid' => $userid,
1299             'search' => $search,
1300             'limitnum' => $limitnum
1301         );
1302         $params = self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1303         self::validate_context($systemcontext);
1305         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1306             throw new moodle_exception('You do not have permission to perform this action.');
1307         }
1309         list($contacts, $courses, $noncontacts) = \core_message\api::search_users(
1310             $params['userid'],
1311             $params['search'],
1312             $params['limitnum']
1313         );
1315         $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1317         $renderer = $PAGE->get_renderer('core_message');
1318         return $search->export_for_template($renderer);
1319     }
1321     /**
1322      * Get messagearea search users returns.
1323      *
1324      * @deprecated since 3.6
1325      *
1326      * @return external_single_structure
1327      * @since 3.2
1328      */
1329     public static function data_for_messagearea_search_users_returns() {
1330         return new external_single_structure(
1331             array(
1332                 'contacts' => new external_multiple_structure(
1333                     self::get_messagearea_contact_structure()
1334                 ),
1335                 'courses' => new external_multiple_structure(
1336                     new external_single_structure(
1337                         array(
1338                             'id' => new external_value(PARAM_INT, 'The course id'),
1339                             'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1340                             'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1341                         )
1342                     )
1343                 ),
1344                 'noncontacts' => new external_multiple_structure(
1345                     self::get_messagearea_contact_structure()
1346                 )
1347             )
1348         );
1349     }
1351     /**
1352      * Marking the method as deprecated.
1353      *
1354      * @return bool
1355      */
1356     public static function data_for_messagearea_search_users_is_deprecated() {
1357         return true;
1358     }
1360     /**
1361      * Get messagearea message search users parameters.
1362      *
1363      * @return external_function_parameters
1364      * @since 3.6
1365      */
1366     public static function message_search_users_parameters() {
1367         return new external_function_parameters(
1368             array(
1369                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1370                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1371                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1372                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1373             )
1374         );
1375     }
1377     /**
1378      * Get search users results.
1379      *
1380      * @param int $userid The id of the user who is performing the search
1381      * @param string $search The string being searched
1382      * @param int $limitfrom
1383      * @param int $limitnum
1384      * @return array
1385      * @throws moodle_exception
1386      * @since 3.6
1387      */
1388     public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1389         global $USER;
1391         $systemcontext = context_system::instance();
1393         $params = array(
1394             'userid' => $userid,
1395             'search' => $search,
1396             'limitfrom' => $limitfrom,
1397             'limitnum' => $limitnum
1398         );
1399         $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1400         self::validate_context($systemcontext);
1402         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1403             throw new moodle_exception('You do not have permission to perform this action.');
1404         }
1406         list($contacts, $noncontacts) = \core_message\api::message_search_users(
1407             $params['userid'],
1408             $params['search'],
1409             $params['limitfrom'],
1410             $params['limitnum']);
1412         return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1413     }
1415     /**
1416      * Get messagearea message search users returns.
1417      *
1418      * @return external_single_structure
1419      * @since 3.2
1420      */
1421     public static function message_search_users_returns() {
1422         return new external_single_structure(
1423             array(
1424                 'contacts' => new external_multiple_structure(
1425                     self::get_conversation_member_structure(false, true)
1426                 ),
1427                 'noncontacts' => new external_multiple_structure(
1428                     self::get_conversation_member_structure(false, true)
1429                 )
1430             )
1431         );
1432     }
1434     /**
1435      * Get messagearea search messages parameters.
1436      *
1437      * @return external_function_parameters
1438      * @since 3.2
1439      */
1440     public static function data_for_messagearea_search_messages_parameters() {
1441         return new external_function_parameters(
1442             array(
1443                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1444                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1445                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1446                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1447             )
1448         );
1449     }
1451     /**
1452      * Get messagearea search messages results.
1453      *
1454      * @param int $userid The id of the user who is performing the search
1455      * @param string $search The string being searched
1456      * @param int $limitfrom
1457      * @param int $limitnum
1458      * @return stdClass
1459      * @throws moodle_exception
1460      * @since 3.2
1461      */
1462     public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1463         global $CFG, $PAGE, $USER;
1465         // Check if messaging is enabled.
1466         if (empty($CFG->messaging)) {
1467             throw new moodle_exception('disabled', 'message');
1468         }
1470         $systemcontext = context_system::instance();
1472         $params = array(
1473             'userid' => $userid,
1474             'search' => $search,
1475             'limitfrom' => $limitfrom,
1476             'limitnum' => $limitnum
1478         );
1479         $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1480         self::validate_context($systemcontext);
1482         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1483             throw new moodle_exception('You do not have permission to perform this action.');
1484         }
1486         $messages = \core_message\api::search_messages(
1487             $params['userid'],
1488             $params['search'],
1489             $params['limitfrom'],
1490             $params['limitnum']
1491         );
1492         $results = new \core_message\output\messagearea\message_search_results($messages);
1494         $renderer = $PAGE->get_renderer('core_message');
1495         return $results->export_for_template($renderer);
1496     }
1498     /**
1499      * Get messagearea search messages returns.
1500      *
1501      * @return external_single_structure
1502      * @since 3.2
1503      */
1504     public static function data_for_messagearea_search_messages_returns() {
1505         return new external_single_structure(
1506             array(
1507                 'contacts' => new external_multiple_structure(
1508                     self::get_messagearea_contact_structure()
1509                 )
1510             )
1511         );
1512     }
1514     /**
1515      * Get conversations parameters.
1516      *
1517      * @return external_function_parameters
1518      * @since 3.6
1519      */
1520     public static function get_conversations_parameters() {
1521         return new external_function_parameters(
1522             array(
1523                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1524                 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1525                 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1526                 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1527                 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1528                 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1529                     VALUE_DEFAULT, null),
1531             )
1532         );
1533     }
1535     /**
1536      * Get the list of conversations for the user.
1537      *
1538      * @param int $userid The id of the user who is performing the search
1539      * @param int $limitfrom
1540      * @param int $limitnum
1541      * @param int|null $type
1542      * @param bool|null $favourites
1543      * @return stdClass
1544      * @throws \moodle_exception if the messaging feature is disabled on the site.
1545      * @since 3.2
1546      */
1547     public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null) {
1548         global $CFG, $USER;
1550         // All the standard BL checks.
1551         if (empty($CFG->messaging)) {
1552             throw new moodle_exception('disabled', 'message');
1553         }
1555         $params = array(
1556             'userid' => $userid,
1557             'limitfrom' => $limitfrom,
1558             'limitnum' => $limitnum,
1559             'type' => $type,
1560             'favourites' => $favourites
1561         );
1562         $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1564         $systemcontext = context_system::instance();
1565         self::validate_context($systemcontext);
1567         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1568             throw new moodle_exception('You do not have permission to perform this action.');
1569         }
1571         $conversations = \core_message\api::get_conversations(
1572             $params['userid'],
1573             $params['limitfrom'],
1574             $params['limitnum'],
1575             $params['type'],
1576             $params['favourites']
1577         );
1579         return (object) ['conversations' => $conversations];
1580     }
1582     /**
1583      * Get conversations returns.
1584      *
1585      * @return external_single_structure
1586      * @since 3.6
1587      */
1588     public static function get_conversations_returns() {
1589         return new external_single_structure(
1590             [
1591                 'conversations' => new external_multiple_structure(
1592                     self::get_conversation_structure()
1593                 )
1594             ]
1595         );
1596     }
1598     /**
1599      * The messagearea conversations parameters.
1600      *
1601      * @deprecated since 3.6
1602      * @return external_function_parameters
1603      * @since 3.2
1604      */
1605     public static function data_for_messagearea_conversations_parameters() {
1606         return new external_function_parameters(
1607             array(
1608                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1609                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1610                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1611             )
1612         );
1613     }
1615     /**
1616      * Get messagearea conversations.
1617      *
1618      * NOTE FOR FINAL DEPRECATION:
1619      * When removing this method, please also consider removal of get_conversations_legacy_formatter()
1620      * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
1621      * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
1622      * removed.
1623      *
1624      * @deprecated since 3.6
1625      * @param int $userid The id of the user who we are viewing conversations for
1626      * @param int $limitfrom
1627      * @param int $limitnum
1628      * @return stdClass
1629      * @throws moodle_exception
1630      * @since 3.2
1631      */
1632     public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1633         global $CFG, $PAGE, $USER;
1635         // Check if messaging is enabled.
1636         if (empty($CFG->messaging)) {
1637             throw new moodle_exception('disabled', 'message');
1638         }
1640         $systemcontext = context_system::instance();
1642         $params = array(
1643             'userid' => $userid,
1644             'limitfrom' => $limitfrom,
1645             'limitnum' => $limitnum
1646         );
1647         $params = self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1648         self::validate_context($systemcontext);
1650         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1651             throw new moodle_exception('You do not have permission to perform this action.');
1652         }
1654         $conversations = \core_message\api::get_conversations($params['userid'], $params['limitfrom'], $params['limitnum']);
1656         // Format the conversations in the legacy style, as the get_conversations method has since been changed.
1657         $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
1659         $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1661         $renderer = $PAGE->get_renderer('core_message');
1662         return $conversations->export_for_template($renderer);
1663     }
1665     /**
1666      * The messagearea conversations return structure.
1667      *
1668      * @deprecated since 3.6
1669      * @return external_single_structure
1670      * @since 3.2
1671      */
1672     public static function data_for_messagearea_conversations_returns() {
1673         return new external_single_structure(
1674             array(
1675                 'contacts' => new external_multiple_structure(
1676                     self::get_messagearea_contact_structure()
1677                 )
1678             )
1679         );
1680     }
1682     /**
1683      * Marking the method as deprecated.
1684      *
1685      * @return bool
1686      */
1687     public static function data_for_messagearea_conversations_is_deprecated() {
1688         return true;
1689     }
1691     /**
1692      * The messagearea contacts return parameters.
1693      *
1694      * @deprecated since 3.6
1695      * @return external_function_parameters
1696      * @since 3.2
1697      */
1698     public static function data_for_messagearea_contacts_parameters() {
1699         return self::data_for_messagearea_conversations_parameters();
1700     }
1702     /**
1703      * Get messagearea contacts parameters.
1704      *
1705      * @deprecated since 3.6
1706      * @param int $userid The id of the user who we are viewing conversations for
1707      * @param int $limitfrom
1708      * @param int $limitnum
1709      * @return stdClass
1710      * @throws moodle_exception
1711      * @since 3.2
1712      */
1713     public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1714         global $CFG, $PAGE, $USER;
1716         // Check if messaging is enabled.
1717         if (empty($CFG->messaging)) {
1718             throw new moodle_exception('disabled', 'message');
1719         }
1721         $systemcontext = context_system::instance();
1723         $params = array(
1724             'userid' => $userid,
1725             'limitfrom' => $limitfrom,
1726             'limitnum' => $limitnum
1727         );
1728         $params = self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1729         self::validate_context($systemcontext);
1731         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1732             throw new moodle_exception('You do not have permission to perform this action.');
1733         }
1735         $contacts = \core_message\api::get_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1736         $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1738         $renderer = $PAGE->get_renderer('core_message');
1739         return $contacts->export_for_template($renderer);
1740     }
1742     /**
1743      * The messagearea contacts return structure.
1744      *
1745      * @deprecated since 3.6
1746      * @return external_single_structure
1747      * @since 3.2
1748      */
1749     public static function data_for_messagearea_contacts_returns() {
1750         return self::data_for_messagearea_conversations_returns();
1751     }
1753     /**
1754      * Marking the method as deprecated.
1755      *
1756      * @return bool
1757      */
1758     public static function data_for_messagearea_contacts_is_deprecated() {
1759         return true;
1760     }
1762     /**
1763      * The messagearea messages parameters.
1764      *
1765      * @deprecated since 3.6
1766      * @return external_function_parameters
1767      * @since 3.2
1768      */
1769     public static function data_for_messagearea_messages_parameters() {
1770         return new external_function_parameters(
1771             array(
1772                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1773                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1774                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1775                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1776                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1777                 'timefrom' => new external_value(PARAM_INT,
1778                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1779             )
1780         );
1781     }
1783     /**
1784      * Get messagearea messages.
1785      *
1786      * @deprecated since 3.6
1787      * @param int $currentuserid The current user's id
1788      * @param int $otheruserid The other user's id
1789      * @param int $limitfrom
1790      * @param int $limitnum
1791      * @param boolean $newest
1792      * @return stdClass
1793      * @throws moodle_exception
1794      * @since 3.2
1795      */
1796     public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1797                                                          $newest = false, $timefrom = 0) {
1798         global $CFG, $PAGE, $USER;
1800         // Check if messaging is enabled.
1801         if (empty($CFG->messaging)) {
1802             throw new moodle_exception('disabled', 'message');
1803         }
1805         $systemcontext = context_system::instance();
1807         $params = array(
1808             'currentuserid' => $currentuserid,
1809             'otheruserid' => $otheruserid,
1810             'limitfrom' => $limitfrom,
1811             'limitnum' => $limitnum,
1812             'newest' => $newest,
1813             'timefrom' => $timefrom,
1814         );
1815         $params = self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1816         self::validate_context($systemcontext);
1818         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1819             throw new moodle_exception('You do not have permission to perform this action.');
1820         }
1822         if ($params['newest']) {
1823             $sort = 'timecreated DESC';
1824         } else {
1825             $sort = 'timecreated ASC';
1826         }
1828         // We need to enforce a one second delay on messages to avoid race conditions of current
1829         // messages still being sent.
1830         //
1831         // There is a chance that we could request messages before the current time's
1832         // second has elapsed and while other messages are being sent in that same second. In which
1833         // case those messages will be lost.
1834         //
1835         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1836         if (!empty($params['timefrom'])) {
1837             $timeto = time() - 1;
1838         } else {
1839             $timeto = 0;
1840         }
1842         // No requesting messages from the current time, as stated above.
1843         if ($params['timefrom'] == time()) {
1844             $messages = [];
1845         } else {
1846             $messages = \core_message\api::get_messages($params['currentuserid'], $params['otheruserid'], $params['limitfrom'],
1847                                                         $params['limitnum'], $sort, $params['timefrom'], $timeto);
1848         }
1850         $messages = new \core_message\output\messagearea\messages($params['currentuserid'], $params['otheruserid'], $messages);
1852         $renderer = $PAGE->get_renderer('core_message');
1853         return $messages->export_for_template($renderer);
1854     }
1856     /**
1857      * The messagearea messages return structure.
1858      *
1859      * @deprecated since 3.6
1860      * @return external_single_structure
1861      * @since 3.2
1862      */
1863     public static function data_for_messagearea_messages_returns() {
1864         return new external_single_structure(
1865             array(
1866                 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1867                     the messages on behalf of?'),
1868                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1869                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1870                 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1871                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1872                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1873                 'messages' => new external_multiple_structure(
1874                     self::get_messagearea_message_structure()
1875                 ),
1876                 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1877             )
1878         );
1879     }
1881     /**
1882      * Marking the method as deprecated.
1883      *
1884      * @return bool
1885      */
1886     public static function data_for_messagearea_messages_is_deprecated() {
1887         return true;
1888     }
1890     /**
1891      * The conversation messages parameters.
1892      *
1893      * @return external_function_parameters
1894      * @since 3.6
1895      */
1896     public static function get_conversation_messages_parameters() {
1897         return new external_function_parameters(
1898             array(
1899                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1900                 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1901                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1902                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1903                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1904                 'timefrom' => new external_value(PARAM_INT,
1905                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1906             )
1907         );
1908     }
1910     /**
1911      * Get conversation messages.
1912      *
1913      * @param  int $currentuserid The current user's id.
1914      * @param  int $convid The conversation id.
1915      * @param  int $limitfrom Return a subset of records, starting at this point (optional).
1916      * @param  int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1917      * @param  bool $newest True for getting first newest messages, false otherwise.
1918      * @param  int  $timefrom The time from the conversation messages to get.
1919      * @return stdClass The messages and members who have sent some of these messages.
1920      * @throws moodle_exception
1921      * @since 3.6
1922      */
1923     public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1924                                                          bool $newest = false, int $timefrom = 0) {
1925         global $CFG, $PAGE, $USER;
1927         // Check if messaging is enabled.
1928         if (empty($CFG->messaging)) {
1929             throw new moodle_exception('disabled', 'message');
1930         }
1932         $systemcontext = context_system::instance();
1934         $params = array(
1935             'currentuserid' => $currentuserid,
1936             'convid' => $convid,
1937             'limitfrom' => $limitfrom,
1938             'limitnum' => $limitnum,
1939             'newest' => $newest,
1940             'timefrom' => $timefrom,
1941         );
1942         $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1943         self::validate_context($systemcontext);
1945         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1946             throw new moodle_exception('You do not have permission to perform this action.');
1947         }
1949         $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1951         // We need to enforce a one second delay on messages to avoid race conditions of current
1952         // messages still being sent.
1953         //
1954         // There is a chance that we could request messages before the current time's
1955         // second has elapsed and while other messages are being sent in that same second. In which
1956         // case those messages will be lost.
1957         //
1958         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1959         $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1961         // No requesting messages from the current time, as stated above.
1962         if ($params['timefrom'] == time()) {
1963             $messages = [];
1964         } else {
1965             $messages = \core_message\api::get_conversation_messages(
1966                 $params['currentuserid'],
1967                 $params['convid'],
1968                 $params['limitfrom'],
1969                 $params['limitnum'],
1970                 $sort,
1971                 $params['timefrom'],
1972                 $timeto);
1973         }
1975         return $messages;
1976     }
1978     /**
1979      * The messagearea messages return structure.
1980      *
1981      * @return external_single_structure
1982      * @since 3.6
1983      */
1984     public static function get_conversation_messages_returns() {
1985         return new external_single_structure(
1986             array(
1987                 'id' => new external_value(PARAM_INT, 'The conversation id'),
1988                 'members' => new external_multiple_structure(
1989                     self::get_conversation_member_structure()
1990                 ),
1991                 'messages' => new external_multiple_structure(
1992                     self::get_conversation_message_structure()
1993                 ),
1994             )
1995         );
1996     }
1998     /**
1999      * The get most recent message return parameters.
2000      *
2001      * @deprecated since 3.6
2002      * @return external_function_parameters
2003      * @since 3.2
2004      */
2005     public static function data_for_messagearea_get_most_recent_message_parameters() {
2006         return new external_function_parameters(
2007             array(
2008                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2009                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2010             )
2011         );
2012     }
2014     /**
2015      * Get the most recent message in a conversation.
2016      *
2017      * @deprecated since 3.6
2018      * @param int $currentuserid The current user's id
2019      * @param int $otheruserid The other user's id
2020      * @return stdClass
2021      * @throws moodle_exception
2022      * @since 3.2
2023      */
2024     public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
2025         global $CFG, $PAGE, $USER;
2027         // Check if messaging is enabled.
2028         if (empty($CFG->messaging)) {
2029             throw new moodle_exception('disabled', 'message');
2030         }
2032         $systemcontext = context_system::instance();
2034         $params = array(
2035             'currentuserid' => $currentuserid,
2036             'otheruserid' => $otheruserid
2037         );
2038         $params = self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
2039         self::validate_context($systemcontext);
2041         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2042             throw new moodle_exception('You do not have permission to perform this action.');
2043         }
2045         $message = \core_message\api::get_most_recent_message($params['currentuserid'], $params['otheruserid']);
2046         $message = new \core_message\output\messagearea\message($message);
2048         $renderer = $PAGE->get_renderer('core_message');
2049         return $message->export_for_template($renderer);
2050     }
2052     /**
2053      * The get most recent message return structure.
2054      *
2055      * @deprecated since 3.6
2056      * @return external_single_structure
2057      * @since 3.2
2058      */
2059     public static function data_for_messagearea_get_most_recent_message_returns() {
2060         return self::get_messagearea_message_structure();
2061     }
2063     /**
2064      * Marking the method as deprecated.
2065      *
2066      * @return bool
2067      */
2068     public static function data_for_messagearea_get_most_recent_message_is_deprecated() {
2069         return true;
2070     }
2072     /**
2073      * The get profile parameters.
2074      *
2075      * @deprecated since 3.6
2076      * @return external_function_parameters
2077      * @since 3.2
2078      */
2079     public static function data_for_messagearea_get_profile_parameters() {
2080         return new external_function_parameters(
2081             array(
2082                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2083                 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
2084             )
2085         );
2086     }
2088     /**
2089      * Get the profile information for a contact.
2090      *
2091      * @deprecated since 3.6
2092      * @param int $currentuserid The current user's id
2093      * @param int $otheruserid The id of the user whose profile we are viewing
2094      * @return stdClass
2095      * @throws moodle_exception
2096      * @since 3.2
2097      */
2098     public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
2099         global $CFG, $PAGE, $USER;
2101         // Check if messaging is enabled.
2102         if (empty($CFG->messaging)) {
2103             throw new moodle_exception('disabled', 'message');
2104         }
2106         $systemcontext = context_system::instance();
2108         $params = array(
2109             'currentuserid' => $currentuserid,
2110             'otheruserid' => $otheruserid
2111         );
2112         $params = self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
2113         self::validate_context($systemcontext);
2115         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2116             throw new moodle_exception('You do not have permission to perform this action.');
2117         }
2119         $profile = \core_message\api::get_profile($params['currentuserid'], $params['otheruserid']);
2120         $profile = new \core_message\output\messagearea\profile($profile);
2122         $renderer = $PAGE->get_renderer('core_message');
2123         return $profile->export_for_template($renderer);
2124     }
2126     /**
2127      * The get profile return structure.
2128      *
2129      * @deprecated since 3.6
2130      * @return external_single_structure
2131      * @since 3.2
2132      */
2133     public static function data_for_messagearea_get_profile_returns() {
2134         return new external_single_structure(
2135             array(
2136                 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
2137                 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
2138                 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
2139                 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
2140                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
2141                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
2142                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
2143                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2144                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2145                 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
2146                 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
2147             )
2148         );
2149     }
2151     /**
2152      * Marking the method as deprecated.
2153      *
2154      * @return bool
2155      */
2156     public static function data_for_messagearea_get_profile_is_deprecated() {
2157         return true;
2158     }
2160     /**
2161      * Get contacts parameters description.
2162      *
2163      * @return external_function_parameters
2164      * @since Moodle 2.5
2165      */
2166     public static function get_contacts_parameters() {
2167         return new external_function_parameters(array());
2168     }
2170     /**
2171      * Get contacts.
2172      *
2173      * @return external_description
2174      * @since Moodle 2.5
2175      */
2176     public static function get_contacts() {
2177         global $CFG, $PAGE, $USER;
2179         // Check if messaging is enabled.
2180         if (empty($CFG->messaging)) {
2181             throw new moodle_exception('disabled', 'message');
2182         }
2184         require_once($CFG->dirroot . '/user/lib.php');
2186         $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
2187         $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
2188         foreach ($contacts as $contact) {
2189             // Set the mode.
2190             $mode = 'offline';
2191             if (\core_message\helper::is_online($contact->lastaccess)) {
2192                 $mode = 'online';
2193             }
2195             $newcontact = array(
2196                 'id' => $contact->id,
2197                 'fullname' => fullname($contact),
2198                 'unread' => $contact->messagecount
2199             );
2201             $userpicture = new user_picture($contact);
2202             $userpicture->size = 1; // Size f1.
2203             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2204             $userpicture->size = 0; // Size f2.
2205             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2207             $allcontacts[$mode][$contact->id] = $newcontact;
2208         }
2210         $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
2211         foreach ($strangers as $contact) {
2212             $newcontact = array(
2213                 'id' => $contact->id,
2214                 'fullname' => fullname($contact),
2215                 'unread' => $contact->messagecount
2216             );
2218             $userpicture = new user_picture($contact);
2219             $userpicture->size = 1; // Size f1.
2220             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2221             $userpicture->size = 0; // Size f2.
2222             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2224             $allcontacts['strangers'][$contact->id] = $newcontact;
2225         }
2227         // Add noreply user and support user to the list, if they don't exist.
2228         $supportuser = core_user::get_support_user();
2229         if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
2230             $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
2231             if ($supportuser->messagecount > 0) {
2232                 $supportuser->fullname = fullname($supportuser);
2233                 $supportuser->unread = $supportuser->messagecount;
2234                 $allcontacts['strangers'][$supportuser->id] = $supportuser;
2235             }
2236         }
2238         $noreplyuser = core_user::get_noreply_user();
2239         if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
2240             $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
2241             if ($noreplyuser->messagecount > 0) {
2242                 $noreplyuser->fullname = fullname($noreplyuser);
2243                 $noreplyuser->unread = $noreplyuser->messagecount;
2244                 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
2245             }
2246         }
2248         return $allcontacts;
2249     }
2251     /**
2252      * Get contacts return description.
2253      *
2254      * @return external_description
2255      * @since Moodle 2.5
2256      */
2257     public static function get_contacts_returns() {
2258         return new external_single_structure(
2259             array(
2260                 'online' => new external_multiple_structure(
2261                     new external_single_structure(
2262                         array(
2263                             'id' => new external_value(PARAM_INT, 'User ID'),
2264                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2265                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2266                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2267                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2268                         )
2269                     ),
2270                     'List of online contacts'
2271                 ),
2272                 'offline' => new external_multiple_structure(
2273                     new external_single_structure(
2274                         array(
2275                             'id' => new external_value(PARAM_INT, 'User ID'),
2276                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2277                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2278                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2279                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2280                         )
2281                     ),
2282                     'List of offline contacts'
2283                 ),
2284                 'strangers' => new external_multiple_structure(
2285                     new external_single_structure(
2286                         array(
2287                             'id' => new external_value(PARAM_INT, 'User ID'),
2288                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2289                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2290                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2291                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2292                         )
2293                     ),
2294                     'List of users that are not in the user\'s contact list but have sent a message'
2295                 )
2296             )
2297         );
2298     }
2300     /**
2301      * Search contacts parameters description.
2302      *
2303      * @return external_function_parameters
2304      * @since Moodle 2.5
2305      */
2306     public static function search_contacts_parameters() {
2307         return new external_function_parameters(
2308             array(
2309                 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2310                 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2311                     VALUE_DEFAULT, false)
2312             )
2313         );
2314     }
2316     /**
2317      * Search contacts.
2318      *
2319      * @param string $searchtext query string.
2320      * @param bool $onlymycourses limit the search to the user's courses only.
2321      * @return external_description
2322      * @since Moodle 2.5
2323      */
2324     public static function search_contacts($searchtext, $onlymycourses = false) {
2325         global $CFG, $USER, $PAGE;
2326         require_once($CFG->dirroot . '/user/lib.php');
2328         // Check if messaging is enabled.
2329         if (empty($CFG->messaging)) {
2330             throw new moodle_exception('disabled', 'message');
2331         }
2333         require_once($CFG->libdir . '/enrollib.php');
2335         $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2336         $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2338         // Extra validation, we do not allow empty queries.
2339         if ($params['searchtext'] === '') {
2340             throw new moodle_exception('querystringcannotbeempty');
2341         }
2343         $courseids = array();
2344         if ($params['onlymycourses']) {
2345             $mycourses = enrol_get_my_courses(array('id'));
2346             foreach ($mycourses as $mycourse) {
2347                 $courseids[] = $mycourse->id;
2348             }
2349         } else {
2350             $courseids[] = SITEID;
2351         }
2353         // Retrieving the users matching the query.
2354         $users = message_search_users($courseids, $params['searchtext']);
2355         $results = array();
2356         foreach ($users as $user) {
2357             $results[$user->id] = $user;
2358         }
2360         // Reorganising information.
2361         foreach ($results as &$user) {
2362             $newuser = array(
2363                 'id' => $user->id,
2364                 'fullname' => fullname($user)
2365             );
2367             // Avoid undefined property notice as phone not specified.
2368             $user->phone1 = null;
2369             $user->phone2 = null;
2371             $userpicture = new user_picture($user);
2372             $userpicture->size = 1; // Size f1.
2373             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2374             $userpicture->size = 0; // Size f2.
2375             $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2377             $user = $newuser;
2378         }
2380         return $results;
2381     }
2383     /**
2384      * Search contacts return description.
2385      *
2386      * @return external_description
2387      * @since Moodle 2.5
2388      */
2389     public static function search_contacts_returns() {
2390         return new external_multiple_structure(
2391             new external_single_structure(
2392                 array(
2393                     'id' => new external_value(PARAM_INT, 'User ID'),
2394                     'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2395                     'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2396                     'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
2397                 )
2398             ),
2399             'List of contacts'
2400         );
2401     }
2403     /**
2404      * Get messages parameters description.
2405      *
2406      * @return external_function_parameters
2407      * @since 2.8
2408      */
2409     public static function get_messages_parameters() {
2410         return new external_function_parameters(
2411             array(
2412                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2413                 'useridfrom' => new external_value(
2414                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2415                     VALUE_DEFAULT, 0),
2416                 'type' => new external_value(
2417                     PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2418                     VALUE_DEFAULT, 'both'),
2419                 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2420                 'newestfirst' => new external_value(
2421                     PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2422                     VALUE_DEFAULT, true),
2423                 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2424                 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2425             )
2426         );
2427     }
2429     /**
2430      * Get messages function implementation.
2431      *
2432      * @since  2.8
2433      * @throws invalid_parameter_exception
2434      * @throws moodle_exception
2435      * @param  int      $useridto       the user id who received the message
2436      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2437      * @param  string   $type           type of message to return, expected values: notifications, conversations and both
2438      * @param  bool     $read           true for retreiving read messages, false for unread
2439      * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
2440      * @param  int      $limitfrom      limit from
2441      * @param  int      $limitnum       limit num
2442      * @return external_description
2443      */
2444     public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2445                                         $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2446         global $CFG, $USER;
2448         $warnings = array();
2450         $params = array(
2451             'useridto' => $useridto,
2452             'useridfrom' => $useridfrom,
2453             'type' => $type,
2454             'read' => $read,
2455             'newestfirst' => $newestfirst,
2456             'limitfrom' => $limitfrom,
2457             'limitnum' => $limitnum
2458         );
2460         $params = self::validate_parameters(self::get_messages_parameters(), $params);
2462         $context = context_system::instance();
2463         self::validate_context($context);
2465         $useridto = $params['useridto'];
2466         $useridfrom = $params['useridfrom'];
2467         $type = $params['type'];
2468         $read = $params['read'];
2469         $newestfirst = $params['newestfirst'];
2470         $limitfrom = $params['limitfrom'];
2471         $limitnum = $params['limitnum'];
2473         $allowedvalues = array('notifications', 'conversations', 'both');
2474         if (!in_array($type, $allowedvalues)) {
2475             throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2476                 'allowed values are: ' . implode(',', $allowedvalues));
2477         }
2479         // Check if private messaging between users is allowed.
2480         if (empty($CFG->messaging)) {
2481             // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2482             if ($type == "conversations") {
2483                 throw new moodle_exception('disabled', 'message');
2484             }
2485             if ($type == "both") {
2486                 $warning = array();
2487                 $warning['item'] = 'message';
2488                 $warning['itemid'] = $USER->id;
2489                 $warning['warningcode'] = '1';
2490                 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2491                     Only notifications will be returned';
2492                 $warnings[] = $warning;
2493             }
2494         }
2496         if (!empty($useridto)) {
2497             if (core_user::is_real_user($useridto)) {
2498                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2499             } else {
2500                 throw new moodle_exception('invaliduser');
2501             }
2502         }
2504         if (!empty($useridfrom)) {
2505             // We use get_user here because the from user can be the noreply or support user.
2506             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2507         }
2509         // Check if the current user is the sender/receiver or just a privileged user.
2510         if ($useridto != $USER->id and $useridfrom != $USER->id and
2511              !has_capability('moodle/site:readallmessages', $context)) {
2512             throw new moodle_exception('accessdenied', 'admin');
2513         }
2515         // Which type of messages to retrieve.
2516         $notifications = -1;
2517         if ($type != 'both') {
2518             $notifications = ($type == 'notifications') ? 1 : 0;
2519         }
2521         $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2522         $sort = "mr.timecreated $orderdirection";
2524         if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2525             $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2527             // In some cases, we don't need to get the to/from user objects from the sql query.
2528             $userfromfullname = '';
2529             $usertofullname = '';
2531             // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2532             if (!empty($useridto)) {
2533                 $usertofullname = fullname($userto, $canviewfullname);
2534                 // The user from may or may not be filled.
2535                 if (!empty($useridfrom)) {
2536                     $userfromfullname = fullname($userfrom, $canviewfullname);
2537                 }
2538             } else {
2539                 // If the useridto field is empty, the useridfrom must be filled.
2540                 $userfromfullname = fullname($userfrom, $canviewfullname);
2541             }
2542             foreach ($messages as $mid => $message) {
2544                 // Do not return deleted messages.
2545                 if (!$message->notification) {
2546                     if (($useridto == $USER->id and $message->timeusertodeleted) or
2547                         ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2548                         unset($messages[$mid]);
2549                         continue;
2550                     }
2551                 }
2553                 // We need to get the user from the query.
2554                 if (empty($userfromfullname)) {
2555                     // Check for non-reply and support users.
2556                     if (core_user::is_real_user($message->useridfrom)) {
2557                         $user = new stdClass();
2558                         $user = username_load_fields_from_object($user, $message, 'userfrom');
2559                         $message->userfromfullname = fullname($user, $canviewfullname);
2560                     } else {
2561                         $user = core_user::get_user($message->useridfrom);
2562                         $message->userfromfullname = fullname($user, $canviewfullname);
2563                     }
2564                 } else {
2565                     $message->userfromfullname = $userfromfullname;
2566                 }
2568                 // We need to get the user from the query.
2569                 if (empty($usertofullname)) {
2570                     $user = new stdClass();
2571                     $user = username_load_fields_from_object($user, $message, 'userto');
2572                     $message->usertofullname = fullname($user, $canviewfullname);
2573                 } else {
2574                     $message->usertofullname = $usertofullname;
2575                 }
2577                 $message->text = message_format_message_text($message);
2578                 $messages[$mid] = (array) $message;
2579             }
2580         }
2582         $results = array(
2583             'messages' => $messages,
2584             'warnings' => $warnings
2585         );
2587         return $results;
2588     }
2590     /**
2591      * Get messages return description.
2592      *
2593      * @return external_single_structure
2594      * @since 2.8
2595      */
2596     public static function get_messages_returns() {
2597         return new external_single_structure(
2598             array(
2599                 'messages' => new external_multiple_structure(
2600                     new external_single_structure(
2601                         array(
2602                             'id' => new external_value(PARAM_INT, 'Message id'),
2603                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2604                             'useridto' => new external_value(PARAM_INT, 'User to id'),
2605                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2606                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
2607                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2608                             'fullmessageformat' => new external_format_value('fullmessage'),
2609                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2610                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2611                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2612                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2613                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2614                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
2615                             'timeread' => new external_value(PARAM_INT, 'Time read'),
2616                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2617                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2618                         ), 'message'
2619                     )
2620                 ),
2621                 'warnings' => new external_warnings()
2622             )
2623         );
2624     }
2626     /**
2627      * Mark all notifications as read parameters description.
2628      *
2629      * @return external_function_parameters
2630      * @since 3.2
2631      */
2632     public static function mark_all_notifications_as_read_parameters() {
2633         return new external_function_parameters(
2634             array(
2635                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2636                 'useridfrom' => new external_value(
2637                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2638                     VALUE_DEFAULT, 0),
2639             )
2640         );
2641     }
2643     /**
2644      * Mark all notifications as read function.
2645      *
2646      * @since  3.2
2647      * @throws invalid_parameter_exception
2648      * @throws moodle_exception
2649      * @param  int      $useridto       the user id who received the message
2650      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2651      * @return external_description
2652      */
2653     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2654         global $USER;
2656         $params = self::validate_parameters(
2657             self::mark_all_notifications_as_read_parameters(),
2658             array(
2659                 'useridto' => $useridto,
2660                 'useridfrom' => $useridfrom,
2661             )
2662         );
2664         $context = context_system::instance();
2665         self::validate_context($context);
2667         $useridto = $params['useridto'];
2668         $useridfrom = $params['useridfrom'];
2670         if (!empty($useridto)) {
2671             if (core_user::is_real_user($useridto)) {
2672                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2673             } else {
2674                 throw new moodle_exception('invaliduser');
2675             }
2676         }
2678         if (!empty($useridfrom)) {
2679             // We use get_user here because the from user can be the noreply or support user.
2680             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2681         }
2683         // Check if the current user is the sender/receiver or just a privileged user.
2684         if ($useridto != $USER->id and $useridfrom != $USER->id and
2685             // The deleteanymessage cap seems more reasonable here than readallmessages.
2686              !has_capability('moodle/site:deleteanymessage', $context)) {
2687             throw new moodle_exception('accessdenied', 'admin');
2688         }
2690         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2692         return true;
2693     }
2695     /**
2696      * Mark all notifications as read return description.
2697      *
2698      * @return external_single_structure
2699      * @since 3.2
2700      */
2701     public static function mark_all_notifications_as_read_returns() {
2702         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2703     }
2705     /**
2706      * Get unread conversations count parameters description.
2707      *
2708      * @return external_function_parameters
2709      * @since 3.2
2710      */
2711     public static function get_unread_conversations_count_parameters() {
2712         return new external_function_parameters(
2713             array(
2714                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2715             )
2716         );
2717     }
2719     /**
2720      * Get unread messages count function.
2721      *
2722      * @since  3.2
2723      * @throws invalid_parameter_exception
2724      * @throws moodle_exception
2725      * @param  int      $useridto       the user id who received the message
2726      * @return external_description
2727      */
2728     public static function get_unread_conversations_count($useridto) {
2729         global $USER, $CFG;
2731         // Check if messaging is enabled.
2732         if (empty($CFG->messaging)) {
2733             throw new moodle_exception('disabled', 'message');
2734         }
2736         $params = self::validate_parameters(
2737             self::get_unread_conversations_count_parameters(),
2738             array('useridto' => $useridto)
2739         );
2741         $context = context_system::instance();
2742         self::validate_context($context);
2744         $useridto = $params['useridto'];
2746         if (!empty($useridto)) {
2747             if (core_user::is_real_user($useridto)) {
2748                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2749             } else {
2750                 throw new moodle_exception('invaliduser');
2751             }
2752         } else {
2753             $useridto = $USER->id;
2754         }
2756         // Check if the current user is the receiver or just a privileged user.
2757         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2758             throw new moodle_exception('accessdenied', 'admin');
2759         }
2761         return \core_message\api::count_unread_conversations($userto);
2762     }
2764     /**
2765      * Get unread conversations count return description.
2766      *
2767      * @return external_single_structure
2768      * @since 3.2
2769      */
2770     public static function get_unread_conversations_count_returns() {
2771         return new external_value(PARAM_INT, 'The count of unread messages for the user');
2772     }
2774     /**
2775      * Get blocked users parameters description.
2776      *
2777      * @return external_function_parameters
2778      * @since 2.9
2779      */
2780     public static function get_blocked_users_parameters() {
2781         return new external_function_parameters(
2782             array(
2783                 'userid' => new external_value(PARAM_INT,
2784                                 'the user whose blocked users we want to retrieve',
2785                                 VALUE_REQUIRED),
2786             )
2787         );
2788     }
2790     /**
2791      * Retrieve a list of users blocked
2792      *
2793      * @param  int $userid the user whose blocked users we want to retrieve
2794      * @return external_description
2795      * @since 2.9
2796      */
2797     public static function get_blocked_users($userid) {
2798         global $CFG, $USER, $PAGE;
2800         // Warnings array, it can be empty at the end but is mandatory.
2801         $warnings = array();
2803         // Validate params.
2804         $params = array(
2805             'userid' => $userid
2806         );
2807         $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2808         $userid = $params['userid'];
2810         // Validate context.
2811         $context = context_system::instance();
2812         self::validate_context($context);
2814         // Check if private messaging between users is allowed.
2815         if (empty($CFG->messaging)) {
2816             throw new moodle_exception('disabled', 'message');
2817         }
2819         $user = core_user::get_user($userid, '*', MUST_EXIST);
2820         core_user::require_active_user($user);
2822         // Check if we have permissions for retrieve the information.
2823         $capability = 'moodle/site:manageallmessaging';
2824         if (($USER->id != $userid) && !has_capability($capability, $context)) {
2825             throw new required_capability_exception($context, $capability, 'nopermissions', '');
2826         }
2828         // Now, we can get safely all the blocked users.
2829         $users = \core_message\api::get_blocked_users($user->id);
2831         $blockedusers = array();
2832         foreach ($users as $user) {
2833             $newuser = array(
2834                 'id' => $user->id,
2835                 'fullname' => fullname($user),
2836             );
2838             $userpicture = new user_picture($user);
2839             $userpicture->size = 1; // Size f1.
2840             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2842             $blockedusers[] = $newuser;
2843         }
2845         $results = array(
2846             'users' => $blockedusers,
2847             'warnings' => $warnings
2848         );
2849         return $results;
2850     }
2852     /**
2853      * Get blocked users return description.
2854      *
2855      * @return external_single_structure
2856      * @since 2.9
2857      */
2858     public static function get_blocked_users_returns() {
2859         return new external_single_structure(
2860             array(
2861                 'users' => new external_multiple_structure(
2862                     new external_single_structure(
2863                         array(
2864                             'id' => new external_value(PARAM_INT, 'User ID'),
2865                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2866                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2867                         )
2868                     ),
2869                     'List of blocked users'
2870                 ),
2871                 'warnings' => new external_warnings()
2872             )
2873         );
2874     }
2876     /**
2877      * Returns description of method parameters
2878      *
2879      * @return external_function_parameters
2880      * @since 2.9
2881      */
2882     public static function mark_message_read_parameters() {
2883         return new external_function_parameters(
2884             array(
2885                 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2886                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2887                     VALUE_DEFAULT, 0)
2888             )
2889         );
2890     }
2892     /**
2893      * Mark a single message as read, trigger message_viewed event
2894      *
2895      * @param  int $messageid id of the message (in the message table)
2896      * @param  int $timeread timestamp for when the message should be marked read
2897      * @return external_description
2898      * @throws invalid_parameter_exception
2899      * @throws moodle_exception
2900      * @since 2.9
2901      */
2902     public static function mark_message_read($messageid, $timeread) {
2903         global $CFG, $DB, $USER;
2905         // Check if private messaging between users is allowed.
2906         if (empty($CFG->messaging)) {
2907             throw new moodle_exception('disabled', 'message');
2908         }
2910         // Warnings array, it can be empty at the end but is mandatory.
2911         $warnings = array();
2913         // Validate params.
2914         $params = array(
2915             'messageid' => $messageid,
2916             'timeread' => $timeread
2917         );
2918         $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2920         if (empty($params['timeread'])) {
2921             $timeread = time();
2922         } else {
2923             $timeread = $params['timeread'];
2924         }
2926         // Validate context.
2927         $context = context_system::instance();
2928         self::validate_context($context);
2930         $sql = "SELECT m.*, mcm.userid as useridto
2931                   FROM {messages} m
2932             INNER JOIN {message_conversations} mc
2933                     ON m.conversationid = mc.id
2934             INNER JOIN {message_conversation_members} mcm
2935                     ON mcm.conversationid = mc.id
2936              LEFT JOIN {message_user_actions} mua
2937                     ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2938                  WHERE mua.id is NULL
2939                    AND mcm.userid != m.useridfrom
2940                    AND m.id = ?";
2941         $messageparams = [];
2942         $messageparams[] = $USER->id;
2943         $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2944         $messageparams[] = $params['messageid'];
2945         $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2947         if ($message->useridto != $USER->id) {
2948             throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2949         }
2951         \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2953         $results = array(
2954             'messageid' => $message->id,
2955             'warnings' => $warnings
2956         );
2957         return $results;
2958     }
2960     /**
2961      * Returns description of method result value
2962      *
2963      * @return external_description
2964      * @since 2.9
2965      */
2966     public static function mark_message_read_returns() {
2967         return new external_single_structure(
2968             array(
2969                 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2970                 'warnings' => new external_warnings()
2971             )
2972         );
2973     }
2975     /**
2976      * Returns description of method parameters
2977      *
2978      * @return external_function_parameters
2979      */
2980     public static function mark_notification_read_parameters() {
2981         return new external_function_parameters(
2982             array(
2983                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2984                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2985                     VALUE_DEFAULT, 0)
2986             )
2987         );
2988     }
2990     /**
2991      * Mark a single notification as read.
2992      *
2993      * This will trigger a 'notification_viewed' event.
2994      *
2995      * @param int $notificationid id of the notification
2996      * @param int $timeread timestamp for when the notification should be marked read
2997      * @return external_description
2998      * @throws invalid_parameter_exception
2999      * @throws moodle_exception
3000      */
3001     public static function mark_notification_read($notificationid, $timeread) {
3002         global $CFG, $DB, $USER;
3004         // Check if private messaging between users is allowed.
3005         if (empty($CFG->messaging)) {
3006             throw new moodle_exception('disabled', 'message');
3007         }
3009         // Warnings array, it can be empty at the end but is mandatory.
3010         $warnings = array();
3012         // Validate params.
3013         $params = array(
3014             'notificationid' => $notificationid,
3015             'timeread' => $timeread
3016         );
3017         $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
3019         if (empty($params['timeread'])) {
3020             $timeread = time();
3021         } else {
3022             $timeread = $params['timeread'];
3023         }
3025         // Validate context.
3026         $context = context_system::instance();
3027         self::validate_context($context);
3029         $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
3031         if ($notification->useridto != $USER->id) {
3032             throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
3033                 'notification as read');
3034         }
3036         \core_message\api::mark_notification_as_read($notification, $timeread);
3038         $results = array(
3039             'notificationid' => $notification->id,
3040             'warnings' => $warnings
3041         );
3043         return $results;
3044     }
3046     /**
3047      * Returns description of method result value
3048      *
3049      * @return external_description
3050      */
3051     public static function mark_notification_read_returns() {
3052         return new external_single_structure(
3053             array(
3054                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
3055                 'warnings' => new external_warnings()
3056             )
3057         );
3058     }
3060     /**
3061      * Mark all messages as read parameters description.
3062      *
3063      * @deprecated since 3.6
3064      * @return external_function_parameters
3065      * @since 3.2
3066      */
3067     public static function mark_all_messages_as_read_parameters() {
3068         return new external_function_parameters(
3069             array(
3070                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3071                 'useridfrom' => new external_value(
3072                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
3073                     VALUE_DEFAULT, 0),
3074             )
3075         );
3076     }
3078     /**
3079      * Mark all messages as read function.
3080      *
3081      * @deprecated since 3.6
3082      * @throws invalid_parameter_exception
3083      * @throws moodle_exception
3084      * @param  int      $useridto       the user id who received the message
3085      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
3086      * @return external_description
3087      * @since  3.2
3088      */
3089     public static function mark_all_messages_as_read($useridto, $useridfrom) {
3090         global $USER, $CFG;
3092         // Check if messaging is enabled.
3093         if (empty($CFG->messaging)) {
3094             throw new moodle_exception('disabled', 'message');
3095         }
3097         $params = self::validate_parameters(
3098             self::mark_all_messages_as_read_parameters(),
3099             array(
3100                 'useridto' => $useridto,
3101                 'useridfrom' => $useridfrom,
3102             )
3103         );
3105         $context = context_system::instance();
3106         self::validate_context($context);
3108         $useridto = $params['useridto'];
3109         $useridfrom = $params['useridfrom'];
3111         if (!empty($useridto)) {
3112             if (core_user::is_real_user($useridto)) {
3113                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3114             } else {
3115                 throw new moodle_exception('invaliduser');
3116             }
3117         }
3119         if (!empty($useridfrom)) {
3120             // We use get_user here because the from user can be the noreply or support user.
3121             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3122         }
3124         // Check if the current user is the sender/receiver or just a privileged user.
3125         if ($useridto != $USER->id and $useridfrom != $USER->id and
3126             // The deleteanymessage cap seems more reasonable here than readallmessages.
3127              !has_capability('moodle/site:deleteanymessage', $context)) {
3128             throw new moodle_exception('accessdenied', 'admin');
3129         }
3131         if ($useridfrom) {
3132             if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
3133                 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
3134             }
3135         } else {
3136             \core_message\api::mark_all_messages_as_read($useridto);
3137         }
3139         return true;
3140     }
3142     /**
3143      * Mark all messages as read return description.
3144      *
3145      * @deprecated since 3.6
3146      * @return external_single_structure
3147      * @since 3.2
3148      */
3149     public static function mark_all_messages_as_read_returns() {
3150         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
3151     }
3153     /**
3154      * Marking the method as deprecated.
3155      *
3156      * @return bool
3157      */
3158     public static function mark_all_messages_as_read_is_deprecated() {
3159         return true;
3160     }
3162     /**
3163      * Mark all conversation messages as read parameters description.
3164      *
3165      * @return external_function_parameters
3166      * @since 3.6
3167      */
3168     public static function mark_all_conversation_messages_as_read_parameters() {
3169         return new external_function_parameters(
3170             array(
3171                 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
3172                 'conversationid' =>
3173                     new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
3174             )
3175         );
3176     }
3178     /**
3179      * Mark all conversation messages as read function.
3180      *
3181      * @param int $userid The user id of who we want to delete the conversation for
3182      * @param int $conversationid The id of the conversations
3183      * @since 3.6
3184      */
3185     public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
3186         global $CFG;
3188         // Check if messaging is enabled.
3189         if (empty($CFG->messaging)) {
3190             throw new moodle_exception('disabled', 'message');
3191         }
3193         $params = array(
3194             'userid' => $userid,
3195             'conversationid' => $conversationid,
3196         );
3197         $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
3199         $context = context_system::instance();
3200         self::validate_context($context);
3202         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3203         core_user::require_active_user($user);
3205         if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
3206             \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
3207         } else {
3208             throw new moodle_exception('accessdenied', 'admin');
3209         }
3210     }
3212     /**
3213      * Mark all conversation messages as read return description.
3214      *
3215      * @return external_warnings
3216      * @since 3.6
3217      */
3218     public static function mark_all_conversation_messages_as_read_returns() {
3219         return null;
3220     }
3222     /**
3223      * Returns description of method parameters.
3224      *
3225      * @deprecated since 3.6
3226      * @return external_function_parameters
3227      * @since 3.2
3228      */
3229     public static function delete_conversation_parameters() {
3230         return new external_function_parameters(
3231             array(
3232                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3233                 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
3234             )
3235         );
3236     }
3238     /**
3239      * Deletes a conversation.
3240      *
3241      * @deprecated since 3.6
3242      * @param int $userid The user id of who we want to delete the conversation for
3243      * @param int $otheruserid The user id of the other user in the conversation
3244      * @return array
3245      * @throws moodle_exception
3246      * @since 3.2
3247      */
3248     public static function delete_conversation($userid, $otheruserid) {
3249         global $CFG;
3251         // Check if private messaging between users is allowed.
3252         if (empty($CFG->messaging)) {
3253             throw new moodle_exception('disabled', 'message');
3254         }
3256         // Warnings array, it can be empty at the end but is mandatory.
3257         $warnings = array();
3259         // Validate params.
3260         $params = array(
3261             'userid' => $userid,
3262             'otheruserid' => $otheruserid,
3263         );
3264         $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
3266         // Validate context.
3267         $context = context_system::instance();
3268         self::validate_context($context);
3270         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3271         core_user::require_active_user($user);
3273         if (!$conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']])) {
3274             return [];
3275         }
3277         if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3278             \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3279             $status = true;
3280         } else {
3281             throw new moodle_exception('You do not have permission to delete messages');
3282         }
3284         $results = array(
3285             'status' => $status,
3286             'warnings' => $warnings
3287         );
3289         return $results;
3290     }
3292     /**
3293      * Returns description of method result value.
3294      *
3295      * @deprecated since 3.6
3296      * @return external_description
3297      * @since 3.2
3298      */
3299     public static function delete_conversation_returns() {
3300         return new external_single_structure(
3301             array(
3302                 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
3303                 'warnings' => new external_warnings()
3304             )
3305         );
3306     }
3308     /**
3309      * Marking the method as deprecated.
3310      *
3311      * @return bool
3312      */
3313     public static function delete_conversation_is_deprecated() {
3314         return true;
3315     }
3317     /**
3318      * Returns description of method parameters.
3319      *
3320      * @return external_function_parameters
3321      * @since 3.6
3322      */
3323     public static function delete_conversations_by_id_parameters() {
3324         return new external_function_parameters(
3325             array(
3326                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3327                 'conversationids' => new external_multiple_structure(
3328                     new external_value(PARAM_INT, 'The id of the conversation'),
3329                     'List of conversation IDs'
3330                 ),
3331             )
3332         );
3333     }
3335     /**
3336      * Deletes a conversation.
3337      *
3338      * @param int $userid The user id of who we want to delete the conversation for
3339      * @param int[] $conversationids The ids of the conversations
3340      * @return array
3341      * @throws moodle_exception
3342      * @since 3.6
3343      */
3344     public static function delete_conversations_by_id($userid, array $conversationids) {
3345         global $CFG;
3347         // Check if private messaging between users is allowed.
3348         if (empty($CFG->messaging)) {
3349             throw new moodle_exception('disabled', 'message');
3350         }
3352         // Validate params.
3353         $params = [
3354             'userid' => $userid,
3355             'conversationids' => $conversationids,
3356         ];
3357         $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
3359         // Validate context.
3360         $context = context_system::instance();
3361         self::validate_context($context);
3363         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3364         core_user::require_active_user($user);
3366         foreach ($params['conversationids'] as $conversationid) {
3367             if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3368                 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3369             } else {
3370                 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
3371             }
3372         }
3374         return [];
3375     }
3377     /**
3378      * Returns description of method result value.
3379      *
3380      * @return external_description
3381      * @since 3.6
3382      */
3383     public static function delete_conversations_by_id_returns() {
3384         return new external_warnings();
3385     }
3387     /**
3388      * Returns description of method parameters
3389      *
3390      * @return external_function_parameters
3391      * @since 3.1
3392      */
3393     public static function delete_message_parameters() {
3394         return new external_function_parameters(
3395             array(
3396                 'messageid' => new external_value(PARAM_INT, 'The message id'),
3397                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
3398                 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
3399             )
3400         );
3401     }
3403     /**
3404      * Deletes a message
3405      *
3406      * @param  int $messageid the message id
3407      * @param  int $userid the user id of who we want to delete the message for
3408      * @param  bool $read if is a message read (default to true)
3409      * @return external_description
3410      * @throws moodle_exception
3411      * @since 3.1
3412      */
3413     public static function delete_message($messageid, $userid, $read = true) {
3414         global $CFG;
3416         // Check if private messaging between users is allowed.
3417         if (empty($CFG->messaging)) {
3418             throw new moodle_exception('disabled', 'message');
3419         }
3421         // Warnings array, it can be empty at the end but is mandatory.
3422         $warnings = array();
3424         // Validate params.
3425         $params = array(
3426             'messageid' => $messageid,
3427             'userid' => $userid,
3428             'read' => $read
3429         );
3430         $params = self::validate_parameters(self::delete_message_parameters(), $params);
3432         // Validate context.
3433         $context = context_system::instance();
3434         self::validate_context($context);
3436         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3437         core_user::require_active_user($user);
3439         if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
3440             $status = \core_message\api::delete_message($user->id, $params['messageid']);
3441         } else {
3442             throw new moodle_exception('You do not have permission to delete this message');
3443         }
3445         $results = array(
3446             'status' => $status,
3447             'warnings' => $warnings
3448         );
3449         return $results;
3450     }
3452     /**
3453      * Returns description of method result value
3454      *
3455      * @return external_description
3456      * @since 3.1
3457      */
3458     public static function delete_message_returns() {
3459         return new external_single_structure(
3460             array(
3461                 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
3462                 'warnings' => new external_warnings()
3463             )
3464         );
3465     }
3467     /**
3468      * Returns description of method parameters
3469      *
3470      * @return external_function_parameters
3471      * @since 3.2
3472      */
3473     public static function message_processor_config_form_parameters() {
3474         return new external_function_parameters(
3475             array(
3476                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
3477                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
3478                 'formvalues' => new external_multiple_structure(
3479                     new external_single_structure(
3480                         array(
3481                             'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
3482                             'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
3483                         )
3484                     ),
3485                     'Config form values',
3486                     VALUE_REQUIRED
3487                 ),
3488             )
3489         );
3490     }
3492     /**
3493      * Processes a message processor config form.
3494      *
3495      * @param  int $userid the user id
3496      * @param  string $name the name of the processor
3497      * @param  array $formvalues the form values
3498      * @return external_description
3499      * @throws moodle_exception
3500      * @since 3.2
3501      */
3502     public static function message_processor_config_form($userid, $name, $formvalues) {
3503         global $USER, $CFG;
3505         // Check if messaging is enabled.
3506         if (empty($CFG->messaging)) {
3507             throw new moodle_exception('disabled', 'message');
3508         }
3510         $params = self::validate_parameters(
3511             self::message_processor_config_form_parameters(),
3512             array(
3513                 'userid' => $userid,
3514                 'name' => $name,
3515                 'formvalues' => $formvalues,
3516             )
3517         );
3519         $user = self::validate_preferences_permissions($params['userid']);
3521         $processor = get_message_processor($params['name']);
3522         $preferences = [];
3523         $form = new stdClass();
3525         foreach ($params['formvalues'] as $formvalue) {
3526             // Curly braces to ensure interpretation is consistent between
3527             // php 5 and php 7.
3528             $form->{$formvalue['name']} = $formvalue['value'];
3529         }
3531         $processor->process_form($form, $preferences);
3533         if (!empty($preferences)) {
3534             set_user_preferences($preferences, $params['userid']);
3535         }
3536     }
3538     /**
3539      * Returns description of method result value
3540      *
3541      * @return external_description
3542      * @since 3.2
3543      */
3544     public static function message_processor_config_form_returns() {
3545         return null;
3546     }
3548     /**
3549      * Returns description of method parameters
3550      *
3551      * @return external_function_parameters
3552      * @since 3.2
3553      */
3554     public static function get_message_processor_parameters() {
3555         return new external_function_parameters(
3556             array(
3557                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
3558                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
3559             )
3560         );
3561     }
3563     /**
3564      * Get a message processor.
3565      *
3566      * @param int $userid
3567      * @param string $name the name of the processor
3568      * @return external_description
3569      * @throws moodle_exception
3570      * @since 3.2
3571      */
3572     public static function get_message_processor($userid = 0, $name) {
3573         global $USER, $PAGE, $CFG;
3575         // Check if messaging is enabled.
3576         if (empty($CFG->messaging)) {
3577             throw new moodle_exception('disabled', 'message');
3578         }
3580         $params = self::validate_parameters(
3581             self::get_message_processor_parameters(),
3582             array(
3583                 'userid' => $userid,
3584                 'name' => $name,
3585             )
3586         );
3588         if (empty($params['userid'])) {
3589             $params['userid'] = $USER->id;
3590         }
3592         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3593         core_user::require_active_user($user);
3594         self::validate_context(context_user::instance($params['userid']));
3596         $processor = get_message_processor($params['name']);
3598         $processoroutput = new \core_message\output\processor($processor, $user);
3599         $renderer = $PAGE->get_renderer('core_message');
3601         return $processoroutput->export_for_template($renderer);
3602     }
3604     /**
3605      * Returns description of method result value
3606      *
3607      * @return external_description
3608      * @since 3.2
3609      */
3610     public static function get_message_processor_returns() {
3611         return new external_function_parameters(
3612             array(
3613                 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
3614                 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
3615             )
3616         );
3617     }
3619     /**
3620      * Check that the user has enough permission to retrieve message or notifications preferences.
3621      *
3622      * @param  int $userid the user id requesting the preferences
3623      * @return stdClass full user object
3624      * @throws moodle_exception
3625      * @since  Moodle 3.2
3626      */
3627     protected static function validate_preferences_permissions($userid) {
3628         global $USER;
3630         if (empty($userid)) {
3631             $user = $USER;
3632         } else {
3633             $user = core_user::get_user($userid, '*', MUST_EXIST);
3634             core_user::require_active_user($user);
3635         }
3637         $systemcontext = context_system::instance();
3638         self::validate_context($systemcontext);
3640         // Check access control.
3641         if ($user->id == $USER->id) {
3642             // Editing own message profile.
3643             require_capability('moodle/user:editownmessageprofile', $systemcontext);
3644         } else {
3645             // Teachers, parents, etc.
3646             $personalcontext = context_user::instance($user->id);
3647             require_capability('moodle/user:editmessageprofile', $personalcontext);
3648         }
3649         return $user;
3650     }
3652     /**
3653      * Returns a notification or message preference structure.
3654      *
3655      * @return external_single_structure the structure
3656      * @since  Moodle 3.2
3657      */
3658     protected static function get_preferences_structure() {
3659         return new external_single_structure(
3660             array(
3661                 'userid' => new external_value(PARAM_INT, 'User id'),
3662                 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3663                 'processors' => new external_multiple_structure(
3664                     new external_single_structure(
3665                         array(
3666                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3667                             'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3668                             'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3669                             'contextid' => new external_value(PARAM_INT, 'Context id'),
3670                             'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3671                         )
3672                     ),
3673                     'Config form values'
3674                 ),
3675                 'components' => new external_multiple_structure(
3676                     new external_single_structure(
3677                         array(
3678                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3679                             'notifications' => new external_multiple_structure(
3680                                 new external_single_structure(
3681                                     array(
3682                                         'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3683                                         'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3684                                         'processors' => new external_multiple_structure(
3685                                             new external_single_structure(
3686                                                 array(
3687                                                     'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3688                                                     'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3689                                                     'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3690                                                     'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3691                                                     'loggedin' => new external_single_structure(
3692                                                         array(
3693                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
3694                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3695                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3696                                                         )
3697                                                     ),
3698                                                     'loggedoff' => new external_single_structure(
3699                                                         array(
3700                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
3701                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3702                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3703                                                         )
3704                                                     ),
3705                                                 )
3706                                             ),
3707                                             'Processors values for this notification'
3708                                         ),
3709                                     )
3710                                 ),
3711                                 'List of notificaitons for the component'
3712                             ),
3713                         )
3714                     ),
3715                     'Available components'
3716                 ),
3717             )
3718         );
3719     }
3721     /**
3722      * Returns description of method parameters
3723      *
3724      * @return external_function_parameters
3725      * @since 3.2
3726      */
3727     public static function get_user_notification_preferences_parameters() {
3728         return new external_function_parameters(
3729             array(
3730                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3731             )
3732         );
3733     }
3735     /**
3736      * Get the notification preferences for a given user.
3737      *
3738      * @param int $userid id of the user, 0 for current user
3739      * @return external_description
3740      * @throws moodle_exception
3741      * @since 3.2
3742      */
3743     public static function get_user_notification_preferences($userid = 0) {
3744         global $PAGE;
3746         $params = self::validate_parameters(
3747             self::get_user_notification_preferences_parameters(),
3748             array(
3749                 'userid' => $userid,
3750             )
3751         );
3752         $user = self::validate_preferences_permissions($params['userid']);
3754         $processors = get_message_processors();
3755         $providers = message_get_providers_for_user($user->id);
3756         $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3757         $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3759         $renderer = $PAGE->get_renderer('core_message');
3761         $result = array(
3762             'warnings' => array(),
3763             'preferences' => $notificationlist->export_for_template($renderer)
3764         );
3765         return $result;
3766     }
3768     /**
3769      * Returns description of method result value
3770      *
3771      * @return external_description
3772      * @since 3.2
3773      */
3774     public static function get_user_notification_preferences_returns() {
3775         return new external_function_parameters(
3776             array(
3777                 'preferences' => self::get_preferences_structure(),
3778                 'warnings' => new external_warnings(),
3779             )
3780         );
3781     }
3783     /**
3784      * Returns description of method parameters
3785      *
3786      * @return external_function_parameters
3787      * @since 3.2
3788      */
3789     public static function get_user_message_preferences_parameters() {
3790         return new external_function_parameters(
3791             array(
3792                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3793             )
3794         );
3795     }
3797     /**
3798      * Get the notification preferences for a given user.
3799      *
3800      * @param int $userid id of the user, 0 for current user
3801      * @return external_description
3802      * @throws moodle_exception
3803      * @since 3.2
3804      */
3805     public static function get_user_message_preferences($userid = 0) {
3806         global $PAGE;
3808         $params = self::validate_parameters(
3809             self::get_user_message_preferences_parameters(),
3810             array(
3811                 'userid' => $userid,
3812             )
3813         );
3815         $user = self::validate_preferences_permissions($params['userid']);
3817         // Filter out enabled, available system_configured and user_configured processors only.
3818         $readyprocessors = array_filter(get_message_processors(), function($processor) {
3819             return $processor->enabled &&
3820                 $processor->configured &&
3821                 $processor->object->is_user_configured() &&
3822                 // Filter out processors that don't have and message preferences to configure.
3823                 $processor->object->has_message_preferences();
3824         });
3826         $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
3827             return $provider->component === 'moodle';
3828         });
3829         $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
3830         $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
3831             $providers, $preferences, $user);
3833         $renderer = $PAGE->get_renderer('core_message');
3835         $result = array(
3836             'warnings' => array(),
3837             'preferences' => $notificationlistoutput->export_for_template($renderer),
3838             'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id),
3839         );
3840         return $result;
3841     }
3843     /**
3844      * Returns description of method result value
3845      *
3846      * @return external_description
3847      * @since 3.2
3848      */
3849     public static function get_user_message_preferences_returns() {
3850         return new external_function_parameters(
3851             array(
3852                 'preferences' => self::get_preferences_structure(),
3853                 'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'),
3854                 'warnings' => new external_warnings(),
3855             )
3856         );
3857     }
3859     /**
3860      * Returns description of method parameters for the favourite_conversations() method.
3861      *
3862      * @return external_function_parameters
3863      */
3864     public static function set_favourite_conversations_parameters() {
3865         return new external_function_parameters(
3866             array(
3867                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3868                 'conversations' => new external_multiple_structure(
3869                     new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3870                 )
3871             )
3872         );
3873     }
3875     /**
3876      * Favourite a conversation, or list of conversations for a user.
3877      *
3878      * @param int $userid the id of the user, or 0 for the current user.
3879      * @param array $conversationids the list of conversations ids to favourite.
3880      * @return array
3881      * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3882      */
3883     public static function set_favourite_conversations(int $userid, array $conversationids) {
3884         global $CFG, $USER;
3886         // All the business logic checks that really shouldn't be in here.
3887         if (empty($CFG->messaging)) {
3888             throw new moodle_exception('disabled', 'message');
3889         }
3890         $params = [
3891             'userid' => $userid,
3892             'conversations' => $conversationids
3893         ];
3894         $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params);
3895         $systemcontext = context_system::instance();
3896         self::validate_context($systemcontext);
3898         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3899             throw new moodle_exception('You do not have permission to perform this action.');
3900         }
3902         foreach ($params['conversations'] as $conversationid) {
3903             \core_message\api::set_favourite_conversation($conversationid, $params['userid']);
3904         }
3906         return [];
3907     }
3909     /**
3910      * Return a description of the returns for the create_user_favourite_conversations() method.
3911      *
3912      * @return external_description
3913      */
3914     public static function set_favourite_conversations_returns() {
3915         return new external_warnings();
3916     }
3918     /**
3919      * Returns description of method parameters for unfavourite_conversations() method.
3920      *
3921      * @return external_function_parameters
3922      */
3923     public static function unset_favourite_conversations_parameters() {
3924         return new external_function_parameters(
3925             array(
3926                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3927                 'conversations' => new external_multiple_structure(
3928                     new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3929                 )
3930             )
3931         );
3932     }
3934     /**
3935      * Unfavourite a conversation, or list of conversations for a user.
3936      *
3937      * @param int $userid the id of the user, or 0 for the current user.
3938      * @param array $conversationids the list of conversations ids unset as favourites.
3939      * @return array
3940      * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3941      */
3942     public static function unset_favourite_conversations(int $userid, array $conversationids) {
3943         global $CFG, $USER;
3945         // All the business logic checks that really shouldn't be in here.
3946         if (empty($CFG->messaging)) {
3947             throw new moodle_exception('disabled', 'message');
3948         }
3949         $params = [
3950             'userid' => $userid,
3951             'conversations' => $conversationids
3952         ];
3953         $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params);
3954         $systemcontext = context_system::instance();
3955         self::validate_context($systemcontext);
3957         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3958             throw new moodle_exception('You do not have permission to perform this action.');
3959         }
3961         foreach ($params['conversations'] as $conversationid) {
3962             \core_message\api::unset_favourite_conversation($conversationid, $params['userid']);
3963         }
3965         return [];
3966     }
3968     /**
3969      * Unset favourite conversations return description.
3970      *
3971      * @return external_description
3972      */
3973     public static function unset_favourite_conversations_returns() {
3974         return new external_warnings();
3975     }
3977     /**
3978      * Returns description of method parameters for get_member_info() method.
3979      *
3980      * @return external_function_parameters
3981      */
3982     public static function get_member_info_parameters() {
3983         return new external_function_parameters(
3984             array(
3985                 'referenceuserid' => new external_value(PARAM_INT, 'id of the user'),
3986                 'userids' => new external_multiple_structure(
3987                     new external_value(PARAM_INT, 'id of members to get')
3988                 ),
3989                 'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false),
3990                 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'i