7f88e62543eb5f7765e76dd51198bbbe5e2dc66f
[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 {
43     /**
44      * Returns description of method parameters
45      *
46      * @return external_function_parameters
47      * @since Moodle 2.2
48      */
49     public static function send_instant_messages_parameters() {
50         return new external_function_parameters(
51             array(
52                 'messages' => new external_multiple_structure(
53                     new external_single_structure(
54                         array(
55                             'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
56                             'text' => new external_value(PARAM_RAW, 'the text of the message'),
57                             'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
58                             '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),
59                         )
60                     )
61                 )
62             )
63         );
64     }
66     /**
67      * Send private messages from the current USER to other users
68      *
69      * @param array $messages An array of message to send.
70      * @return array
71      * @since Moodle 2.2
72      */
73     public static function send_instant_messages($messages = array()) {
74         global $CFG, $USER, $DB;
76         // Check if messaging is enabled.
77         if (empty($CFG->messaging)) {
78             throw new moodle_exception('disabled', 'message');
79         }
81         // Ensure the current user is allowed to run this function
82         $context = context_system::instance();
83         self::validate_context($context);
84         require_capability('moodle/site:sendmessage', $context);
86         $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
88         //retrieve all tousers of the messages
89         $receivers = array();
90         foreach($params['messages'] as $message) {
91             $receivers[] = $message['touserid'];
92         }
93         list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
94         $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
96         $resultmessages = array();
97         foreach ($params['messages'] as $message) {
98             $resultmsg = array(); //the infos about the success of the operation
100             // We are going to do some checking.
101             // Code should match /messages/index.php checks.
102             $success = true;
104             // Check the user exists.
105             if (empty($tousers[$message['touserid']])) {
106                 $success = false;
107                 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
108             }
110             // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
111             // Check if the recipient can be messaged by the sender.
112             if ($success && !\core_message\api::can_post_message($tousers[$message['touserid']], $USER)) {
113                 $success = false;
114                 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
115             }
117             // Now we can send the message (at least try).
118             if ($success) {
119                 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
120                 $success = message_post_message($USER, $tousers[$message['touserid']],
121                         $message['text'], external_validate_format($message['textformat']));
122             }
124             // Build the resultmsg.
125             if (isset($message['clientmsgid'])) {
126                 $resultmsg['clientmsgid'] = $message['clientmsgid'];
127             }
128             if ($success) {
129                 $resultmsg['msgid'] = $success;
130             } else {
131                 // WARNINGS: for backward compatibility we return this errormessage.
132                 //          We should have thrown exceptions as these errors prevent results to be returned.
133                 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
134                 $resultmsg['msgid'] = -1;
135                 $resultmsg['errormessage'] = $errormessage;
136             }
138             $resultmessages[] = $resultmsg;
139         }
141         return $resultmessages;
142     }
144     /**
145      * Returns description of method result value
146      *
147      * @return external_description
148      * @since Moodle 2.2
149      */
150     public static function send_instant_messages_returns() {
151         return new external_multiple_structure(
152             new external_single_structure(
153                 array(
154                     'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
155                     'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
156                     'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
157                 )
158             )
159         );
160     }
162     /**
163      * Create contacts parameters description.
164      *
165      * @deprecated since Moodle 3.6
166      * @return external_function_parameters
167      * @since Moodle 2.5
168      */
169     public static function create_contacts_parameters() {
170         return new external_function_parameters(
171             array(
172                 'userids' => new external_multiple_structure(
173                     new external_value(PARAM_INT, 'User ID'),
174                     'List of user IDs'
175                 ),
176                 'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
177                     current user', VALUE_DEFAULT, 0)
178             )
179         );
180     }
182     /**
183      * Create contacts.
184      *
185      * @deprecated since Moodle 3.6
186      * @param array $userids array of user IDs.
187      * @param int $userid The id of the user we are creating the contacts for
188      * @return external_description
189      * @since Moodle 2.5
190      */
191     public static function create_contacts($userids, $userid = 0) {
192         global $CFG, $USER;
194         // Check if messaging is enabled.
195         if (empty($CFG->messaging)) {
196             throw new moodle_exception('disabled', 'message');
197         }
199         if (empty($userid)) {
200             $userid = $USER->id;
201         }
203         // Validate context.
204         $context = context_system::instance();
205         self::validate_context($context);
207         $capability = 'moodle/site:manageallmessaging';
208         if (($USER->id != $userid) && !has_capability($capability, $context)) {
209             throw new required_capability_exception($context, $capability, 'nopermissions', '');
210         }
212         $params = array('userids' => $userids, 'userid' => $userid);
213         $params = self::validate_parameters(self::create_contacts_parameters(), $params);
215         $warnings = array();
216         foreach ($params['userids'] as $id) {
217             if (!message_add_contact($id, 0, $userid)) {
218                 $warnings[] = array(
219                     'item' => 'user',
220                     'itemid' => $id,
221                     'warningcode' => 'contactnotcreated',
222                     'message' => 'The contact could not be created'
223                 );
224             }
225         }
226         return $warnings;
227     }
229     /**
230      * Create contacts return description.
231      *
232      * @deprecated since Moodle 3.6
233      * @return external_description
234      * @since Moodle 2.5
235      */
236     public static function create_contacts_returns() {
237         return new external_warnings();
238     }
240     /**
241      * Marking the method as deprecated.
242      *
243      * @return bool
244      */
245     public static function create_contacts_is_deprecated() {
246         return true;
247     }
249     /**
250      * Delete contacts parameters description.
251      *
252      * @return external_function_parameters
253      * @since Moodle 2.5
254      */
255     public static function delete_contacts_parameters() {
256         return new external_function_parameters(
257             array(
258                 'userids' => new external_multiple_structure(
259                     new external_value(PARAM_INT, 'User ID'),
260                     'List of user IDs'
261                 ),
262                 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
263                     current user', VALUE_DEFAULT, 0)
264             )
265         );
266     }
268     /**
269      * Delete contacts.
270      *
271      * @param array $userids array of user IDs.
272      * @param int $userid The id of the user we are deleting the contacts for
273      * @return null
274      * @since Moodle 2.5
275      */
276     public static function delete_contacts($userids, $userid = 0) {
277         global $CFG, $USER;
279         // Check if messaging is enabled.
280         if (empty($CFG->messaging)) {
281             throw new moodle_exception('disabled', 'message');
282         }
284         if (empty($userid)) {
285             $userid = $USER->id;
286         }
288         // Validate context.
289         $context = context_system::instance();
290         self::validate_context($context);
292         $capability = 'moodle/site:manageallmessaging';
293         if (($USER->id != $userid) && !has_capability($capability, $context)) {
294             throw new required_capability_exception($context, $capability, 'nopermissions', '');
295         }
297         $params = array('userids' => $userids, 'userid' => $userid);
298         $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
300         foreach ($params['userids'] as $id) {
301             \core_message\api::remove_contact($userid, $id);
302         }
304         return null;
305     }
307     /**
308      * Delete contacts return description.
309      *
310      * @return external_description
311      * @since Moodle 2.5
312      */
313     public static function delete_contacts_returns() {
314         return null;
315     }
317     /**
318      * Block user parameters description.
319      *
320      * @return external_function_parameters
321      */
322     public static function block_user_parameters() {
323         return new external_function_parameters(
324             [
325                 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
326                 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
327             ]
328         );
329     }
331     /**
332      * Blocks a user.
333      *
334      * @param int $userid The id of the user who is blocking
335      * @param int $blockeduserid The id of the user being blocked
336      * @return external_description
337      */
338     public static function block_user(int $userid, int $blockeduserid) {
339         global $CFG, $USER;
341         // Check if messaging is enabled.
342         if (empty($CFG->messaging)) {
343             throw new moodle_exception('disabled', 'message');
344         }
346         // Validate context.
347         $context = context_system::instance();
348         self::validate_context($context);
350         $capability = 'moodle/site:manageallmessaging';
351         if (($USER->id != $userid) && !has_capability($capability, $context)) {
352             throw new required_capability_exception($context, $capability, 'nopermissions', '');
353         }
355         $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
356         $params = self::validate_parameters(self::block_user_parameters(), $params);
358         if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
359             \core_message\api::block_user($params['userid'], $params['blockeduserid']);
360         }
362         return [];
363     }
365     /**
366      * Block user return description.
367      *
368      * @return external_description
369      */
370     public static function block_user_returns() {
371         return new external_warnings();
372     }
374     /**
375      * Unblock user parameters description.
376      *
377      * @return external_function_parameters
378      */
379     public static function unblock_user_parameters() {
380         return new external_function_parameters(
381             [
382                 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
383                 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
384             ]
385         );
386     }
388     /**
389      * Unblock user.
390      *
391      * @param int $userid The id of the user who is unblocking
392      * @param int $unblockeduserid The id of the user being unblocked
393      */
394     public static function unblock_user(int $userid, int $unblockeduserid) {
395         global $CFG, $USER;
397         // Check if messaging is enabled.
398         if (empty($CFG->messaging)) {
399             throw new moodle_exception('disabled', 'message');
400         }
402         // Validate context.
403         $context = context_system::instance();
404         self::validate_context($context);
406         $capability = 'moodle/site:manageallmessaging';
407         if (($USER->id != $userid) && !has_capability($capability, $context)) {
408             throw new required_capability_exception($context, $capability, 'nopermissions', '');
409         }
411         $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
412         $params = self::validate_parameters(self::unblock_user_parameters(), $params);
414         \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
416         return [];
417     }
419     /**
420      * Unblock user return description.
421      *
422      * @return external_description
423      */
424     public static function unblock_user_returns() {
425         return new external_warnings();
426     }
428     /**
429      * Block contacts parameters description.
430      *
431      * @deprecated since Moodle 3.6
432      * @return external_function_parameters
433      * @since Moodle 2.5
434      */
435     public static function block_contacts_parameters() {
436         return new external_function_parameters(
437             array(
438                 'userids' => new external_multiple_structure(
439                     new external_value(PARAM_INT, 'User ID'),
440                     'List of user IDs'
441                 ),
442                 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
443                     current user', VALUE_DEFAULT, 0)
444             )
445         );
446     }
448     /**
449      * Block contacts.
450      *
451      * @deprecated since Moodle 3.6
452      * @param array $userids array of user IDs.
453      * @param int $userid The id of the user we are blocking the contacts for
454      * @return external_description
455      * @since Moodle 2.5
456      */
457     public static function block_contacts($userids, $userid = 0) {
458         global $CFG, $USER;
460         // Check if messaging is enabled.
461         if (empty($CFG->messaging)) {
462             throw new moodle_exception('disabled', 'message');
463         }
465         if (empty($userid)) {
466             $userid = $USER->id;
467         }
469         // Validate context.
470         $context = context_system::instance();
471         self::validate_context($context);
473         $capability = 'moodle/site:manageallmessaging';
474         if (($USER->id != $userid) && !has_capability($capability, $context)) {
475             throw new required_capability_exception($context, $capability, 'nopermissions', '');
476         }
478         $params = array('userids' => $userids, 'userid' => $userid);
479         $params = self::validate_parameters(self::block_contacts_parameters(), $params);
481         $warnings = array();
482         foreach ($params['userids'] as $id) {
483             if (!message_block_contact($id, $userid)) {
484                 $warnings[] = array(
485                     'item' => 'user',
486                     'itemid' => $id,
487                     'warningcode' => 'contactnotblocked',
488                     'message' => 'The contact could not be blocked'
489                 );
490             }
491         }
492         return $warnings;
493     }
495     /**
496      * Block contacts return description.
497      *
498      * @deprecated since Moodle 3.6
499      * @return external_description
500      * @since Moodle 2.5
501      */
502     public static function block_contacts_returns() {
503         return new external_warnings();
504     }
506     /**
507      * Marking the method as deprecated.
508      *
509      * @return bool
510      */
511     public static function block_contacts_is_deprecated() {
512         return true;
513     }
515     /**
516      * Unblock contacts parameters description.
517      *
518      * @deprecated since Moodle 3.6
519      * @return external_function_parameters
520      * @since Moodle 2.5
521      */
522     public static function unblock_contacts_parameters() {
523         return new external_function_parameters(
524             array(
525                 'userids' => new external_multiple_structure(
526                     new external_value(PARAM_INT, 'User ID'),
527                     'List of user IDs'
528                 ),
529                 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
530                     current user', VALUE_DEFAULT, 0)
531             )
532         );
533     }
535     /**
536      * Unblock contacts.
537      *
538      * @param array $userids array of user IDs.
539      * @param int $userid The id of the user we are unblocking the contacts for
540      * @return null
541      * @since Moodle 2.5
542      */
543     public static function unblock_contacts($userids, $userid = 0) {
544         global $CFG, $USER;
546         // Check if messaging is enabled.
547         if (empty($CFG->messaging)) {
548             throw new moodle_exception('disabled', 'message');
549         }
551         if (empty($userid)) {
552             $userid = $USER->id;
553         }
555         // Validate context.
556         $context = context_system::instance();
557         self::validate_context($context);
559         $capability = 'moodle/site:manageallmessaging';
560         if (($USER->id != $userid) && !has_capability($capability, $context)) {
561             throw new required_capability_exception($context, $capability, 'nopermissions', '');
562         }
564         $params = array('userids' => $userids, 'userid' => $userid);
565         $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
567         foreach ($params['userids'] as $id) {
568             message_unblock_contact($id, $userid);
569         }
571         return null;
572     }
574     /**
575      * Unblock contacts return description.
576      *
577      * @deprecated since Moodle 3.6
578      * @return external_description
579      * @since Moodle 2.5
580      */
581     public static function unblock_contacts_returns() {
582         return null;
583     }
585     /**
586      * Marking the method as deprecated.
587      *
588      * @return bool
589      */
590     public static function unblock_contacts_is_deprecated() {
591         return true;
592     }
594     /**
595      * Returns contact requests parameters description.
596      *
597      * @return external_function_parameters
598      */
599     public static function get_contact_requests_parameters() {
600         return new external_function_parameters(
601             [
602                 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for')
603             ]
604         );
605     }
607     /**
608      * Handles returning the contact requests for a user.
609      *
610      * This also includes the user data necessary to display information
611      * about the user.
612      *
613      * It will not include blocked users.
614      *
615      * @param int $userid The id of the user we want to get the contact requests for
616      */
617     public static function get_contact_requests(int $userid) {
618         global $CFG, $USER;
620         // Check if messaging is enabled.
621         if (empty($CFG->messaging)) {
622             throw new moodle_exception('disabled', 'message');
623         }
625         // Validate context.
626         $context = context_system::instance();
627         self::validate_context($context);
629         $capability = 'moodle/site:manageallmessaging';
630         if (($USER->id != $userid) && !has_capability($capability, $context)) {
631             throw new required_capability_exception($context, $capability, 'nopermissions', '');
632         }
634         $params = ['userid' => $userid];
635         $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
637         return \core_message\api::get_contact_requests($params['userid']);
638     }
640     /**
641      * Returns the contact requests return description.
642      *
643      * @return external_description
644      */
645     public static function get_contact_requests_returns() {
646         return new external_multiple_structure(
647             new external_single_structure(
648                 [
649                     'id' => new external_value(core_user::get_property_type('id'), 'ID of the user'),
650                     'contactrequestid' => new external_value(PARAM_INT, 'The ID of the contact request'),
651                     'picture' => new external_value(core_user::get_property_type('picture'), 'The picture'),
652                     'firstname' => new external_value(core_user::get_property_type('firstname'),
653                         'The first name(s) of the user'),
654                     'lastname' => new external_value(core_user::get_property_type('lastname'),
655                         'The family name of the user'),
656                     'firstnamephonetic' => new external_value(core_user::get_property_type('firstnamephonetic'),
657                         'The phonetic first name of the user'),
658                     'lastnamephonetic' => new external_value(core_user::get_property_type('lastnamephonetic'),
659                         'The phonetic last name of the user'),
660                     'middlename' => new external_value(core_user::get_property_type('middlename'),
661                         'The middle name of the user'),
662                     'alternatename' => new external_value(core_user::get_property_type('alternatename'),
663                         'The alternate name of the user'),
664                     'email' => new external_value(core_user::get_property_type('email'), 'An email address')
665                 ]
666             )
667         );
668     }
670     /**
671      * Returns get conversation members parameters description.
672      *
673      * @return external_function_parameters
674      */
675     public static function get_conversation_members_parameters() {
676         return new external_function_parameters(
677             [
678                 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
679                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
680                 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
681                     VALUE_DEFAULT, false),
682                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
683                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
684             ]
685         );
686     }
688     /**
689      * Returns a list of conversation members.
690      *
691      * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
692      * @param int $conversationid The id of the conversation
693      * @param bool $includecontactrequests Do we want to include contact requests with this data?
694      * @param int $limitfrom
695      * @param int $limitnum
696      * @return array
697      */
698     public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
699                                                     int $limitfrom = 0, int $limitnum = 0) {
700         global $CFG, $USER;
702         // Check if messaging is enabled.
703         if (empty($CFG->messaging)) {
704             throw new moodle_exception('disabled', 'message');
705         }
707         // Validate context.
708         $context = context_system::instance();
709         self::validate_context($context);
711         $capability = 'moodle/site:manageallmessaging';
712         if (($USER->id != $userid) && !has_capability($capability, $context)) {
713             throw new required_capability_exception($context, $capability, 'nopermissions', '');
714         }
716         // The user needs to be a part of the conversation before querying who the members are.
717         if (!\core_message\api::is_user_in_conversation($userid, $conversationid)) {
718             throw new moodle_exception('You are not a member of this conversation.');
719         }
721         $params = [
722             'userid' => $userid,
723             'conversationid' => $conversationid,
724             'includecontactrequests' => $includecontactrequests,
725             'limitfrom' => $limitfrom,
726             'limitnum' => $limitnum
727         ];
728         self::validate_parameters(self::get_conversation_members_parameters(), $params);
730         return \core_message\api::get_conversation_members($userid, $conversationid, $includecontactrequests,
731             $limitfrom, $limitnum);
732     }
734     /**
735      * Returns the get conversation members return description.
736      *
737      * @return external_description
738      */
739     public static function get_conversation_members_returns() {
740         return new external_multiple_structure(
741             self::get_conversation_member_structure(true)
742         );
743     }
745     /**
746      * Creates a contact request parameters description.
747      *
748      * @return external_function_parameters
749      */
750     public static function create_contact_request_parameters() {
751         return new external_function_parameters(
752             [
753                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
754                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
755             ]
756         );
757     }
759     /**
760      * Creates a contact request.
761      *
762      * @param int $userid The id of the user who is creating the contact request
763      * @param int $requesteduserid The id of the user being requested
764      */
765     public static function create_contact_request(int $userid, int $requesteduserid) {
766         global $CFG, $USER;
768         // Check if messaging is enabled.
769         if (empty($CFG->messaging)) {
770             throw new moodle_exception('disabled', 'message');
771         }
773         // Validate context.
774         $context = context_system::instance();
775         self::validate_context($context);
777         $capability = 'moodle/site:manageallmessaging';
778         if (($USER->id != $userid) && !has_capability($capability, $context)) {
779             throw new required_capability_exception($context, $capability, 'nopermissions', '');
780         }
782         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
783         $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
785         if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
786             $warning[] = [
787                 'item' => 'user',
788                 'itemid' => $params['requesteduserid'],
789                 'warningcode' => 'cannotcreatecontactrequest',
790                 'message' => 'You are unable to create a contact request for this user'
791             ];
792             return $warning;
793         }
795         if (!\core_message\api::does_contact_request_exist($params['userid'], $params['requesteduserid'])) {
796             \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
797         }
799         return [];
800     }
802     /**
803      * Creates a contact request return description.
804      *
805      * @return external_description
806      */
807     public static function create_contact_request_returns() {
808         return new external_warnings();
809     }
811     /**
812      * Confirm a contact request parameters description.
813      *
814      * @return external_function_parameters
815      */
816     public static function confirm_contact_request_parameters() {
817         return new external_function_parameters(
818             [
819                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
820                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
821             ]
822         );
823     }
825     /**
826      * Confirm a contact request.
827      *
828      * @param int $userid The id of the user who is creating the contact request
829      * @param int $requesteduserid The id of the user being requested
830      */
831     public static function confirm_contact_request(int $userid, int $requesteduserid) {
832         global $CFG, $USER;
834         // Check if messaging is enabled.
835         if (empty($CFG->messaging)) {
836             throw new moodle_exception('disabled', 'message');
837         }
839         // Validate context.
840         $context = context_system::instance();
841         self::validate_context($context);
843         $capability = 'moodle/site:manageallmessaging';
844         if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
845             throw new required_capability_exception($context, $capability, 'nopermissions', '');
846         }
848         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
849         $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
851         \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
853         return [];
854     }
856     /**
857      * Confirm a contact request return description.
858      *
859      * @return external_description
860      */
861     public static function confirm_contact_request_returns() {
862         return new external_warnings();
863     }
865     /**
866      * Declines a contact request parameters description.
867      *
868      * @return external_function_parameters
869      */
870     public static function decline_contact_request_parameters() {
871         return new external_function_parameters(
872             [
873                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
874                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
875             ]
876         );
877     }
879     /**
880      * Declines a contact request.
881      *
882      * @param int $userid The id of the user who is creating the contact request
883      * @param int $requesteduserid The id of the user being requested
884      */
885     public static function decline_contact_request(int $userid, int $requesteduserid) {
886         global $CFG, $USER;
888         // Check if messaging is enabled.
889         if (empty($CFG->messaging)) {
890             throw new moodle_exception('disabled', 'message');
891         }
893         // Validate context.
894         $context = context_system::instance();
895         self::validate_context($context);
897         $capability = 'moodle/site:manageallmessaging';
898         if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
899             throw new required_capability_exception($context, $capability, 'nopermissions', '');
900         }
902         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
903         $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
905         \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
907         return [];
908     }
910     /**
911      * Declines a contact request return description.
912      *
913      * @return external_description
914      */
915     public static function decline_contact_request_returns() {
916         return new external_warnings();
917     }
919     /**
920      * Return the structure of a message area contact.
921      *
922      * @return external_single_structure
923      * @since Moodle 3.2
924      */
925     private static function get_messagearea_contact_structure() {
926         return new external_single_structure(
927             array(
928                 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
929                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
930                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
931                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
932                 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
933                 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
934                 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
935                 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
936                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
937                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
938                 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
939                 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
940                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
941                     VALUE_DEFAULT, null),
942             )
943         );
944     }
946     /**
947      * Return the structure of a conversation member.
948      *
949      * @param bool $includecontactrequests Are we including contact requests?
950      * @return external_single_structure
951      * @since Moodle 3.6
952      */
953     private static function get_conversation_member_structure(bool $includecontactrequests = false) {
954         $result = [
955             'id' => new external_value(PARAM_INT, 'The user id'),
956             'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
957             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
958             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
959             'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
960             'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
961             'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
962             'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
963         ];
965         if ($includecontactrequests) {
966             $result['contactrequests'] = new external_multiple_structure(
967                 new external_single_structure(
968                     [
969                         'id' => new external_value(PARAM_INT, 'The id of the message'),
970                         'userid' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
971                         'requesteduserid' => new external_value(PARAM_RAW, 'The text of the message'),
972                         'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
973                     ]
974                 ), 'The contact requests', VALUE_OPTIONAL
975             );
976         }
978         return new external_single_structure(
979             $result
980         );
981     }
983     /**
984      * Return the structure of a message area message.
985      *
986      * @return external_single_structure
987      * @since Moodle 3.6
988      */
989     private static function get_conversation_message_structure() {
990         return new external_single_structure(
991             array(
992                 'id' => new external_value(PARAM_INT, 'The id of the message'),
993                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
994                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
995                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
996             )
997         );
998     }
1000     /**
1001      * Return the structure of a message area message.
1002      *
1003      * @return external_single_structure
1004      * @since Moodle 3.2
1005      */
1006     private static function get_messagearea_message_structure() {
1007         return new external_single_structure(
1008             array(
1009                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1010                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1011                 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1012                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1013                 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1014                 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1015                 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1016                 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1017                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1018                 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1019             )
1020         );
1021     }
1023     /**
1024      * Get messagearea search users in course parameters.
1025      *
1026      * @return external_function_parameters
1027      * @since 3.2
1028      */
1029     public static function data_for_messagearea_search_users_in_course_parameters() {
1030         return new external_function_parameters(
1031             array(
1032                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1033                 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1034                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1035                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1036                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1037             )
1038         );
1039     }
1041     /**
1042      * Get messagearea search users in course results.
1043      *
1044      * @param int $userid The id of the user who is performing the search
1045      * @param int $courseid The id of the course
1046      * @param string $search The string being searched
1047      * @param int $limitfrom
1048      * @param int $limitnum
1049      * @return stdClass
1050      * @throws moodle_exception
1051      * @since 3.2
1052      */
1053     public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1054                                                                        $limitnum = 0) {
1055         global $CFG, $PAGE, $USER;
1057         // Check if messaging is enabled.
1058         if (empty($CFG->messaging)) {
1059             throw new moodle_exception('disabled', 'message');
1060         }
1062         $systemcontext = context_system::instance();
1064         $params = array(
1065             'userid' => $userid,
1066             'courseid' => $courseid,
1067             'search' => $search,
1068             'limitfrom' => $limitfrom,
1069             'limitnum' => $limitnum
1070         );
1071         self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1072         self::validate_context($systemcontext);
1074         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1075             throw new moodle_exception('You do not have permission to perform this action.');
1076         }
1078         $users = \core_message\api::search_users_in_course($userid, $courseid, $search, $limitfrom, $limitnum);
1079         $results = new \core_message\output\messagearea\user_search_results($users);
1081         $renderer = $PAGE->get_renderer('core_message');
1082         return $results->export_for_template($renderer);
1083     }
1085     /**
1086      * Get messagearea search users in course returns.
1087      *
1088      * @return external_single_structure
1089      * @since 3.2
1090      */
1091     public static function data_for_messagearea_search_users_in_course_returns() {
1092         return new external_single_structure(
1093             array(
1094                 'contacts' => new external_multiple_structure(
1095                     self::get_messagearea_contact_structure()
1096                 ),
1097             )
1098         );
1099     }
1101     /**
1102      * Get messagearea search users parameters.
1103      *
1104      * @return external_function_parameters
1105      * @since 3.2
1106      */
1107     public static function data_for_messagearea_search_users_parameters() {
1108         return new external_function_parameters(
1109             array(
1110                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1111                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1112                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1113             )
1114         );
1115     }
1117     /**
1118      * Get messagearea search users results.
1119      *
1120      * @param int $userid The id of the user who is performing the search
1121      * @param string $search The string being searched
1122      * @param int $limitnum
1123      * @return stdClass
1124      * @throws moodle_exception
1125      * @since 3.2
1126      */
1127     public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1128         global $CFG, $PAGE, $USER;
1130         // Check if messaging is enabled.
1131         if (empty($CFG->messaging)) {
1132             throw new moodle_exception('disabled', 'message');
1133         }
1135         $systemcontext = context_system::instance();
1137         $params = array(
1138             'userid' => $userid,
1139             'search' => $search,
1140             'limitnum' => $limitnum
1141         );
1142         self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1143         self::validate_context($systemcontext);
1145         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1146             throw new moodle_exception('You do not have permission to perform this action.');
1147         }
1149         list($contacts, $courses, $noncontacts) = \core_message\api::search_users($userid, $search, $limitnum);
1150         $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1152         $renderer = $PAGE->get_renderer('core_message');
1153         return $search->export_for_template($renderer);
1154     }
1156     /**
1157      * Get messagearea search users returns.
1158      *
1159      * @return external_single_structure
1160      * @since 3.2
1161      */
1162     public static function data_for_messagearea_search_users_returns() {
1163         return new external_single_structure(
1164             array(
1165                 'contacts' => new external_multiple_structure(
1166                     self::get_messagearea_contact_structure()
1167                 ),
1168                 'courses' => new external_multiple_structure(
1169                     new external_single_structure(
1170                         array(
1171                             'id' => new external_value(PARAM_INT, 'The course id'),
1172                             'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1173                             'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1174                         )
1175                     )
1176                 ),
1177                 'noncontacts' => new external_multiple_structure(
1178                     self::get_messagearea_contact_structure()
1179                 )
1180             )
1181         );
1182     }
1184     /**
1185      * Get messagearea search messages parameters.
1186      *
1187      * @return external_function_parameters
1188      * @since 3.2
1189      */
1190     public static function data_for_messagearea_search_messages_parameters() {
1191         return new external_function_parameters(
1192             array(
1193                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1194                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1195                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1196                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1197             )
1198         );
1199     }
1201     /**
1202      * Get messagearea search messages results.
1203      *
1204      * @param int $userid The id of the user who is performing the search
1205      * @param string $search The string being searched
1206      * @param int $limitfrom
1207      * @param int $limitnum
1208      * @return stdClass
1209      * @throws moodle_exception
1210      * @since 3.2
1211      */
1212     public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1213         global $CFG, $PAGE, $USER;
1215         // Check if messaging is enabled.
1216         if (empty($CFG->messaging)) {
1217             throw new moodle_exception('disabled', 'message');
1218         }
1220         $systemcontext = context_system::instance();
1222         $params = array(
1223             'userid' => $userid,
1224             'search' => $search,
1225             'limitfrom' => $limitfrom,
1226             'limitnum' => $limitnum
1228         );
1229         self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1230         self::validate_context($systemcontext);
1232         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1233             throw new moodle_exception('You do not have permission to perform this action.');
1234         }
1236         $messages = \core_message\api::search_messages($userid, $search, $limitfrom, $limitnum);
1237         $results = new \core_message\output\messagearea\message_search_results($messages);
1239         $renderer = $PAGE->get_renderer('core_message');
1240         return $results->export_for_template($renderer);
1241     }
1243     /**
1244      * Get messagearea search messages returns.
1245      *
1246      * @return external_single_structure
1247      * @since 3.2
1248      */
1249     public static function data_for_messagearea_search_messages_returns() {
1250         return new external_single_structure(
1251             array(
1252                 'contacts' => new external_multiple_structure(
1253                     self::get_messagearea_contact_structure()
1254                 )
1255             )
1256         );
1257     }
1259     /**
1260      * The messagearea conversations parameters.
1261      *
1262      * @return external_function_parameters
1263      * @since 3.2
1264      */
1265     public static function data_for_messagearea_conversations_parameters() {
1266         return new external_function_parameters(
1267             array(
1268                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1269                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1270                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1271             )
1272         );
1273     }
1275     /**
1276      * Get messagearea conversations.
1277      *
1278      * @param int $userid The id of the user who we are viewing conversations for
1279      * @param int $limitfrom
1280      * @param int $limitnum
1281      * @return stdClass
1282      * @throws moodle_exception
1283      * @since 3.2
1284      */
1285     public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1286         global $CFG, $PAGE, $USER;
1288         // Check if messaging is enabled.
1289         if (empty($CFG->messaging)) {
1290             throw new moodle_exception('disabled', 'message');
1291         }
1293         $systemcontext = context_system::instance();
1295         $params = array(
1296             'userid' => $userid,
1297             'limitfrom' => $limitfrom,
1298             'limitnum' => $limitnum
1299         );
1300         self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1301         self::validate_context($systemcontext);
1303         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1304             throw new moodle_exception('You do not have permission to perform this action.');
1305         }
1307         $conversations = \core_message\api::get_conversations($userid, $limitfrom, $limitnum);
1308         $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1310         $renderer = $PAGE->get_renderer('core_message');
1311         return $conversations->export_for_template($renderer);
1312     }
1314     /**
1315      * The messagearea conversations return structure.
1316      *
1317      * @return external_single_structure
1318      * @since 3.2
1319      */
1320     public static function data_for_messagearea_conversations_returns() {
1321         return new external_single_structure(
1322             array(
1323                 'contacts' => new external_multiple_structure(
1324                     self::get_messagearea_contact_structure()
1325                 )
1326             )
1327         );
1328     }
1330     /**
1331      * The messagearea contacts return parameters.
1332      *
1333      * @return external_function_parameters
1334      * @since 3.2
1335      */
1336     public static function data_for_messagearea_contacts_parameters() {
1337         return self::data_for_messagearea_conversations_parameters();
1338     }
1340     /**
1341      * Get messagearea contacts parameters.
1342      *
1343      * @param int $userid The id of the user who we are viewing conversations for
1344      * @param int $limitfrom
1345      * @param int $limitnum
1346      * @return stdClass
1347      * @throws moodle_exception
1348      * @since 3.2
1349      */
1350     public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1351         global $CFG, $PAGE, $USER;
1353         // Check if messaging is enabled.
1354         if (empty($CFG->messaging)) {
1355             throw new moodle_exception('disabled', 'message');
1356         }
1358         $systemcontext = context_system::instance();
1360         $params = array(
1361             'userid' => $userid,
1362             'limitfrom' => $limitfrom,
1363             'limitnum' => $limitnum
1364         );
1365         self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1366         self::validate_context($systemcontext);
1368         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1369             throw new moodle_exception('You do not have permission to perform this action.');
1370         }
1372         $contacts = \core_message\api::get_contacts($userid, $limitfrom, $limitnum);
1373         $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1375         $renderer = $PAGE->get_renderer('core_message');
1376         return $contacts->export_for_template($renderer);
1377     }
1379     /**
1380      * The messagearea contacts return structure.
1381      *
1382      * @return external_single_structure
1383      * @since 3.2
1384      */
1385     public static function data_for_messagearea_contacts_returns() {
1386         return self::data_for_messagearea_conversations_returns();
1387     }
1389     /**
1390      * The messagearea messages parameters.
1391      *
1392      * @return external_function_parameters
1393      * @since 3.2
1394      */
1395     public static function data_for_messagearea_messages_parameters() {
1396         return new external_function_parameters(
1397             array(
1398                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1399                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1400                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1401                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1402                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1403                 'timefrom' => new external_value(PARAM_INT,
1404                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1405             )
1406         );
1407     }
1409     /**
1410      * Get messagearea messages.
1411      *
1412      * @param int $currentuserid The current user's id
1413      * @param int $otheruserid The other user's id
1414      * @param int $limitfrom
1415      * @param int $limitnum
1416      * @param boolean $newest
1417      * @return stdClass
1418      * @throws moodle_exception
1419      * @since 3.2
1420      */
1421     public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1422                                                          $newest = false, $timefrom = 0) {
1423         global $CFG, $PAGE, $USER;
1425         // Check if messaging is enabled.
1426         if (empty($CFG->messaging)) {
1427             throw new moodle_exception('disabled', 'message');
1428         }
1430         $systemcontext = context_system::instance();
1432         $params = array(
1433             'currentuserid' => $currentuserid,
1434             'otheruserid' => $otheruserid,
1435             'limitfrom' => $limitfrom,
1436             'limitnum' => $limitnum,
1437             'newest' => $newest,
1438             'timefrom' => $timefrom,
1439         );
1440         self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1441         self::validate_context($systemcontext);
1443         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1444             throw new moodle_exception('You do not have permission to perform this action.');
1445         }
1447         if ($newest) {
1448             $sort = 'timecreated DESC';
1449         } else {
1450             $sort = 'timecreated ASC';
1451         }
1453         // We need to enforce a one second delay on messages to avoid race conditions of current
1454         // messages still being sent.
1455         //
1456         // There is a chance that we could request messages before the current time's
1457         // second has elapsed and while other messages are being sent in that same second. In which
1458         // case those messages will be lost.
1459         //
1460         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1461         if (!empty($timefrom)) {
1462             $timeto = time() - 1;
1463         } else {
1464             $timeto = 0;
1465         }
1467         // No requesting messages from the current time, as stated above.
1468         if ($timefrom == time()) {
1469             $messages = [];
1470         } else {
1471             $messages = \core_message\api::get_messages($currentuserid, $otheruserid, $limitfrom,
1472                                                         $limitnum, $sort, $timefrom, $timeto);
1473         }
1475         $messages = new \core_message\output\messagearea\messages($currentuserid, $otheruserid, $messages);
1477         $renderer = $PAGE->get_renderer('core_message');
1478         return $messages->export_for_template($renderer);
1479     }
1481     /**
1482      * The messagearea messages return structure.
1483      *
1484      * @return external_single_structure
1485      * @since 3.2
1486      */
1487     public static function data_for_messagearea_messages_returns() {
1488         return new external_single_structure(
1489             array(
1490                 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1491                     the messages on behalf of?'),
1492                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1493                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1494                 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1495                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1496                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1497                 'messages' => new external_multiple_structure(
1498                     self::get_messagearea_message_structure()
1499                 ),
1500                 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1501             )
1502         );
1503     }
1505     /**
1506      * The conversation messages parameters.
1507      *
1508      * @return external_function_parameters
1509      * @since 3.6
1510      */
1511     public static function get_conversation_messages_parameters() {
1512         return new external_function_parameters(
1513             array(
1514                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1515                 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1516                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1517                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1518                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1519                 'timefrom' => new external_value(PARAM_INT,
1520                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1521             )
1522         );
1523     }
1525     /**
1526      * Get conversation messages.
1527      *
1528      * @param  int $currentuserid The current user's id.
1529      * @param  int $convid The conversation id.
1530      * @param  int $limitfrom Return a subset of records, starting at this point (optional).
1531      * @param  int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1532      * @param  bool $newest True for getting first newest messages, false otherwise.
1533      * @param  int  $timefrom The time from the conversation messages to get.
1534      * @return stdClass The messages and members who have sent some of these messages.
1535      * @throws moodle_exception
1536      * @since 3.6
1537      */
1538     public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1539                                                          bool $newest = false, int $timefrom = 0) {
1540         global $CFG, $PAGE, $USER;
1542         // Check if messaging is enabled.
1543         if (empty($CFG->messaging)) {
1544             throw new moodle_exception('disabled', 'message');
1545         }
1547         $systemcontext = context_system::instance();
1549         $params = array(
1550             'currentuserid' => $currentuserid,
1551             'convid' => $convid,
1552             'limitfrom' => $limitfrom,
1553             'limitnum' => $limitnum,
1554             'newest' => $newest,
1555             'timefrom' => $timefrom,
1556         );
1557         self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1558         self::validate_context($systemcontext);
1560         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1561             throw new moodle_exception('You do not have permission to perform this action.');
1562         }
1564         $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1566         // We need to enforce a one second delay on messages to avoid race conditions of current
1567         // messages still being sent.
1568         //
1569         // There is a chance that we could request messages before the current time's
1570         // second has elapsed and while other messages are being sent in that same second. In which
1571         // case those messages will be lost.
1572         //
1573         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1574         $timeto = empty($timefrom) ? 0 : time() - 1;
1576         // No requesting messages from the current time, as stated above.
1577         if ($timefrom == time()) {
1578             $messages = [];
1579         } else {
1580             $messages = \core_message\api::get_conversation_messages($currentuserid, $convid, $limitfrom,
1581                                                         $limitnum, $sort, $timefrom, $timeto);
1582         }
1584         return $messages;
1585     }
1587     /**
1588      * The messagearea messages return structure.
1589      *
1590      * @return external_single_structure
1591      * @since 3.6
1592      */
1593     public static function get_conversation_messages_returns() {
1594         return new external_single_structure(
1595             array(
1596                 'id' => new external_value(PARAM_INT, 'The conversation id'),
1597                 'members' => new external_multiple_structure(
1598                     self::get_conversation_member_structure()
1599                 ),
1600                 'messages' => new external_multiple_structure(
1601                     self::get_conversation_message_structure()
1602                 ),
1603             )
1604         );
1605     }
1607     /**
1608      * The get most recent message return parameters.
1609      *
1610      * @return external_function_parameters
1611      * @since 3.2
1612      */
1613     public static function data_for_messagearea_get_most_recent_message_parameters() {
1614         return new external_function_parameters(
1615             array(
1616                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1617                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1618             )
1619         );
1620     }
1622     /**
1623      * Get the most recent message in a conversation.
1624      *
1625      * @param int $currentuserid The current user's id
1626      * @param int $otheruserid The other user's id
1627      * @return stdClass
1628      * @throws moodle_exception
1629      * @since 3.2
1630      */
1631     public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
1632         global $CFG, $PAGE, $USER;
1634         // Check if messaging is enabled.
1635         if (empty($CFG->messaging)) {
1636             throw new moodle_exception('disabled', 'message');
1637         }
1639         $systemcontext = context_system::instance();
1641         $params = array(
1642             'currentuserid' => $currentuserid,
1643             'otheruserid' => $otheruserid
1644         );
1645         self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
1646         self::validate_context($systemcontext);
1648         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1649             throw new moodle_exception('You do not have permission to perform this action.');
1650         }
1652         $message = \core_message\api::get_most_recent_message($currentuserid, $otheruserid);
1653         $message = new \core_message\output\messagearea\message($message);
1655         $renderer = $PAGE->get_renderer('core_message');
1656         return $message->export_for_template($renderer);
1657     }
1659     /**
1660      * The get most recent message return structure.
1661      *
1662      * @return external_single_structure
1663      * @since 3.2
1664      */
1665     public static function data_for_messagearea_get_most_recent_message_returns() {
1666         return self::get_messagearea_message_structure();
1667     }
1669     /**
1670      * The get profile parameters.
1671      *
1672      * @return external_function_parameters
1673      * @since 3.2
1674      */
1675     public static function data_for_messagearea_get_profile_parameters() {
1676         return new external_function_parameters(
1677             array(
1678                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1679                 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
1680             )
1681         );
1682     }
1684     /**
1685      * Get the profile information for a contact.
1686      *
1687      * @param int $currentuserid The current user's id
1688      * @param int $otheruserid The id of the user whose profile we are viewing
1689      * @return stdClass
1690      * @throws moodle_exception
1691      * @since 3.2
1692      */
1693     public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
1694         global $CFG, $PAGE, $USER;
1696         // Check if messaging is enabled.
1697         if (empty($CFG->messaging)) {
1698             throw new moodle_exception('disabled', 'message');
1699         }
1701         $systemcontext = context_system::instance();
1703         $params = array(
1704             'currentuserid' => $currentuserid,
1705             'otheruserid' => $otheruserid
1706         );
1707         self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
1708         self::validate_context($systemcontext);
1710         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1711             throw new moodle_exception('You do not have permission to perform this action.');
1712         }
1714         $profile = \core_message\api::get_profile($currentuserid, $otheruserid);
1715         $profile = new \core_message\output\messagearea\profile($profile);
1717         $renderer = $PAGE->get_renderer('core_message');
1718         return $profile->export_for_template($renderer);
1719     }
1721     /**
1722      * The get profile return structure.
1723      *
1724      * @return external_single_structure
1725      * @since 3.2
1726      */
1727     public static function data_for_messagearea_get_profile_returns() {
1728         return new external_single_structure(
1729             array(
1730                 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
1731                 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
1732                 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
1733                 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
1734                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1735                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1736                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1737                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1738                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1739                 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
1740                 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
1741             )
1742         );
1743     }
1745     /**
1746      * Get contacts parameters description.
1747      *
1748      * @return external_function_parameters
1749      * @since Moodle 2.5
1750      */
1751     public static function get_contacts_parameters() {
1752         return new external_function_parameters(array());
1753     }
1755     /**
1756      * Get contacts.
1757      *
1758      * @return external_description
1759      * @since Moodle 2.5
1760      */
1761     public static function get_contacts() {
1762         global $CFG, $PAGE, $USER;
1764         // Check if messaging is enabled.
1765         if (empty($CFG->messaging)) {
1766             throw new moodle_exception('disabled', 'message');
1767         }
1769         require_once($CFG->dirroot . '/user/lib.php');
1771         $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
1772         $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
1773         foreach ($contacts as $contact) {
1774             // Set the mode.
1775             $mode = 'offline';
1776             if (\core_message\helper::is_online($contact->lastaccess)) {
1777                 $mode = 'online';
1778             }
1780             $newcontact = array(
1781                 'id' => $contact->id,
1782                 'fullname' => fullname($contact),
1783                 'unread' => $contact->messagecount
1784             );
1786             $userpicture = new user_picture($contact);
1787             $userpicture->size = 1; // Size f1.
1788             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1789             $userpicture->size = 0; // Size f2.
1790             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1792             $allcontacts[$mode][$contact->id] = $newcontact;
1793         }
1795         $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
1796         foreach ($strangers as $contact) {
1797             $newcontact = array(
1798                 'id' => $contact->id,
1799                 'fullname' => fullname($contact),
1800                 'unread' => $contact->messagecount
1801             );
1803             $userpicture = new user_picture($contact);
1804             $userpicture->size = 1; // Size f1.
1805             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1806             $userpicture->size = 0; // Size f2.
1807             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1809             $allcontacts['strangers'][$contact->id] = $newcontact;
1810         }
1812         // Add noreply user and support user to the list, if they don't exist.
1813         $supportuser = core_user::get_support_user();
1814         if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
1815             $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
1816             if ($supportuser->messagecount > 0) {
1817                 $supportuser->fullname = fullname($supportuser);
1818                 $supportuser->unread = $supportuser->messagecount;
1819                 $allcontacts['strangers'][$supportuser->id] = $supportuser;
1820             }
1821         }
1823         $noreplyuser = core_user::get_noreply_user();
1824         if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
1825             $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
1826             if ($noreplyuser->messagecount > 0) {
1827                 $noreplyuser->fullname = fullname($noreplyuser);
1828                 $noreplyuser->unread = $noreplyuser->messagecount;
1829                 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
1830             }
1831         }
1833         return $allcontacts;
1834     }
1836     /**
1837      * Get contacts return description.
1838      *
1839      * @return external_description
1840      * @since Moodle 2.5
1841      */
1842     public static function get_contacts_returns() {
1843         return new external_single_structure(
1844             array(
1845                 'online' => new external_multiple_structure(
1846                     new external_single_structure(
1847                         array(
1848                             'id' => new external_value(PARAM_INT, 'User ID'),
1849                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1850                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1851                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1852                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1853                         )
1854                     ),
1855                     'List of online contacts'
1856                 ),
1857                 'offline' => new external_multiple_structure(
1858                     new external_single_structure(
1859                         array(
1860                             'id' => new external_value(PARAM_INT, 'User ID'),
1861                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1862                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1863                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1864                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1865                         )
1866                     ),
1867                     'List of offline contacts'
1868                 ),
1869                 'strangers' => new external_multiple_structure(
1870                     new external_single_structure(
1871                         array(
1872                             'id' => new external_value(PARAM_INT, 'User ID'),
1873                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1874                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1875                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1876                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1877                         )
1878                     ),
1879                     'List of users that are not in the user\'s contact list but have sent a message'
1880                 )
1881             )
1882         );
1883     }
1885     /**
1886      * Search contacts parameters description.
1887      *
1888      * @return external_function_parameters
1889      * @since Moodle 2.5
1890      */
1891     public static function search_contacts_parameters() {
1892         return new external_function_parameters(
1893             array(
1894                 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1895                 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1896                     VALUE_DEFAULT, false)
1897             )
1898         );
1899     }
1901     /**
1902      * Search contacts.
1903      *
1904      * @param string $searchtext query string.
1905      * @param bool $onlymycourses limit the search to the user's courses only.
1906      * @return external_description
1907      * @since Moodle 2.5
1908      */
1909     public static function search_contacts($searchtext, $onlymycourses = false) {
1910         global $CFG, $USER, $PAGE;
1911         require_once($CFG->dirroot . '/user/lib.php');
1913         // Check if messaging is enabled.
1914         if (empty($CFG->messaging)) {
1915             throw new moodle_exception('disabled', 'message');
1916         }
1918         require_once($CFG->libdir . '/enrollib.php');
1920         $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1921         $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1923         // Extra validation, we do not allow empty queries.
1924         if ($params['searchtext'] === '') {
1925             throw new moodle_exception('querystringcannotbeempty');
1926         }
1928         $courseids = array();
1929         if ($params['onlymycourses']) {
1930             $mycourses = enrol_get_my_courses(array('id'));
1931             foreach ($mycourses as $mycourse) {
1932                 $courseids[] = $mycourse->id;
1933             }
1934         } else {
1935             $courseids[] = SITEID;
1936         }
1938         // Retrieving the users matching the query.
1939         $users = message_search_users($courseids, $params['searchtext']);
1940         $results = array();
1941         foreach ($users as $user) {
1942             $results[$user->id] = $user;
1943         }
1945         // Reorganising information.
1946         foreach ($results as &$user) {
1947             $newuser = array(
1948                 'id' => $user->id,
1949                 'fullname' => fullname($user)
1950             );
1952             // Avoid undefined property notice as phone not specified.
1953             $user->phone1 = null;
1954             $user->phone2 = null;
1956             $userpicture = new user_picture($user);
1957             $userpicture->size = 1; // Size f1.
1958             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1959             $userpicture->size = 0; // Size f2.
1960             $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1962             $user = $newuser;
1963         }
1965         return $results;
1966     }
1968     /**
1969      * Search contacts return description.
1970      *
1971      * @return external_description
1972      * @since Moodle 2.5
1973      */
1974     public static function search_contacts_returns() {
1975         return new external_multiple_structure(
1976             new external_single_structure(
1977                 array(
1978                     'id' => new external_value(PARAM_INT, 'User ID'),
1979                     'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1980                     'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1981                     'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1982                 )
1983             ),
1984             'List of contacts'
1985         );
1986     }
1988     /**
1989      * Get messages parameters description.
1990      *
1991      * @return external_function_parameters
1992      * @since 2.8
1993      */
1994     public static function get_messages_parameters() {
1995         return new external_function_parameters(
1996             array(
1997                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1998                 'useridfrom' => new external_value(
1999                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2000                     VALUE_DEFAULT, 0),
2001                 'type' => new external_value(
2002                     PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2003                     VALUE_DEFAULT, 'both'),
2004                 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2005                 'newestfirst' => new external_value(
2006                     PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2007                     VALUE_DEFAULT, true),
2008                 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2009                 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2010             )
2011         );
2012     }
2014     /**
2015      * Get messages function implementation.
2016      *
2017      * @since  2.8
2018      * @throws invalid_parameter_exception
2019      * @throws moodle_exception
2020      * @param  int      $useridto       the user id who received the message
2021      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2022      * @param  string   $type           type of message to return, expected values: notifications, conversations and both
2023      * @param  bool     $read           true for retreiving read messages, false for unread
2024      * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
2025      * @param  int      $limitfrom      limit from
2026      * @param  int      $limitnum       limit num
2027      * @return external_description
2028      */
2029     public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2030                                         $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2031         global $CFG, $USER;
2033         $warnings = array();
2035         $params = array(
2036             'useridto' => $useridto,
2037             'useridfrom' => $useridfrom,
2038             'type' => $type,
2039             'read' => $read,
2040             'newestfirst' => $newestfirst,
2041             'limitfrom' => $limitfrom,
2042             'limitnum' => $limitnum
2043         );
2045         $params = self::validate_parameters(self::get_messages_parameters(), $params);
2047         $context = context_system::instance();
2048         self::validate_context($context);
2050         $useridto = $params['useridto'];
2051         $useridfrom = $params['useridfrom'];
2052         $type = $params['type'];
2053         $read = $params['read'];
2054         $newestfirst = $params['newestfirst'];
2055         $limitfrom = $params['limitfrom'];
2056         $limitnum = $params['limitnum'];
2058         $allowedvalues = array('notifications', 'conversations', 'both');
2059         if (!in_array($type, $allowedvalues)) {
2060             throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2061                 'allowed values are: ' . implode(',', $allowedvalues));
2062         }
2064         // Check if private messaging between users is allowed.
2065         if (empty($CFG->messaging)) {
2066             // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2067             if ($type == "conversations") {
2068                 throw new moodle_exception('disabled', 'message');
2069             }
2070             if ($type == "both") {
2071                 $warning = array();
2072                 $warning['item'] = 'message';
2073                 $warning['itemid'] = $USER->id;
2074                 $warning['warningcode'] = '1';
2075                 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2076                     Only notifications will be returned';
2077                 $warnings[] = $warning;
2078             }
2079         }
2081         if (!empty($useridto)) {
2082             if (core_user::is_real_user($useridto)) {
2083                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2084             } else {
2085                 throw new moodle_exception('invaliduser');
2086             }
2087         }
2089         if (!empty($useridfrom)) {
2090             // We use get_user here because the from user can be the noreply or support user.
2091             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2092         }
2094         // Check if the current user is the sender/receiver or just a privileged user.
2095         if ($useridto != $USER->id and $useridfrom != $USER->id and
2096              !has_capability('moodle/site:readallmessages', $context)) {
2097             throw new moodle_exception('accessdenied', 'admin');
2098         }
2100         // Which type of messages to retrieve.
2101         $notifications = -1;
2102         if ($type != 'both') {
2103             $notifications = ($type == 'notifications') ? 1 : 0;
2104         }
2106         $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2107         $sort = "mr.timecreated $orderdirection";
2109         if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2110             $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2112             // In some cases, we don't need to get the to/from user objects from the sql query.
2113             $userfromfullname = '';
2114             $usertofullname = '';
2116             // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2117             if (!empty($useridto)) {
2118                 $usertofullname = fullname($userto, $canviewfullname);
2119                 // The user from may or may not be filled.
2120                 if (!empty($useridfrom)) {
2121                     $userfromfullname = fullname($userfrom, $canviewfullname);
2122                 }
2123             } else {
2124                 // If the useridto field is empty, the useridfrom must be filled.
2125                 $userfromfullname = fullname($userfrom, $canviewfullname);
2126             }
2127             foreach ($messages as $mid => $message) {
2129                 // Do not return deleted messages.
2130                 if (!$message->notification) {
2131                     if (($useridto == $USER->id and $message->timeusertodeleted) or
2132                         ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2133                         unset($messages[$mid]);
2134                         continue;
2135                     }
2136                 }
2138                 // We need to get the user from the query.
2139                 if (empty($userfromfullname)) {
2140                     // Check for non-reply and support users.
2141                     if (core_user::is_real_user($message->useridfrom)) {
2142                         $user = new stdClass();
2143                         $user = username_load_fields_from_object($user, $message, 'userfrom');
2144                         $message->userfromfullname = fullname($user, $canviewfullname);
2145                     } else {
2146                         $user = core_user::get_user($message->useridfrom);
2147                         $message->userfromfullname = fullname($user, $canviewfullname);
2148                     }
2149                 } else {
2150                     $message->userfromfullname = $userfromfullname;
2151                 }
2153                 // We need to get the user from the query.
2154                 if (empty($usertofullname)) {
2155                     $user = new stdClass();
2156                     $user = username_load_fields_from_object($user, $message, 'userto');
2157                     $message->usertofullname = fullname($user, $canviewfullname);
2158                 } else {
2159                     $message->usertofullname = $usertofullname;
2160                 }
2162                 $message->text = message_format_message_text($message);
2163                 $messages[$mid] = (array) $message;
2164             }
2165         }
2167         $results = array(
2168             'messages' => $messages,
2169             'warnings' => $warnings
2170         );
2172         return $results;
2173     }
2175     /**
2176      * Get messages return description.
2177      *
2178      * @return external_single_structure
2179      * @since 2.8
2180      */
2181     public static function get_messages_returns() {
2182         return new external_single_structure(
2183             array(
2184                 'messages' => new external_multiple_structure(
2185                     new external_single_structure(
2186                         array(
2187                             'id' => new external_value(PARAM_INT, 'Message id'),
2188                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2189                             'useridto' => new external_value(PARAM_INT, 'User to id'),
2190                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2191                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
2192                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2193                             'fullmessageformat' => new external_format_value('fullmessage'),
2194                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2195                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2196                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2197                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2198                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2199                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
2200                             'timeread' => new external_value(PARAM_INT, 'Time read'),
2201                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2202                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2203                         ), 'message'
2204                     )
2205                 ),
2206                 'warnings' => new external_warnings()
2207             )
2208         );
2209     }
2211     /**
2212      * Mark all notifications as read parameters description.
2213      *
2214      * @return external_function_parameters
2215      * @since 3.2
2216      */
2217     public static function mark_all_notifications_as_read_parameters() {
2218         return new external_function_parameters(
2219             array(
2220                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2221                 'useridfrom' => new external_value(
2222                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2223                     VALUE_DEFAULT, 0),
2224             )
2225         );
2226     }
2228     /**
2229      * Mark all notifications as read function.
2230      *
2231      * @since  3.2
2232      * @throws invalid_parameter_exception
2233      * @throws moodle_exception
2234      * @param  int      $useridto       the user id who received the message
2235      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2236      * @return external_description
2237      */
2238     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2239         global $USER;
2241         $params = self::validate_parameters(
2242             self::mark_all_notifications_as_read_parameters(),
2243             array(
2244                 'useridto' => $useridto,
2245                 'useridfrom' => $useridfrom,
2246             )
2247         );
2249         $context = context_system::instance();
2250         self::validate_context($context);
2252         $useridto = $params['useridto'];
2253         $useridfrom = $params['useridfrom'];
2255         if (!empty($useridto)) {
2256             if (core_user::is_real_user($useridto)) {
2257                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2258             } else {
2259                 throw new moodle_exception('invaliduser');
2260             }
2261         }
2263         if (!empty($useridfrom)) {
2264             // We use get_user here because the from user can be the noreply or support user.
2265             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2266         }
2268         // Check if the current user is the sender/receiver or just a privileged user.
2269         if ($useridto != $USER->id and $useridfrom != $USER->id and
2270             // The deleteanymessage cap seems more reasonable here than readallmessages.
2271              !has_capability('moodle/site:deleteanymessage', $context)) {
2272             throw new moodle_exception('accessdenied', 'admin');
2273         }
2275         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2277         return true;
2278     }
2280     /**
2281      * Mark all notifications as read return description.
2282      *
2283      * @return external_single_structure
2284      * @since 3.2
2285      */
2286     public static function mark_all_notifications_as_read_returns() {
2287         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2288     }
2290     /**
2291      * Get unread conversations count parameters description.
2292      *
2293      * @return external_function_parameters
2294      * @since 3.2
2295      */
2296     public static function get_unread_conversations_count_parameters() {
2297         return new external_function_parameters(
2298             array(
2299                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2300             )
2301         );
2302     }
2304     /**
2305      * Get unread messages count function.
2306      *
2307      * @since  3.2
2308      * @throws invalid_parameter_exception
2309      * @throws moodle_exception
2310      * @param  int      $useridto       the user id who received the message
2311      * @return external_description
2312      */
2313     public static function get_unread_conversations_count($useridto) {
2314         global $USER, $CFG;
2316         // Check if messaging is enabled.
2317         if (empty($CFG->messaging)) {
2318             throw new moodle_exception('disabled', 'message');
2319         }
2321         $params = self::validate_parameters(
2322             self::get_unread_conversations_count_parameters(),
2323             array('useridto' => $useridto)
2324         );
2326         $context = context_system::instance();
2327         self::validate_context($context);
2329         $useridto = $params['useridto'];
2331         if (!empty($useridto)) {
2332             if (core_user::is_real_user($useridto)) {
2333                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2334             } else {
2335                 throw new moodle_exception('invaliduser');
2336             }
2337         } else {
2338             $useridto = $USER->id;
2339         }
2341         // Check if the current user is the receiver or just a privileged user.
2342         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2343             throw new moodle_exception('accessdenied', 'admin');
2344         }
2346         return \core_message\api::count_unread_conversations($userto);
2347     }
2349     /**
2350      * Get unread conversations count return description.
2351      *
2352      * @return external_single_structure
2353      * @since 3.2
2354      */
2355     public static function get_unread_conversations_count_returns() {
2356         return new external_value(PARAM_INT, 'The count of unread messages for the user');
2357     }
2359     /**
2360      * Get blocked users parameters description.
2361      *
2362      * @return external_function_parameters
2363      * @since 2.9
2364      */
2365     public static function get_blocked_users_parameters() {
2366         return new external_function_parameters(
2367             array(
2368                 'userid' => new external_value(PARAM_INT,
2369                                 'the user whose blocked users we want to retrieve',
2370                                 VALUE_REQUIRED),
2371             )
2372         );
2373     }
2375     /**
2376      * Retrieve a list of users blocked
2377      *
2378      * @param  int $userid the user whose blocked users we want to retrieve
2379      * @return external_description
2380      * @since 2.9
2381      */
2382     public static function get_blocked_users($userid) {
2383         global $CFG, $USER, $PAGE;
2385         // Warnings array, it can be empty at the end but is mandatory.
2386         $warnings = array();
2388         // Validate params.
2389         $params = array(
2390             'userid' => $userid
2391         );
2392         $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2393         $userid = $params['userid'];
2395         // Validate context.
2396         $context = context_system::instance();
2397         self::validate_context($context);
2399         // Check if private messaging between users is allowed.
2400         if (empty($CFG->messaging)) {
2401             throw new moodle_exception('disabled', 'message');
2402         }
2404         $user = core_user::get_user($userid, '*', MUST_EXIST);
2405         core_user::require_active_user($user);
2407         // Check if we have permissions for retrieve the information.
2408         $capability = 'moodle/site:manageallmessaging';
2409         if (($USER->id != $userid) && !has_capability($capability, $context)) {
2410             throw new required_capability_exception($context, $capability, 'nopermissions', '');
2411         }
2413         // Now, we can get safely all the blocked users.
2414         $users = \core_message\api::get_blocked_users($user->id);
2416         $blockedusers = array();
2417         foreach ($users as $user) {
2418             $newuser = array(
2419                 'id' => $user->id,
2420                 'fullname' => fullname($user),
2421             );
2423             $userpicture = new user_picture($user);
2424             $userpicture->size = 1; // Size f1.
2425             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2427             $blockedusers[] = $newuser;
2428         }
2430         $results = array(
2431             'users' => $blockedusers,
2432             'warnings' => $warnings
2433         );
2434         return $results;
2435     }
2437     /**
2438      * Get blocked users return description.
2439      *
2440      * @return external_single_structure
2441      * @since 2.9
2442      */
2443     public static function get_blocked_users_returns() {
2444         return new external_single_structure(
2445             array(
2446                 'users' => new external_multiple_structure(
2447                     new external_single_structure(
2448                         array(
2449                             'id' => new external_value(PARAM_INT, 'User ID'),
2450                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2451                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2452                         )
2453                     ),
2454                     'List of blocked users'
2455                 ),
2456                 'warnings' => new external_warnings()
2457             )
2458         );
2459     }
2461     /**
2462      * Returns description of method parameters
2463      *
2464      * @return external_function_parameters
2465      * @since 2.9
2466      */
2467     public static function mark_message_read_parameters() {
2468         return new external_function_parameters(
2469             array(
2470                 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2471                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2472                     VALUE_DEFAULT, 0)
2473             )
2474         );
2475     }
2477     /**
2478      * Mark a single message as read, trigger message_viewed event
2479      *
2480      * @param  int $messageid id of the message (in the message table)
2481      * @param  int $timeread timestamp for when the message should be marked read
2482      * @return external_description
2483      * @throws invalid_parameter_exception
2484      * @throws moodle_exception
2485      * @since 2.9
2486      */
2487     public static function mark_message_read($messageid, $timeread) {
2488         global $CFG, $DB, $USER;
2490         // Check if private messaging between users is allowed.
2491         if (empty($CFG->messaging)) {
2492             throw new moodle_exception('disabled', 'message');
2493         }
2495         // Warnings array, it can be empty at the end but is mandatory.
2496         $warnings = array();
2498         // Validate params.
2499         $params = array(
2500             'messageid' => $messageid,
2501             'timeread' => $timeread
2502         );
2503         $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2505         if (empty($params['timeread'])) {
2506             $timeread = time();
2507         } else {
2508             $timeread = $params['timeread'];
2509         }
2511         // Validate context.
2512         $context = context_system::instance();
2513         self::validate_context($context);
2515         $sql = "SELECT m.*, mcm.userid as useridto
2516                   FROM {messages} m
2517             INNER JOIN {message_conversations} mc
2518                     ON m.conversationid = mc.id
2519             INNER JOIN {message_conversation_members} mcm
2520                     ON mcm.conversationid = mc.id
2521              LEFT JOIN {message_user_actions} mua
2522                     ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2523                  WHERE mua.id is NULL
2524                    AND mcm.userid != m.useridfrom
2525                    AND m.id = ?";
2526         $messageparams = [];
2527         $messageparams[] = $USER->id;
2528         $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2529         $messageparams[] = $params['messageid'];
2530         $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2532         if ($message->useridto != $USER->id) {
2533             throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2534         }
2536         \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2538         $results = array(
2539             'messageid' => $message->id,
2540             'warnings' => $warnings
2541         );
2542         return $results;
2543     }
2545     /**
2546      * Returns description of method result value
2547      *
2548      * @return external_description
2549      * @since 2.9
2550      */
2551     public static function mark_message_read_returns() {
2552         return new external_single_structure(
2553             array(
2554                 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2555                 'warnings' => new external_warnings()
2556             )
2557         );
2558     }
2560     /**
2561      * Returns description of method parameters
2562      *
2563      * @return external_function_parameters
2564      */
2565     public static function mark_notification_read_parameters() {
2566         return new external_function_parameters(
2567             array(
2568                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2569                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2570                     VALUE_DEFAULT, 0)
2571             )
2572         );
2573     }
2575     /**
2576      * Mark a single notification as read.
2577      *
2578      * This will trigger a 'notification_viewed' event.
2579      *
2580      * @param int $notificationid id of the notification
2581      * @param int $timeread timestamp for when the notification should be marked read
2582      * @return external_description
2583      * @throws invalid_parameter_exception
2584      * @throws moodle_exception
2585      */
2586     public static function mark_notification_read($notificationid, $timeread) {
2587         global $CFG, $DB, $USER;
2589         // Check if private messaging between users is allowed.
2590         if (empty($CFG->messaging)) {
2591             throw new moodle_exception('disabled', 'message');
2592         }
2594         // Warnings array, it can be empty at the end but is mandatory.
2595         $warnings = array();
2597         // Validate params.
2598         $params = array(
2599             'notificationid' => $notificationid,
2600             'timeread' => $timeread
2601         );
2602         $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2604         if (empty($params['timeread'])) {
2605             $timeread = time();
2606         } else {
2607             $timeread = $params['timeread'];
2608         }
2610         // Validate context.
2611         $context = context_system::instance();
2612         self::validate_context($context);
2614         $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2616         if ($notification->useridto != $USER->id) {
2617             throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2618                 'notification as read');
2619         }
2621         \core_message\api::mark_notification_as_read($notification, $timeread);
2623         $results = array(
2624             'notificationid' => $notification->id,
2625             'warnings' => $warnings
2626         );
2628         return $results;
2629     }
2631     /**
2632      * Returns description of method result value
2633      *
2634      * @return external_description
2635      */
2636     public static function mark_notification_read_returns() {
2637         return new external_single_structure(
2638             array(
2639                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2640                 'warnings' => new external_warnings()
2641             )
2642         );
2643     }
2645     /**
2646      * Mark all messages as read parameters description.
2647      *
2648      * @deprecated since 3.6
2649      * @return external_function_parameters
2650      * @since 3.2
2651      */
2652     public static function mark_all_messages_as_read_parameters() {
2653         return new external_function_parameters(
2654             array(
2655                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2656                 'useridfrom' => new external_value(
2657                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2658                     VALUE_DEFAULT, 0),
2659             )
2660         );
2661     }
2663     /**
2664      * Mark all messages as read function.
2665      *
2666      * @deprecated since 3.6
2667      * @throws invalid_parameter_exception
2668      * @throws moodle_exception
2669      * @param  int      $useridto       the user id who received the message
2670      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2671      * @return external_description
2672      * @since  3.2
2673      */
2674     public static function mark_all_messages_as_read($useridto, $useridfrom) {
2675         global $USER, $CFG;
2677         // Check if messaging is enabled.
2678         if (empty($CFG->messaging)) {
2679             throw new moodle_exception('disabled', 'message');
2680         }
2682         $params = self::validate_parameters(
2683             self::mark_all_messages_as_read_parameters(),
2684             array(
2685                 'useridto' => $useridto,
2686                 'useridfrom' => $useridfrom,
2687             )
2688         );
2690         $context = context_system::instance();
2691         self::validate_context($context);
2693         $useridto = $params['useridto'];
2694         $useridfrom = $params['useridfrom'];
2696         if (!empty($useridto)) {
2697             if (core_user::is_real_user($useridto)) {
2698                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2699             } else {
2700                 throw new moodle_exception('invaliduser');
2701             }
2702         }
2704         if (!empty($useridfrom)) {
2705             // We use get_user here because the from user can be the noreply or support user.
2706             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2707         }
2709         // Check if the current user is the sender/receiver or just a privileged user.
2710         if ($useridto != $USER->id and $useridfrom != $USER->id and
2711             // The deleteanymessage cap seems more reasonable here than readallmessages.
2712              !has_capability('moodle/site:deleteanymessage', $context)) {
2713             throw new moodle_exception('accessdenied', 'admin');
2714         }
2716         if ($useridfrom) {
2717             if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
2718                 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
2719             }
2720         } else {
2721             \core_message\api::mark_all_messages_as_read($useridto);
2722         }
2724         return true;
2725     }
2727     /**
2728      * Mark all messages as read return description.
2729      *
2730      * @deprecated since 3.6
2731      * @return external_single_structure
2732      * @since 3.2
2733      */
2734     public static function mark_all_messages_as_read_returns() {
2735         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2736     }
2738     /**
2739      * Marking the method as deprecated.
2740      *
2741      * @return bool
2742      */
2743     public static function mark_all_messages_as_read_is_deprecated() {
2744         return true;
2745     }
2747     /**
2748      * Mark all conversation messages as read parameters description.
2749      *
2750      * @return external_function_parameters
2751      * @since 3.6
2752      */
2753     public static function mark_all_conversation_messages_as_read_parameters() {
2754         return new external_function_parameters(
2755             array(
2756                 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2757                 'conversationid' =>
2758                     new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2759             )
2760         );
2761     }
2763     /**
2764      * Mark all conversation messages as read function.
2765      *
2766      * @param int $userid The user id of who we want to delete the conversation for
2767      * @param int $conversationid The id of the conversations
2768      * @since 3.6
2769      */
2770     public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2771         global $CFG;
2773         // Check if messaging is enabled.
2774         if (empty($CFG->messaging)) {
2775             throw new moodle_exception('disabled', 'message');
2776         }
2778         $params = array(
2779             'userid' => $userid,
2780             'conversationid' => $conversationid,
2781         );
2782         $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2784         $context = context_system::instance();
2785         self::validate_context($context);
2787         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2788         core_user::require_active_user($user);
2790         if (\core_message\api::can_mark_all_messages_as_read($userid, $conversationid)) {
2791             \core_message\api::mark_all_messages_as_read($userid, $conversationid);
2792         } else {
2793             throw new moodle_exception('accessdenied', 'admin');
2794         }
2795     }
2797     /**
2798      * Mark all conversation messages as read return description.
2799      *
2800      * @return external_warnings
2801      * @since 3.6
2802      */
2803     public static function mark_all_conversation_messages_as_read_returns() {
2804         return new external_warnings();
2805     }
2807     /**
2808      * Returns description of method parameters.
2809      *
2810      * @deprecated since 3.6
2811      * @return external_function_parameters
2812      * @since 3.2
2813      */
2814     public static function delete_conversation_parameters() {
2815         return new external_function_parameters(
2816             array(
2817                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2818                 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
2819             )
2820         );
2821     }
2823     /**
2824      * Deletes a conversation.
2825      *
2826      * @deprecated since 3.6
2827      * @param int $userid The user id of who we want to delete the conversation for
2828      * @param int $otheruserid The user id of the other user in the conversation
2829      * @return array
2830      * @throws moodle_exception
2831      * @since 3.2
2832      */
2833     public static function delete_conversation($userid, $otheruserid) {
2834         global $CFG;
2836         // Check if private messaging between users is allowed.
2837         if (empty($CFG->messaging)) {
2838             throw new moodle_exception('disabled', 'message');
2839         }
2841         // Warnings array, it can be empty at the end but is mandatory.
2842         $warnings = array();
2844         // Validate params.
2845         $params = array(
2846             'userid' => $userid,
2847             'otheruserid' => $otheruserid,
2848         );
2849         $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
2851         // Validate context.
2852         $context = context_system::instance();
2853         self::validate_context($context);
2855         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2856         core_user::require_active_user($user);
2858         if (!$conversationid = \core_message\api::get_conversation_between_users([$userid, $otheruserid])) {
2859             return [];
2860         }
2862         if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2863             \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2864             $status = true;
2865         } else {
2866             throw new moodle_exception('You do not have permission to delete messages');
2867         }
2869         $results = array(
2870             'status' => $status,
2871             'warnings' => $warnings
2872         );
2874         return $results;
2875     }
2877     /**
2878      * Returns description of method result value.
2879      *
2880      * @deprecated since 3.6
2881      * @return external_description
2882      * @since 3.2
2883      */
2884     public static function delete_conversation_returns() {
2885         return new external_single_structure(
2886             array(
2887                 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
2888                 'warnings' => new external_warnings()
2889             )
2890         );
2891     }
2893     /**
2894      * Marking the method as deprecated.
2895      *
2896      * @return bool
2897      */
2898     public static function delete_conversation_is_deprecated() {
2899         return true;
2900     }
2902     /**
2903      * Returns description of method parameters.
2904      *
2905      * @return external_function_parameters
2906      * @since 3.6
2907      */
2908     public static function delete_conversations_by_id_parameters() {
2909         return new external_function_parameters(
2910             array(
2911                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2912                 'conversationids' => new external_multiple_structure(
2913                     new external_value(PARAM_INT, 'The id of the conversation'),
2914                     'List of conversation IDs'
2915                 ),
2916             )
2917         );
2918     }
2920     /**
2921      * Deletes a conversation.
2922      *
2923      * @param int $userid The user id of who we want to delete the conversation for
2924      * @param int[] $conversationids The ids of the conversations
2925      * @return array
2926      * @throws moodle_exception
2927      * @since 3.6
2928      */
2929     public static function delete_conversations_by_id($userid, array $conversationids) {
2930         global $CFG;
2932         // Check if private messaging between users is allowed.
2933         if (empty($CFG->messaging)) {
2934             throw new moodle_exception('disabled', 'message');
2935         }
2937         // Validate params.
2938         $params = [
2939             'userid' => $userid,
2940             'conversationids' => $conversationids,
2941         ];
2942         $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
2944         // Validate context.
2945         $context = context_system::instance();
2946         self::validate_context($context);
2948         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2949         core_user::require_active_user($user);
2951         foreach ($conversationids as $conversationid) {
2952             if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2953                 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2954             } else {
2955                 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2956             }
2957         }
2959         return [];
2960     }
2962     /**
2963      * Returns description of method result value.
2964      *
2965      * @return external_description
2966      * @since 3.6
2967      */
2968     public static function delete_conversations_by_id_returns() {
2969         return new external_warnings();
2970     }
2972     /**
2973      * Returns description of method parameters
2974      *
2975      * @return external_function_parameters
2976      * @since 3.1
2977      */
2978     public static function delete_message_parameters() {
2979         return new external_function_parameters(
2980             array(
2981                 'messageid' => new external_value(PARAM_INT, 'The message id'),
2982                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2983                 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2984             )
2985         );
2986     }
2988     /**
2989      * Deletes a message
2990      *
2991      * @param  int $messageid the message id
2992      * @param  int $userid the user id of who we want to delete the message for
2993      * @param  bool $read if is a message read (default to true)
2994      * @return external_description
2995      * @throws moodle_exception
2996      * @since 3.1
2997      */
2998     public static function delete_message($messageid, $userid, $read = true) {
2999         global $CFG;
3001         // Check if private messaging between users is allowed.
3002         if (empty($CFG->messaging)) {
3003             throw new moodle_exception('disabled', 'message');
3004         }
3006         // Warnings array, it can be empty at the end but is mandatory.
3007         $warnings = array();
3009         // Validate params.
3010         $params = array(
3011             'messageid' => $messageid,
3012             'userid' => $userid,
3013             'read' => $read
3014         );
3015         $params = self::validate_parameters(self::delete_message_parameters(), $params);
3017         // Validate context.
3018         $context = context_system::instance();
3019         self::validate_context($context);
3021         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3022         core_user::require_active_user($user);
3024         if (\core_message\api::can_delete_message($user->id, $messageid)) {
3025             $status = \core_message\api::delete_message($user->id, $messageid);
3026         } else {
3027             throw new moodle_exception('You do not have permission to delete this message');
3028         }
3030         $results = array(
3031             'status' => $status,
3032             'warnings' => $warnings
3033         );
3034         return $results;
3035     }
3037     /**
3038      * Returns description of method result value
3039      *
3040      * @return external_description
3041      * @since 3.1
3042      */
3043     public static function delete_message_returns() {
3044         return new external_single_structure(
3045             array(
3046                 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
3047                 'warnings' => new external_warnings()
3048             )
3049         );
3050     }
3052     /**
3053      * Returns description of method parameters
3054      *
3055      * @return external_function_parameters
3056      * @since 3.2
3057      */
3058     public static function message_processor_config_form_parameters() {
3059         return new external_function_parameters(
3060             array(
3061                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
3062                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
3063                 'formvalues' => new external_multiple_structure(
3064                     new external_single_structure(
3065                         array(
3066                             'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
3067                             'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
3068                         )
3069                     ),
3070                     'Config form values',
3071                     VALUE_REQUIRED
3072                 ),
3073             )
3074         );
3075     }
3077     /**
3078      * Processes a message processor config form.
3079      *
3080      * @param  int $userid the user id
3081      * @param  string $name the name of the processor
3082      * @param  array $formvalues the form values
3083      * @return external_description
3084      * @throws moodle_exception
3085      * @since 3.2
3086      */
3087     public static function message_processor_config_form($userid, $name, $formvalues) {
3088         global $USER, $CFG;
3090         // Check if messaging is enabled.
3091         if (empty($CFG->messaging)) {
3092             throw new moodle_exception('disabled', 'message');
3093         }
3095         $params = self::validate_parameters(
3096             self::message_processor_config_form_parameters(),
3097             array(
3098                 'userid' => $userid,
3099                 'name' => $name,
3100                 'formvalues' => $formvalues,
3101             )
3102         );
3104         $user = self::validate_preferences_permissions($params['userid']);
3106         $processor = get_message_processor($name);
3107         $preferences = [];
3108         $form = new stdClass();
3110         foreach ($formvalues as $formvalue) {
3111             // Curly braces to ensure interpretation is consistent between
3112             // php 5 and php 7.
3113             $form->{$formvalue['name']} = $formvalue['value'];
3114         }
3116         $processor->process_form($form, $preferences);
3118         if (!empty($preferences)) {
3119             set_user_preferences($preferences, $userid);
3120         }
3121     }
3123     /**
3124      * Returns description of method result value
3125      *
3126      * @return external_description
3127      * @since 3.2
3128      */
3129     public static function message_processor_config_form_returns() {
3130         return null;
3131     }
3133     /**
3134      * Returns description of method parameters
3135      *
3136      * @return external_function_parameters
3137      * @since 3.2
3138      */
3139     public static function get_message_processor_parameters() {
3140         return new external_function_parameters(
3141             array(
3142                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
3143                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
3144             )
3145         );
3146     }
3148     /**
3149      * Get a message processor.
3150      *
3151      * @param int $userid
3152      * @param string $name the name of the processor
3153      * @return external_description
3154      * @throws moodle_exception
3155      * @since 3.2
3156      */
3157     public static function get_message_processor($userid = 0, $name) {
3158         global $USER, $PAGE, $CFG;
3160         // Check if messaging is enabled.
3161         if (empty($CFG->messaging)) {
3162             throw new moodle_exception('disabled', 'message');
3163         }
3165         $params = self::validate_parameters(
3166             self::get_message_processor_parameters(),
3167             array(
3168                 'userid' => $userid,
3169                 'name' => $name,
3170             )
3171         );
3173         if (empty($params['userid'])) {
3174             $params['userid'] = $USER->id;
3175         }
3177         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3178         core_user::require_active_user($user);
3179         self::validate_context(context_user::instance($params['userid']));
3181         $processor = get_message_processor($name);
3183         $processoroutput = new \core_message\output\processor($processor, $user);
3184         $renderer = $PAGE->get_renderer('core_message');
3186         return $processoroutput->export_for_template($renderer);
3187     }
3189     /**
3190      * Returns description of method result value
3191      *
3192      * @return external_description
3193      * @since 3.2
3194      */
3195     public static function get_message_processor_returns() {
3196         return new external_function_parameters(
3197             array(
3198                 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
3199                 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
3200             )
3201         );
3202     }
3204     /**
3205      * Check that the user has enough permission to retrieve message or notifications preferences.
3206      *
3207      * @param  int $userid the user id requesting the preferences
3208      * @return stdClass full user object
3209      * @throws moodle_exception
3210      * @since  Moodle 3.2
3211      */
3212     protected static function validate_preferences_permissions($userid) {
3213         global $USER;
3215         if (empty($userid)) {
3216             $user = $USER;
3217         } else {
3218             $user = core_user::get_user($userid, '*', MUST_EXIST);
3219             core_user::require_active_user($user);
3220         }
3222         $systemcontext = context_system::instance();
3223         self::validate_context($systemcontext);
3225         // Check access control.
3226         if ($user->id == $USER->id) {
3227             // Editing own message profile.
3228             require_capability('moodle/user:editownmessageprofile', $systemcontext);
3229         } else {
3230             // Teachers, parents, etc.
3231             $personalcontext = context_user::instance($user->id);
3232             require_capability('moodle/user:editmessageprofile', $personalcontext);
3233         }
3234         return $user;
3235     }
3237     /**
3238      * Returns a notification or message preference structure.
3239      *
3240      * @return external_single_structure the structure
3241      * @since  Moodle 3.2
3242      */
3243     protected static function get_preferences_structure() {
3244         return new external_single_structure(
3245             array(
3246                 'userid' => new external_value(PARAM_INT, 'User id'),
3247                 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3248                 'processors' => new external_multiple_structure(
3249                     new external_single_structure(
3250                         array(
3251                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3252                             'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3253                             'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3254                             'contextid' => new external_value(PARAM_INT, 'Context id'),
3255                             'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3256                         )
3257                     ),
3258                     'Config form values'
3259                 ),
3260                 'components' => new external_multiple_structure(
3261                     new external_single_structure(
3262                         array(
3263                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3264                             'notifications' => new external_multiple_structure(
3265                                 new external_single_structure(
3266                                     array(
3267                                         'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3268                                         'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3269                                         'processors' => new external_multiple_structure(
3270                                             new external_single_structure(
3271                                                 array(
3272                                                     'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3273                                                     'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3274                                                     'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3275                                                     'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3276                                                     'loggedin' => new external_single_structure(
3277                                                         array(
3278                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
3279                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3280                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3281                                                         )
3282                                                     ),
3283                                                     'loggedoff' => new external_single_structure(
3284                                                         array(
3285                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
3286                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3287                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3288                                                         )
3289                                                     ),
3290                                                 )
3291                                             ),
3292                                             'Processors values for this notification'
3293                                         ),
3294                                     )
3295                                 ),
3296                                 'List of notificaitons for the component'
3297                             ),
3298                         )
3299                     ),
3300                     'Available components'
3301                 ),
3302             )
3303         );
3304     }
3306     /**
3307      * Returns description of method parameters
3308      *
3309      * @return external_function_parameters
3310      * @since 3.2
3311      */
3312     public static function get_user_notification_preferences_parameters() {
3313         return new external_function_parameters(
3314             array(
3315                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3316             )
3317         );
3318     }
3320     /**
3321      * Get the notification preferences for a given user.
3322      *
3323      * @param int $userid id of the user, 0 for current user
3324      * @return external_description
3325      * @throws moodle_exception
3326      * @since 3.2
3327      */
3328     public static function get_user_notification_preferences($userid = 0) {
3329         global $PAGE;
3331         $params = self::validate_parameters(
3332             self::get_user_notification_preferences_parameters(),
3333             array(
3334                 'userid' => $userid,
3335             )
3336         );
3337         $user = self::validate_preferences_permissions($params['userid']);
3339         $processors = get_message_processors();
3340         $providers = message_get_providers_for_user($user->id);
3341         $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3342         $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3344         $renderer = $PAGE->get_renderer('core_message');
3346         $result = array(
3347             'warnings' => array(),
3348             'preferences' => $notificationlist->export_for_template($renderer)
3349         );
3350         return $result;
3351     }
3353     /**
3354      * Returns description of method result value
3355      *
3356      * @return external_description
3357      * @since 3.2
3358      */
3359     public static function get_user_notification_preferences_returns() {
3360         return new external_function_parameters(
3361             array(
3362                 'preferences' => self::get_preferences_structure(),
3363                 'warnings' => new external_warnings(),
3364             )
3365         );
3366     }
3368     /**
3369      * Returns description of method parameters
3370      *
3371      * @return external_function_parameters
3372      * @since 3.2
3373      */
3374     public static function get_user_message_preferences_parameters() {
3375         return new external_function_parameters(
3376             array(
3377                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3378             )
3379         );
3380     }
3382     /**
3383      * Get the notification preferences for a given user.
3384      *
3385      * @param int $userid id of the user, 0 for current user
3386      * @return external_description
3387      * @throws moodle_exception
3388      * @since 3.2
3389      */
3390     public static function get_user_message_preferences($userid = 0) {
3391         global $PAGE;
3393         $params = self::validate_parameters(
3394             self::get_user_message_preferences_parameters(),
3395             array(
3396                 'userid' => $userid,
3397             )
3398         );
3400         $user = self::validate_preferences_permissions($params['userid']);
3402         // Filter out enabled, available system_configured and user_configured processors only.
3403         $readyprocessors = array_filter(get_message_processors(), function($processor) {
3404             return $processor->enabled &&
3405                 $processor->configured &&
3406                 $processor->object->is_user_configured() &&
3407                 // Filter out processors that don't have and message preferences to configure.
3408                 $processor->object->has_message_preferences();
3409         });