MDL-63063 block_recentlyaccesseditems: CSS
[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         $params = [
717             'userid' => $userid,
718             'conversationid' => $conversationid,
719             'includecontactrequests' => $includecontactrequests,
720             'limitfrom' => $limitfrom,
721             'limitnum' => $limitnum
722         ];
723         self::validate_parameters(self::get_conversation_members_parameters(), $params);
725         return \core_message\api::get_conversation_members($userid, $conversationid, $includecontactrequests,
726             $limitfrom, $limitnum);
727     }
729     /**
730      * Returns the get conversation members return description.
731      *
732      * @return external_description
733      */
734     public static function get_conversation_members_returns() {
735         return new external_multiple_structure(
736             self::get_conversation_member_structure(true)
737         );
738     }
740     /**
741      * Creates a contact request parameters description.
742      *
743      * @return external_function_parameters
744      */
745     public static function create_contact_request_parameters() {
746         return new external_function_parameters(
747             [
748                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
749                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
750             ]
751         );
752     }
754     /**
755      * Creates a contact request.
756      *
757      * @param int $userid The id of the user who is creating the contact request
758      * @param int $requesteduserid The id of the user being requested
759      */
760     public static function create_contact_request(int $userid, int $requesteduserid) {
761         global $CFG, $USER;
763         // Check if messaging is enabled.
764         if (empty($CFG->messaging)) {
765             throw new moodle_exception('disabled', 'message');
766         }
768         // Validate context.
769         $context = context_system::instance();
770         self::validate_context($context);
772         $capability = 'moodle/site:manageallmessaging';
773         if (($USER->id != $userid) && !has_capability($capability, $context)) {
774             throw new required_capability_exception($context, $capability, 'nopermissions', '');
775         }
777         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
778         $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
780         if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
781             $warning[] = [
782                 'item' => 'user',
783                 'itemid' => $params['requesteduserid'],
784                 'warningcode' => 'cannotcreatecontactrequest',
785                 'message' => 'You are unable to create a contact request for this user'
786             ];
787             return $warning;
788         }
790         if (!\core_message\api::does_contact_request_exist($params['userid'], $params['requesteduserid'])) {
791             \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
792         }
794         return [];
795     }
797     /**
798      * Creates a contact request return description.
799      *
800      * @return external_description
801      */
802     public static function create_contact_request_returns() {
803         return new external_warnings();
804     }
806     /**
807      * Confirm a contact request parameters description.
808      *
809      * @return external_function_parameters
810      */
811     public static function confirm_contact_request_parameters() {
812         return new external_function_parameters(
813             [
814                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
815                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
816             ]
817         );
818     }
820     /**
821      * Confirm a contact request.
822      *
823      * @param int $userid The id of the user who is creating the contact request
824      * @param int $requesteduserid The id of the user being requested
825      */
826     public static function confirm_contact_request(int $userid, int $requesteduserid) {
827         global $CFG, $USER;
829         // Check if messaging is enabled.
830         if (empty($CFG->messaging)) {
831             throw new moodle_exception('disabled', 'message');
832         }
834         // Validate context.
835         $context = context_system::instance();
836         self::validate_context($context);
838         $capability = 'moodle/site:manageallmessaging';
839         if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
840             throw new required_capability_exception($context, $capability, 'nopermissions', '');
841         }
843         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
844         $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
846         \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
848         return [];
849     }
851     /**
852      * Confirm a contact request return description.
853      *
854      * @return external_description
855      */
856     public static function confirm_contact_request_returns() {
857         return new external_warnings();
858     }
860     /**
861      * Declines a contact request parameters description.
862      *
863      * @return external_function_parameters
864      */
865     public static function decline_contact_request_parameters() {
866         return new external_function_parameters(
867             [
868                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
869                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
870             ]
871         );
872     }
874     /**
875      * Declines a contact request.
876      *
877      * @param int $userid The id of the user who is creating the contact request
878      * @param int $requesteduserid The id of the user being requested
879      */
880     public static function decline_contact_request(int $userid, int $requesteduserid) {
881         global $CFG, $USER;
883         // Check if messaging is enabled.
884         if (empty($CFG->messaging)) {
885             throw new moodle_exception('disabled', 'message');
886         }
888         // Validate context.
889         $context = context_system::instance();
890         self::validate_context($context);
892         $capability = 'moodle/site:manageallmessaging';
893         if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
894             throw new required_capability_exception($context, $capability, 'nopermissions', '');
895         }
897         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
898         $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
900         \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
902         return [];
903     }
905     /**
906      * Declines a contact request return description.
907      *
908      * @return external_description
909      */
910     public static function decline_contact_request_returns() {
911         return new external_warnings();
912     }
914     /**
915      * Return the structure of a message area contact.
916      *
917      * @return external_single_structure
918      * @since Moodle 3.2
919      */
920     private static function get_messagearea_contact_structure() {
921         return new external_single_structure(
922             array(
923                 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
924                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
925                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
926                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
927                 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
928                 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
929                 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
930                 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
931                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
932                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
933                 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
934                 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
935                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
936                     VALUE_DEFAULT, null),
937             )
938         );
939     }
941     /**
942      * Return the structure of a conversation.
943      *
944      * @return external_single_structure
945      * @since Moodle 3.6
946      */
947     private static function get_conversation_structure() {
948         return new external_single_structure(
949             array(
950                 'id' => new external_value(PARAM_INT, 'The conversation id'),
951                 'name' => new external_value(PARAM_NOTAGS, 'The conversation name, if set', VALUE_DEFAULT, null),
952                 'subname' => new external_value(PARAM_NOTAGS, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
953                 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group)'),
954                 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
955                 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked conversation this conversation as a favourite'),
956                 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
957                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
958                     VALUE_DEFAULT, null),
959                 'members' => new external_multiple_structure(
960                     self::get_conversation_member_structure()
961                 ),
962                 'messages' => new external_multiple_structure(
963                     self::get_conversation_message_structure()
964                 ),
965             )
966         );
967     }
969     /**
970      * Return the structure of a conversation member.
971      *
972      * @param bool $includecontactrequests Are we including contact requests?
973      * @return external_single_structure
974      * @since Moodle 3.6
975      */
976     private static function get_conversation_member_structure(bool $includecontactrequests = false) {
977         $result = [
978             'id' => new external_value(PARAM_INT, 'The user id'),
979             'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
980             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
981             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
982             'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
983             'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
984             'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
985             'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
986         ];
988         if ($includecontactrequests) {
989             $result['contactrequests'] = new external_multiple_structure(
990                 new external_single_structure(
991                     [
992                         'id' => new external_value(PARAM_INT, 'The id of the message'),
993                         'userid' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
994                         'requesteduserid' => 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                 ), 'The contact requests', VALUE_OPTIONAL
998             );
999         }
1001         return new external_single_structure(
1002             $result
1003         );
1004     }
1006     /**
1007      * Return the structure of a message area message.
1008      *
1009      * @return external_single_structure
1010      * @since Moodle 3.6
1011      */
1012     private static function get_conversation_message_structure() {
1013         return new external_single_structure(
1014             array(
1015                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1016                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1017                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1018                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1019             )
1020         );
1021     }
1023     /**
1024      * Return the structure of a message area message.
1025      *
1026      * @return external_single_structure
1027      * @since Moodle 3.2
1028      */
1029     private static function get_messagearea_message_structure() {
1030         return new external_single_structure(
1031             array(
1032                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1033                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1034                 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1035                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1036                 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1037                 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1038                 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1039                 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1040                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1041                 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1042             )
1043         );
1044     }
1046     /**
1047      * Get messagearea search users in course parameters.
1048      *
1049      * @return external_function_parameters
1050      * @since 3.2
1051      */
1052     public static function data_for_messagearea_search_users_in_course_parameters() {
1053         return new external_function_parameters(
1054             array(
1055                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1056                 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1057                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1058                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1059                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1060             )
1061         );
1062     }
1064     /**
1065      * Get messagearea search users in course results.
1066      *
1067      * @param int $userid The id of the user who is performing the search
1068      * @param int $courseid The id of the course
1069      * @param string $search The string being searched
1070      * @param int $limitfrom
1071      * @param int $limitnum
1072      * @return stdClass
1073      * @throws moodle_exception
1074      * @since 3.2
1075      */
1076     public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1077                                                                        $limitnum = 0) {
1078         global $CFG, $PAGE, $USER;
1080         // Check if messaging is enabled.
1081         if (empty($CFG->messaging)) {
1082             throw new moodle_exception('disabled', 'message');
1083         }
1085         $systemcontext = context_system::instance();
1087         $params = array(
1088             'userid' => $userid,
1089             'courseid' => $courseid,
1090             'search' => $search,
1091             'limitfrom' => $limitfrom,
1092             'limitnum' => $limitnum
1093         );
1094         self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1095         self::validate_context($systemcontext);
1097         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1098             throw new moodle_exception('You do not have permission to perform this action.');
1099         }
1101         $users = \core_message\api::search_users_in_course($userid, $courseid, $search, $limitfrom, $limitnum);
1102         $results = new \core_message\output\messagearea\user_search_results($users);
1104         $renderer = $PAGE->get_renderer('core_message');
1105         return $results->export_for_template($renderer);
1106     }
1108     /**
1109      * Get messagearea search users in course returns.
1110      *
1111      * @return external_single_structure
1112      * @since 3.2
1113      */
1114     public static function data_for_messagearea_search_users_in_course_returns() {
1115         return new external_single_structure(
1116             array(
1117                 'contacts' => new external_multiple_structure(
1118                     self::get_messagearea_contact_structure()
1119                 ),
1120             )
1121         );
1122     }
1124     /**
1125      * Get messagearea search users parameters.
1126      *
1127      * @return external_function_parameters
1128      * @since 3.2
1129      */
1130     public static function data_for_messagearea_search_users_parameters() {
1131         return new external_function_parameters(
1132             array(
1133                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1134                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1135                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1136             )
1137         );
1138     }
1140     /**
1141      * Get messagearea search users results.
1142      *
1143      * @param int $userid The id of the user who is performing the search
1144      * @param string $search The string being searched
1145      * @param int $limitnum
1146      * @return stdClass
1147      * @throws moodle_exception
1148      * @since 3.2
1149      */
1150     public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1151         global $CFG, $PAGE, $USER;
1153         // Check if messaging is enabled.
1154         if (empty($CFG->messaging)) {
1155             throw new moodle_exception('disabled', 'message');
1156         }
1158         $systemcontext = context_system::instance();
1160         $params = array(
1161             'userid' => $userid,
1162             'search' => $search,
1163             'limitnum' => $limitnum
1164         );
1165         self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1166         self::validate_context($systemcontext);
1168         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1169             throw new moodle_exception('You do not have permission to perform this action.');
1170         }
1172         list($contacts, $courses, $noncontacts) = \core_message\api::search_users($userid, $search, $limitnum);
1173         $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1175         $renderer = $PAGE->get_renderer('core_message');
1176         return $search->export_for_template($renderer);
1177     }
1179     /**
1180      * Get messagearea search users returns.
1181      *
1182      * @return external_single_structure
1183      * @since 3.2
1184      */
1185     public static function data_for_messagearea_search_users_returns() {
1186         return new external_single_structure(
1187             array(
1188                 'contacts' => new external_multiple_structure(
1189                     self::get_messagearea_contact_structure()
1190                 ),
1191                 'courses' => new external_multiple_structure(
1192                     new external_single_structure(
1193                         array(
1194                             'id' => new external_value(PARAM_INT, 'The course id'),
1195                             'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1196                             'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1197                         )
1198                     )
1199                 ),
1200                 'noncontacts' => new external_multiple_structure(
1201                     self::get_messagearea_contact_structure()
1202                 )
1203             )
1204         );
1205     }
1207     /**
1208      * Get messagearea search messages parameters.
1209      *
1210      * @return external_function_parameters
1211      * @since 3.2
1212      */
1213     public static function data_for_messagearea_search_messages_parameters() {
1214         return new external_function_parameters(
1215             array(
1216                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1217                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1218                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1219                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1220             )
1221         );
1222     }
1224     /**
1225      * Get messagearea search messages results.
1226      *
1227      * @param int $userid The id of the user who is performing the search
1228      * @param string $search The string being searched
1229      * @param int $limitfrom
1230      * @param int $limitnum
1231      * @return stdClass
1232      * @throws moodle_exception
1233      * @since 3.2
1234      */
1235     public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1236         global $CFG, $PAGE, $USER;
1238         // Check if messaging is enabled.
1239         if (empty($CFG->messaging)) {
1240             throw new moodle_exception('disabled', 'message');
1241         }
1243         $systemcontext = context_system::instance();
1245         $params = array(
1246             'userid' => $userid,
1247             'search' => $search,
1248             'limitfrom' => $limitfrom,
1249             'limitnum' => $limitnum
1251         );
1252         self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1253         self::validate_context($systemcontext);
1255         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1256             throw new moodle_exception('You do not have permission to perform this action.');
1257         }
1259         $messages = \core_message\api::search_messages($userid, $search, $limitfrom, $limitnum);
1260         $results = new \core_message\output\messagearea\message_search_results($messages);
1262         $renderer = $PAGE->get_renderer('core_message');
1263         return $results->export_for_template($renderer);
1264     }
1266     /**
1267      * Get messagearea search messages returns.
1268      *
1269      * @return external_single_structure
1270      * @since 3.2
1271      */
1272     public static function data_for_messagearea_search_messages_returns() {
1273         return new external_single_structure(
1274             array(
1275                 'contacts' => new external_multiple_structure(
1276                     self::get_messagearea_contact_structure()
1277                 )
1278             )
1279         );
1280     }
1282     /**
1283      * Get conversations parameters.
1284      *
1285      * @return external_function_parameters
1286      * @since 3.6
1287      */
1288     public static function get_conversations_parameters() {
1289         return new external_function_parameters(
1290             array(
1291                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1292                 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1293                 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1294                 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1295                 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1296                 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1297                     VALUE_DEFAULT, null),
1299             )
1300         );
1301     }
1303     /**
1304      * Get the list of conversations for the user.
1305      *
1306      * @param int $userid The id of the user who is performing the search
1307      * @param int $limitfrom
1308      * @param int $limitnum
1309      * @param int|null $type
1310      * @param bool|null $favourites
1311      * @return stdClass
1312      * @throws \moodle_exception if the messaging feature is disabled on the site.
1313      * @since 3.2
1314      */
1315     public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null) {
1316         global $CFG, $USER;
1318         // All the standard BL checks.
1319         if (empty($CFG->messaging)) {
1320             throw new moodle_exception('disabled', 'message');
1321         }
1323         $params = array(
1324             'userid' => $userid,
1325             'limitfrom' => $limitfrom,
1326             'limitnum' => $limitnum,
1327             'type' => $type,
1328             'favourites' => $favourites
1329         );
1330         self::validate_parameters(self::get_conversations_parameters(), $params);
1332         $systemcontext = context_system::instance();
1333         self::validate_context($systemcontext);
1335         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1336             throw new moodle_exception('You do not have permission to perform this action.');
1337         }
1339         $conversations = \core_message\api::get_conversations($userid, $limitfrom, $limitnum, $type, $favourites);
1340         return (object) ['conversations' => $conversations];
1341     }
1343     /**
1344      * Get conversations returns.
1345      *
1346      * @return external_single_structure
1347      * @since 3.6
1348      */
1349     public static function get_conversations_returns() {
1350         return new external_single_structure(
1351             [
1352                 'conversations' => new external_multiple_structure(
1353                     self::get_conversation_structure()
1354                 )
1355             ]
1356         );
1357     }
1359     /**
1360      * The messagearea conversations parameters.
1361      *
1362      * @deprecated since 3.6
1363      * @return external_function_parameters
1364      * @since 3.2
1365      */
1366     public static function data_for_messagearea_conversations_parameters() {
1367         return new external_function_parameters(
1368             array(
1369                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1370                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1371                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1372             )
1373         );
1374     }
1376     /**
1377      * Get messagearea conversations.
1378      *
1379      * NOTE FOR FINAL DEPRECATION:
1380      * When removing this method, please also consider removal of get_conversations_legacy_formatter()
1381      * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
1382      * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
1383      * removed.
1384      *
1385      * @deprecated since 3.6
1386      * @param int $userid The id of the user who we are viewing conversations for
1387      * @param int $limitfrom
1388      * @param int $limitnum
1389      * @return stdClass
1390      * @throws moodle_exception
1391      * @since 3.2
1392      */
1393     public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1394         global $CFG, $PAGE, $USER;
1396         // Check if messaging is enabled.
1397         if (empty($CFG->messaging)) {
1398             throw new moodle_exception('disabled', 'message');
1399         }
1401         $systemcontext = context_system::instance();
1403         $params = array(
1404             'userid' => $userid,
1405             'limitfrom' => $limitfrom,
1406             'limitnum' => $limitnum
1407         );
1408         self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1409         self::validate_context($systemcontext);
1411         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1412             throw new moodle_exception('You do not have permission to perform this action.');
1413         }
1415         $conversations = \core_message\api::get_conversations($userid, $limitfrom, $limitnum);
1417         // Format the conversations in the legacy style, as the get_conversations method has since been changed.
1418         $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
1420         $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1422         $renderer = $PAGE->get_renderer('core_message');
1423         return $conversations->export_for_template($renderer);
1424     }
1426     /**
1427      * The messagearea conversations return structure.
1428      *
1429      * @deprecated since 3.6
1430      * @return external_single_structure
1431      * @since 3.2
1432      */
1433     public static function data_for_messagearea_conversations_returns() {
1434         return new external_single_structure(
1435             array(
1436                 'contacts' => new external_multiple_structure(
1437                     self::get_messagearea_contact_structure()
1438                 )
1439             )
1440         );
1441     }
1443     /**
1444      * Marking the method as deprecated.
1445      *
1446      * @return bool
1447      */
1448     public static function data_for_messagearea_conversations_is_deprecated() {
1449         return true;
1450     }
1452     /**
1453      * The messagearea contacts return parameters.
1454      *
1455      * @return external_function_parameters
1456      * @since 3.2
1457      */
1458     public static function data_for_messagearea_contacts_parameters() {
1459         return self::data_for_messagearea_conversations_parameters();
1460     }
1462     /**
1463      * Get messagearea contacts parameters.
1464      *
1465      * @param int $userid The id of the user who we are viewing conversations for
1466      * @param int $limitfrom
1467      * @param int $limitnum
1468      * @return stdClass
1469      * @throws moodle_exception
1470      * @since 3.2
1471      */
1472     public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1473         global $CFG, $PAGE, $USER;
1475         // Check if messaging is enabled.
1476         if (empty($CFG->messaging)) {
1477             throw new moodle_exception('disabled', 'message');
1478         }
1480         $systemcontext = context_system::instance();
1482         $params = array(
1483             'userid' => $userid,
1484             'limitfrom' => $limitfrom,
1485             'limitnum' => $limitnum
1486         );
1487         self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1488         self::validate_context($systemcontext);
1490         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1491             throw new moodle_exception('You do not have permission to perform this action.');
1492         }
1494         $contacts = \core_message\api::get_contacts($userid, $limitfrom, $limitnum);
1495         $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1497         $renderer = $PAGE->get_renderer('core_message');
1498         return $contacts->export_for_template($renderer);
1499     }
1501     /**
1502      * The messagearea contacts return structure.
1503      *
1504      * @return external_single_structure
1505      * @since 3.2
1506      */
1507     public static function data_for_messagearea_contacts_returns() {
1508         return self::data_for_messagearea_conversations_returns();
1509     }
1511     /**
1512      * The messagearea messages parameters.
1513      *
1514      * @return external_function_parameters
1515      * @since 3.2
1516      */
1517     public static function data_for_messagearea_messages_parameters() {
1518         return new external_function_parameters(
1519             array(
1520                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1521                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1522                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1523                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1524                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1525                 'timefrom' => new external_value(PARAM_INT,
1526                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1527             )
1528         );
1529     }
1531     /**
1532      * Get messagearea messages.
1533      *
1534      * @param int $currentuserid The current user's id
1535      * @param int $otheruserid The other user's id
1536      * @param int $limitfrom
1537      * @param int $limitnum
1538      * @param boolean $newest
1539      * @return stdClass
1540      * @throws moodle_exception
1541      * @since 3.2
1542      */
1543     public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1544                                                          $newest = false, $timefrom = 0) {
1545         global $CFG, $PAGE, $USER;
1547         // Check if messaging is enabled.
1548         if (empty($CFG->messaging)) {
1549             throw new moodle_exception('disabled', 'message');
1550         }
1552         $systemcontext = context_system::instance();
1554         $params = array(
1555             'currentuserid' => $currentuserid,
1556             'otheruserid' => $otheruserid,
1557             'limitfrom' => $limitfrom,
1558             'limitnum' => $limitnum,
1559             'newest' => $newest,
1560             'timefrom' => $timefrom,
1561         );
1562         self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1563         self::validate_context($systemcontext);
1565         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1566             throw new moodle_exception('You do not have permission to perform this action.');
1567         }
1569         if ($newest) {
1570             $sort = 'timecreated DESC';
1571         } else {
1572             $sort = 'timecreated ASC';
1573         }
1575         // We need to enforce a one second delay on messages to avoid race conditions of current
1576         // messages still being sent.
1577         //
1578         // There is a chance that we could request messages before the current time's
1579         // second has elapsed and while other messages are being sent in that same second. In which
1580         // case those messages will be lost.
1581         //
1582         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1583         if (!empty($timefrom)) {
1584             $timeto = time() - 1;
1585         } else {
1586             $timeto = 0;
1587         }
1589         // No requesting messages from the current time, as stated above.
1590         if ($timefrom == time()) {
1591             $messages = [];
1592         } else {
1593             $messages = \core_message\api::get_messages($currentuserid, $otheruserid, $limitfrom,
1594                                                         $limitnum, $sort, $timefrom, $timeto);
1595         }
1597         $messages = new \core_message\output\messagearea\messages($currentuserid, $otheruserid, $messages);
1599         $renderer = $PAGE->get_renderer('core_message');
1600         return $messages->export_for_template($renderer);
1601     }
1603     /**
1604      * The messagearea messages return structure.
1605      *
1606      * @return external_single_structure
1607      * @since 3.2
1608      */
1609     public static function data_for_messagearea_messages_returns() {
1610         return new external_single_structure(
1611             array(
1612                 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1613                     the messages on behalf of?'),
1614                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1615                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1616                 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1617                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1618                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1619                 'messages' => new external_multiple_structure(
1620                     self::get_messagearea_message_structure()
1621                 ),
1622                 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1623             )
1624         );
1625     }
1627     /**
1628      * The conversation messages parameters.
1629      *
1630      * @return external_function_parameters
1631      * @since 3.6
1632      */
1633     public static function get_conversation_messages_parameters() {
1634         return new external_function_parameters(
1635             array(
1636                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1637                 'convid' => new external_value(PARAM_INT, 'The conversation id'),
1638                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1639                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1640                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1641                 'timefrom' => new external_value(PARAM_INT,
1642                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1643             )
1644         );
1645     }
1647     /**
1648      * Get conversation messages.
1649      *
1650      * @param  int $currentuserid The current user's id.
1651      * @param  int $convid The conversation id.
1652      * @param  int $limitfrom Return a subset of records, starting at this point (optional).
1653      * @param  int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1654      * @param  bool $newest True for getting first newest messages, false otherwise.
1655      * @param  int  $timefrom The time from the conversation messages to get.
1656      * @return stdClass The messages and members who have sent some of these messages.
1657      * @throws moodle_exception
1658      * @since 3.6
1659      */
1660     public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1661                                                          bool $newest = false, int $timefrom = 0) {
1662         global $CFG, $PAGE, $USER;
1664         // Check if messaging is enabled.
1665         if (empty($CFG->messaging)) {
1666             throw new moodle_exception('disabled', 'message');
1667         }
1669         $systemcontext = context_system::instance();
1671         $params = array(
1672             'currentuserid' => $currentuserid,
1673             'convid' => $convid,
1674             'limitfrom' => $limitfrom,
1675             'limitnum' => $limitnum,
1676             'newest' => $newest,
1677             'timefrom' => $timefrom,
1678         );
1679         self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1680         self::validate_context($systemcontext);
1682         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1683             throw new moodle_exception('You do not have permission to perform this action.');
1684         }
1686         $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1688         // We need to enforce a one second delay on messages to avoid race conditions of current
1689         // messages still being sent.
1690         //
1691         // There is a chance that we could request messages before the current time's
1692         // second has elapsed and while other messages are being sent in that same second. In which
1693         // case those messages will be lost.
1694         //
1695         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1696         $timeto = empty($timefrom) ? 0 : time() - 1;
1698         // No requesting messages from the current time, as stated above.
1699         if ($timefrom == time()) {
1700             $messages = [];
1701         } else {
1702             $messages = \core_message\api::get_conversation_messages($currentuserid, $convid, $limitfrom,
1703                                                         $limitnum, $sort, $timefrom, $timeto);
1704         }
1706         return $messages;
1707     }
1709     /**
1710      * The messagearea messages return structure.
1711      *
1712      * @return external_single_structure
1713      * @since 3.6
1714      */
1715     public static function get_conversation_messages_returns() {
1716         return new external_single_structure(
1717             array(
1718                 'id' => new external_value(PARAM_INT, 'The conversation id'),
1719                 'members' => new external_multiple_structure(
1720                     self::get_conversation_member_structure()
1721                 ),
1722                 'messages' => new external_multiple_structure(
1723                     self::get_conversation_message_structure()
1724                 ),
1725             )
1726         );
1727     }
1729     /**
1730      * The get most recent message return parameters.
1731      *
1732      * @return external_function_parameters
1733      * @since 3.2
1734      */
1735     public static function data_for_messagearea_get_most_recent_message_parameters() {
1736         return new external_function_parameters(
1737             array(
1738                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1739                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1740             )
1741         );
1742     }
1744     /**
1745      * Get the most recent message in a conversation.
1746      *
1747      * @param int $currentuserid The current user's id
1748      * @param int $otheruserid The other user's id
1749      * @return stdClass
1750      * @throws moodle_exception
1751      * @since 3.2
1752      */
1753     public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
1754         global $CFG, $PAGE, $USER;
1756         // Check if messaging is enabled.
1757         if (empty($CFG->messaging)) {
1758             throw new moodle_exception('disabled', 'message');
1759         }
1761         $systemcontext = context_system::instance();
1763         $params = array(
1764             'currentuserid' => $currentuserid,
1765             'otheruserid' => $otheruserid
1766         );
1767         self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
1768         self::validate_context($systemcontext);
1770         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1771             throw new moodle_exception('You do not have permission to perform this action.');
1772         }
1774         $message = \core_message\api::get_most_recent_message($currentuserid, $otheruserid);
1775         $message = new \core_message\output\messagearea\message($message);
1777         $renderer = $PAGE->get_renderer('core_message');
1778         return $message->export_for_template($renderer);
1779     }
1781     /**
1782      * The get most recent message return structure.
1783      *
1784      * @return external_single_structure
1785      * @since 3.2
1786      */
1787     public static function data_for_messagearea_get_most_recent_message_returns() {
1788         return self::get_messagearea_message_structure();
1789     }
1791     /**
1792      * The get profile parameters.
1793      *
1794      * @return external_function_parameters
1795      * @since 3.2
1796      */
1797     public static function data_for_messagearea_get_profile_parameters() {
1798         return new external_function_parameters(
1799             array(
1800                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1801                 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
1802             )
1803         );
1804     }
1806     /**
1807      * Get the profile information for a contact.
1808      *
1809      * @param int $currentuserid The current user's id
1810      * @param int $otheruserid The id of the user whose profile we are viewing
1811      * @return stdClass
1812      * @throws moodle_exception
1813      * @since 3.2
1814      */
1815     public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
1816         global $CFG, $PAGE, $USER;
1818         // Check if messaging is enabled.
1819         if (empty($CFG->messaging)) {
1820             throw new moodle_exception('disabled', 'message');
1821         }
1823         $systemcontext = context_system::instance();
1825         $params = array(
1826             'currentuserid' => $currentuserid,
1827             'otheruserid' => $otheruserid
1828         );
1829         self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
1830         self::validate_context($systemcontext);
1832         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1833             throw new moodle_exception('You do not have permission to perform this action.');
1834         }
1836         $profile = \core_message\api::get_profile($currentuserid, $otheruserid);
1837         $profile = new \core_message\output\messagearea\profile($profile);
1839         $renderer = $PAGE->get_renderer('core_message');
1840         return $profile->export_for_template($renderer);
1841     }
1843     /**
1844      * The get profile return structure.
1845      *
1846      * @return external_single_structure
1847      * @since 3.2
1848      */
1849     public static function data_for_messagearea_get_profile_returns() {
1850         return new external_single_structure(
1851             array(
1852                 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
1853                 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
1854                 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
1855                 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
1856                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1857                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1858                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1859                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1860                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1861                 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
1862                 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
1863             )
1864         );
1865     }
1867     /**
1868      * Get contacts parameters description.
1869      *
1870      * @return external_function_parameters
1871      * @since Moodle 2.5
1872      */
1873     public static function get_contacts_parameters() {
1874         return new external_function_parameters(array());
1875     }
1877     /**
1878      * Get contacts.
1879      *
1880      * @return external_description
1881      * @since Moodle 2.5
1882      */
1883     public static function get_contacts() {
1884         global $CFG, $PAGE, $USER;
1886         // Check if messaging is enabled.
1887         if (empty($CFG->messaging)) {
1888             throw new moodle_exception('disabled', 'message');
1889         }
1891         require_once($CFG->dirroot . '/user/lib.php');
1893         $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
1894         $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
1895         foreach ($contacts as $contact) {
1896             // Set the mode.
1897             $mode = 'offline';
1898             if (\core_message\helper::is_online($contact->lastaccess)) {
1899                 $mode = 'online';
1900             }
1902             $newcontact = array(
1903                 'id' => $contact->id,
1904                 'fullname' => fullname($contact),
1905                 'unread' => $contact->messagecount
1906             );
1908             $userpicture = new user_picture($contact);
1909             $userpicture->size = 1; // Size f1.
1910             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1911             $userpicture->size = 0; // Size f2.
1912             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1914             $allcontacts[$mode][$contact->id] = $newcontact;
1915         }
1917         $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
1918         foreach ($strangers as $contact) {
1919             $newcontact = array(
1920                 'id' => $contact->id,
1921                 'fullname' => fullname($contact),
1922                 'unread' => $contact->messagecount
1923             );
1925             $userpicture = new user_picture($contact);
1926             $userpicture->size = 1; // Size f1.
1927             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1928             $userpicture->size = 0; // Size f2.
1929             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1931             $allcontacts['strangers'][$contact->id] = $newcontact;
1932         }
1934         // Add noreply user and support user to the list, if they don't exist.
1935         $supportuser = core_user::get_support_user();
1936         if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
1937             $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
1938             if ($supportuser->messagecount > 0) {
1939                 $supportuser->fullname = fullname($supportuser);
1940                 $supportuser->unread = $supportuser->messagecount;
1941                 $allcontacts['strangers'][$supportuser->id] = $supportuser;
1942             }
1943         }
1945         $noreplyuser = core_user::get_noreply_user();
1946         if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
1947             $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
1948             if ($noreplyuser->messagecount > 0) {
1949                 $noreplyuser->fullname = fullname($noreplyuser);
1950                 $noreplyuser->unread = $noreplyuser->messagecount;
1951                 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
1952             }
1953         }
1955         return $allcontacts;
1956     }
1958     /**
1959      * Get contacts return description.
1960      *
1961      * @return external_description
1962      * @since Moodle 2.5
1963      */
1964     public static function get_contacts_returns() {
1965         return new external_single_structure(
1966             array(
1967                 'online' => new external_multiple_structure(
1968                     new external_single_structure(
1969                         array(
1970                             'id' => new external_value(PARAM_INT, 'User ID'),
1971                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1972                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1973                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1974                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1975                         )
1976                     ),
1977                     'List of online contacts'
1978                 ),
1979                 'offline' => new external_multiple_structure(
1980                     new external_single_structure(
1981                         array(
1982                             'id' => new external_value(PARAM_INT, 'User ID'),
1983                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1984                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1985                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1986                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1987                         )
1988                     ),
1989                     'List of offline contacts'
1990                 ),
1991                 'strangers' => new external_multiple_structure(
1992                     new external_single_structure(
1993                         array(
1994                             'id' => new external_value(PARAM_INT, 'User ID'),
1995                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1996                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1997                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1998                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1999                         )
2000                     ),
2001                     'List of users that are not in the user\'s contact list but have sent a message'
2002                 )
2003             )
2004         );
2005     }
2007     /**
2008      * Search contacts parameters description.
2009      *
2010      * @return external_function_parameters
2011      * @since Moodle 2.5
2012      */
2013     public static function search_contacts_parameters() {
2014         return new external_function_parameters(
2015             array(
2016                 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2017                 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2018                     VALUE_DEFAULT, false)
2019             )
2020         );
2021     }
2023     /**
2024      * Search contacts.
2025      *
2026      * @param string $searchtext query string.
2027      * @param bool $onlymycourses limit the search to the user's courses only.
2028      * @return external_description
2029      * @since Moodle 2.5
2030      */
2031     public static function search_contacts($searchtext, $onlymycourses = false) {
2032         global $CFG, $USER, $PAGE;
2033         require_once($CFG->dirroot . '/user/lib.php');
2035         // Check if messaging is enabled.
2036         if (empty($CFG->messaging)) {
2037             throw new moodle_exception('disabled', 'message');
2038         }
2040         require_once($CFG->libdir . '/enrollib.php');
2042         $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2043         $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2045         // Extra validation, we do not allow empty queries.
2046         if ($params['searchtext'] === '') {
2047             throw new moodle_exception('querystringcannotbeempty');
2048         }
2050         $courseids = array();
2051         if ($params['onlymycourses']) {
2052             $mycourses = enrol_get_my_courses(array('id'));
2053             foreach ($mycourses as $mycourse) {
2054                 $courseids[] = $mycourse->id;
2055             }
2056         } else {
2057             $courseids[] = SITEID;
2058         }
2060         // Retrieving the users matching the query.
2061         $users = message_search_users($courseids, $params['searchtext']);
2062         $results = array();
2063         foreach ($users as $user) {
2064             $results[$user->id] = $user;
2065         }
2067         // Reorganising information.
2068         foreach ($results as &$user) {
2069             $newuser = array(
2070                 'id' => $user->id,
2071                 'fullname' => fullname($user)
2072             );
2074             // Avoid undefined property notice as phone not specified.
2075             $user->phone1 = null;
2076             $user->phone2 = null;
2078             $userpicture = new user_picture($user);
2079             $userpicture->size = 1; // Size f1.
2080             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2081             $userpicture->size = 0; // Size f2.
2082             $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2084             $user = $newuser;
2085         }
2087         return $results;
2088     }
2090     /**
2091      * Search contacts return description.
2092      *
2093      * @return external_description
2094      * @since Moodle 2.5
2095      */
2096     public static function search_contacts_returns() {
2097         return new external_multiple_structure(
2098             new external_single_structure(
2099                 array(
2100                     'id' => new external_value(PARAM_INT, 'User ID'),
2101                     'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2102                     'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2103                     'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
2104                 )
2105             ),
2106             'List of contacts'
2107         );
2108     }
2110     /**
2111      * Get messages parameters description.
2112      *
2113      * @return external_function_parameters
2114      * @since 2.8
2115      */
2116     public static function get_messages_parameters() {
2117         return new external_function_parameters(
2118             array(
2119                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2120                 'useridfrom' => new external_value(
2121                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2122                     VALUE_DEFAULT, 0),
2123                 'type' => new external_value(
2124                     PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
2125                     VALUE_DEFAULT, 'both'),
2126                 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
2127                 'newestfirst' => new external_value(
2128                     PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
2129                     VALUE_DEFAULT, true),
2130                 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
2131                 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
2132             )
2133         );
2134     }
2136     /**
2137      * Get messages function implementation.
2138      *
2139      * @since  2.8
2140      * @throws invalid_parameter_exception
2141      * @throws moodle_exception
2142      * @param  int      $useridto       the user id who received the message
2143      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2144      * @param  string   $type           type of message to return, expected values: notifications, conversations and both
2145      * @param  bool     $read           true for retreiving read messages, false for unread
2146      * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
2147      * @param  int      $limitfrom      limit from
2148      * @param  int      $limitnum       limit num
2149      * @return external_description
2150      */
2151     public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
2152                                         $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2153         global $CFG, $USER;
2155         $warnings = array();
2157         $params = array(
2158             'useridto' => $useridto,
2159             'useridfrom' => $useridfrom,
2160             'type' => $type,
2161             'read' => $read,
2162             'newestfirst' => $newestfirst,
2163             'limitfrom' => $limitfrom,
2164             'limitnum' => $limitnum
2165         );
2167         $params = self::validate_parameters(self::get_messages_parameters(), $params);
2169         $context = context_system::instance();
2170         self::validate_context($context);
2172         $useridto = $params['useridto'];
2173         $useridfrom = $params['useridfrom'];
2174         $type = $params['type'];
2175         $read = $params['read'];
2176         $newestfirst = $params['newestfirst'];
2177         $limitfrom = $params['limitfrom'];
2178         $limitnum = $params['limitnum'];
2180         $allowedvalues = array('notifications', 'conversations', 'both');
2181         if (!in_array($type, $allowedvalues)) {
2182             throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2183                 'allowed values are: ' . implode(',', $allowedvalues));
2184         }
2186         // Check if private messaging between users is allowed.
2187         if (empty($CFG->messaging)) {
2188             // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2189             if ($type == "conversations") {
2190                 throw new moodle_exception('disabled', 'message');
2191             }
2192             if ($type == "both") {
2193                 $warning = array();
2194                 $warning['item'] = 'message';
2195                 $warning['itemid'] = $USER->id;
2196                 $warning['warningcode'] = '1';
2197                 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2198                     Only notifications will be returned';
2199                 $warnings[] = $warning;
2200             }
2201         }
2203         if (!empty($useridto)) {
2204             if (core_user::is_real_user($useridto)) {
2205                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2206             } else {
2207                 throw new moodle_exception('invaliduser');
2208             }
2209         }
2211         if (!empty($useridfrom)) {
2212             // We use get_user here because the from user can be the noreply or support user.
2213             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2214         }
2216         // Check if the current user is the sender/receiver or just a privileged user.
2217         if ($useridto != $USER->id and $useridfrom != $USER->id and
2218              !has_capability('moodle/site:readallmessages', $context)) {
2219             throw new moodle_exception('accessdenied', 'admin');
2220         }
2222         // Which type of messages to retrieve.
2223         $notifications = -1;
2224         if ($type != 'both') {
2225             $notifications = ($type == 'notifications') ? 1 : 0;
2226         }
2228         $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2229         $sort = "mr.timecreated $orderdirection";
2231         if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2232             $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2234             // In some cases, we don't need to get the to/from user objects from the sql query.
2235             $userfromfullname = '';
2236             $usertofullname = '';
2238             // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2239             if (!empty($useridto)) {
2240                 $usertofullname = fullname($userto, $canviewfullname);
2241                 // The user from may or may not be filled.
2242                 if (!empty($useridfrom)) {
2243                     $userfromfullname = fullname($userfrom, $canviewfullname);
2244                 }
2245             } else {
2246                 // If the useridto field is empty, the useridfrom must be filled.
2247                 $userfromfullname = fullname($userfrom, $canviewfullname);
2248             }
2249             foreach ($messages as $mid => $message) {
2251                 // Do not return deleted messages.
2252                 if (!$message->notification) {
2253                     if (($useridto == $USER->id and $message->timeusertodeleted) or
2254                         ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2255                         unset($messages[$mid]);
2256                         continue;
2257                     }
2258                 }
2260                 // We need to get the user from the query.
2261                 if (empty($userfromfullname)) {
2262                     // Check for non-reply and support users.
2263                     if (core_user::is_real_user($message->useridfrom)) {
2264                         $user = new stdClass();
2265                         $user = username_load_fields_from_object($user, $message, 'userfrom');
2266                         $message->userfromfullname = fullname($user, $canviewfullname);
2267                     } else {
2268                         $user = core_user::get_user($message->useridfrom);
2269                         $message->userfromfullname = fullname($user, $canviewfullname);
2270                     }
2271                 } else {
2272                     $message->userfromfullname = $userfromfullname;
2273                 }
2275                 // We need to get the user from the query.
2276                 if (empty($usertofullname)) {
2277                     $user = new stdClass();
2278                     $user = username_load_fields_from_object($user, $message, 'userto');
2279                     $message->usertofullname = fullname($user, $canviewfullname);
2280                 } else {
2281                     $message->usertofullname = $usertofullname;
2282                 }
2284                 $message->text = message_format_message_text($message);
2285                 $messages[$mid] = (array) $message;
2286             }
2287         }
2289         $results = array(
2290             'messages' => $messages,
2291             'warnings' => $warnings
2292         );
2294         return $results;
2295     }
2297     /**
2298      * Get messages return description.
2299      *
2300      * @return external_single_structure
2301      * @since 2.8
2302      */
2303     public static function get_messages_returns() {
2304         return new external_single_structure(
2305             array(
2306                 'messages' => new external_multiple_structure(
2307                     new external_single_structure(
2308                         array(
2309                             'id' => new external_value(PARAM_INT, 'Message id'),
2310                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2311                             'useridto' => new external_value(PARAM_INT, 'User to id'),
2312                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2313                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
2314                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2315                             'fullmessageformat' => new external_format_value('fullmessage'),
2316                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2317                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2318                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2319                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2320                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2321                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
2322                             'timeread' => new external_value(PARAM_INT, 'Time read'),
2323                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2324                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2325                         ), 'message'
2326                     )
2327                 ),
2328                 'warnings' => new external_warnings()
2329             )
2330         );
2331     }
2333     /**
2334      * Mark all notifications as read parameters description.
2335      *
2336      * @return external_function_parameters
2337      * @since 3.2
2338      */
2339     public static function mark_all_notifications_as_read_parameters() {
2340         return new external_function_parameters(
2341             array(
2342                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2343                 'useridfrom' => new external_value(
2344                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2345                     VALUE_DEFAULT, 0),
2346             )
2347         );
2348     }
2350     /**
2351      * Mark all notifications as read function.
2352      *
2353      * @since  3.2
2354      * @throws invalid_parameter_exception
2355      * @throws moodle_exception
2356      * @param  int      $useridto       the user id who received the message
2357      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2358      * @return external_description
2359      */
2360     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2361         global $USER;
2363         $params = self::validate_parameters(
2364             self::mark_all_notifications_as_read_parameters(),
2365             array(
2366                 'useridto' => $useridto,
2367                 'useridfrom' => $useridfrom,
2368             )
2369         );
2371         $context = context_system::instance();
2372         self::validate_context($context);
2374         $useridto = $params['useridto'];
2375         $useridfrom = $params['useridfrom'];
2377         if (!empty($useridto)) {
2378             if (core_user::is_real_user($useridto)) {
2379                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2380             } else {
2381                 throw new moodle_exception('invaliduser');
2382             }
2383         }
2385         if (!empty($useridfrom)) {
2386             // We use get_user here because the from user can be the noreply or support user.
2387             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2388         }
2390         // Check if the current user is the sender/receiver or just a privileged user.
2391         if ($useridto != $USER->id and $useridfrom != $USER->id and
2392             // The deleteanymessage cap seems more reasonable here than readallmessages.
2393              !has_capability('moodle/site:deleteanymessage', $context)) {
2394             throw new moodle_exception('accessdenied', 'admin');
2395         }
2397         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2399         return true;
2400     }
2402     /**
2403      * Mark all notifications as read return description.
2404      *
2405      * @return external_single_structure
2406      * @since 3.2
2407      */
2408     public static function mark_all_notifications_as_read_returns() {
2409         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2410     }
2412     /**
2413      * Get unread conversations count parameters description.
2414      *
2415      * @return external_function_parameters
2416      * @since 3.2
2417      */
2418     public static function get_unread_conversations_count_parameters() {
2419         return new external_function_parameters(
2420             array(
2421                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2422             )
2423         );
2424     }
2426     /**
2427      * Get unread messages count function.
2428      *
2429      * @since  3.2
2430      * @throws invalid_parameter_exception
2431      * @throws moodle_exception
2432      * @param  int      $useridto       the user id who received the message
2433      * @return external_description
2434      */
2435     public static function get_unread_conversations_count($useridto) {
2436         global $USER, $CFG;
2438         // Check if messaging is enabled.
2439         if (empty($CFG->messaging)) {
2440             throw new moodle_exception('disabled', 'message');
2441         }
2443         $params = self::validate_parameters(
2444             self::get_unread_conversations_count_parameters(),
2445             array('useridto' => $useridto)
2446         );
2448         $context = context_system::instance();
2449         self::validate_context($context);
2451         $useridto = $params['useridto'];
2453         if (!empty($useridto)) {
2454             if (core_user::is_real_user($useridto)) {
2455                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2456             } else {
2457                 throw new moodle_exception('invaliduser');
2458             }
2459         } else {
2460             $useridto = $USER->id;
2461         }
2463         // Check if the current user is the receiver or just a privileged user.
2464         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2465             throw new moodle_exception('accessdenied', 'admin');
2466         }
2468         return \core_message\api::count_unread_conversations($userto);
2469     }
2471     /**
2472      * Get unread conversations count return description.
2473      *
2474      * @return external_single_structure
2475      * @since 3.2
2476      */
2477     public static function get_unread_conversations_count_returns() {
2478         return new external_value(PARAM_INT, 'The count of unread messages for the user');
2479     }
2481     /**
2482      * Get blocked users parameters description.
2483      *
2484      * @return external_function_parameters
2485      * @since 2.9
2486      */
2487     public static function get_blocked_users_parameters() {
2488         return new external_function_parameters(
2489             array(
2490                 'userid' => new external_value(PARAM_INT,
2491                                 'the user whose blocked users we want to retrieve',
2492                                 VALUE_REQUIRED),
2493             )
2494         );
2495     }
2497     /**
2498      * Retrieve a list of users blocked
2499      *
2500      * @param  int $userid the user whose blocked users we want to retrieve
2501      * @return external_description
2502      * @since 2.9
2503      */
2504     public static function get_blocked_users($userid) {
2505         global $CFG, $USER, $PAGE;
2507         // Warnings array, it can be empty at the end but is mandatory.
2508         $warnings = array();
2510         // Validate params.
2511         $params = array(
2512             'userid' => $userid
2513         );
2514         $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2515         $userid = $params['userid'];
2517         // Validate context.
2518         $context = context_system::instance();
2519         self::validate_context($context);
2521         // Check if private messaging between users is allowed.
2522         if (empty($CFG->messaging)) {
2523             throw new moodle_exception('disabled', 'message');
2524         }
2526         $user = core_user::get_user($userid, '*', MUST_EXIST);
2527         core_user::require_active_user($user);
2529         // Check if we have permissions for retrieve the information.
2530         $capability = 'moodle/site:manageallmessaging';
2531         if (($USER->id != $userid) && !has_capability($capability, $context)) {
2532             throw new required_capability_exception($context, $capability, 'nopermissions', '');
2533         }
2535         // Now, we can get safely all the blocked users.
2536         $users = \core_message\api::get_blocked_users($user->id);
2538         $blockedusers = array();
2539         foreach ($users as $user) {
2540             $newuser = array(
2541                 'id' => $user->id,
2542                 'fullname' => fullname($user),
2543             );
2545             $userpicture = new user_picture($user);
2546             $userpicture->size = 1; // Size f1.
2547             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2549             $blockedusers[] = $newuser;
2550         }
2552         $results = array(
2553             'users' => $blockedusers,
2554             'warnings' => $warnings
2555         );
2556         return $results;
2557     }
2559     /**
2560      * Get blocked users return description.
2561      *
2562      * @return external_single_structure
2563      * @since 2.9
2564      */
2565     public static function get_blocked_users_returns() {
2566         return new external_single_structure(
2567             array(
2568                 'users' => new external_multiple_structure(
2569                     new external_single_structure(
2570                         array(
2571                             'id' => new external_value(PARAM_INT, 'User ID'),
2572                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2573                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2574                         )
2575                     ),
2576                     'List of blocked users'
2577                 ),
2578                 'warnings' => new external_warnings()
2579             )
2580         );
2581     }
2583     /**
2584      * Returns description of method parameters
2585      *
2586      * @return external_function_parameters
2587      * @since 2.9
2588      */
2589     public static function mark_message_read_parameters() {
2590         return new external_function_parameters(
2591             array(
2592                 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2593                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2594                     VALUE_DEFAULT, 0)
2595             )
2596         );
2597     }
2599     /**
2600      * Mark a single message as read, trigger message_viewed event
2601      *
2602      * @param  int $messageid id of the message (in the message table)
2603      * @param  int $timeread timestamp for when the message should be marked read
2604      * @return external_description
2605      * @throws invalid_parameter_exception
2606      * @throws moodle_exception
2607      * @since 2.9
2608      */
2609     public static function mark_message_read($messageid, $timeread) {
2610         global $CFG, $DB, $USER;
2612         // Check if private messaging between users is allowed.
2613         if (empty($CFG->messaging)) {
2614             throw new moodle_exception('disabled', 'message');
2615         }
2617         // Warnings array, it can be empty at the end but is mandatory.
2618         $warnings = array();
2620         // Validate params.
2621         $params = array(
2622             'messageid' => $messageid,
2623             'timeread' => $timeread
2624         );
2625         $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2627         if (empty($params['timeread'])) {
2628             $timeread = time();
2629         } else {
2630             $timeread = $params['timeread'];
2631         }
2633         // Validate context.
2634         $context = context_system::instance();
2635         self::validate_context($context);
2637         $sql = "SELECT m.*, mcm.userid as useridto
2638                   FROM {messages} m
2639             INNER JOIN {message_conversations} mc
2640                     ON m.conversationid = mc.id
2641             INNER JOIN {message_conversation_members} mcm
2642                     ON mcm.conversationid = mc.id
2643              LEFT JOIN {message_user_actions} mua
2644                     ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2645                  WHERE mua.id is NULL
2646                    AND mcm.userid != m.useridfrom
2647                    AND m.id = ?";
2648         $messageparams = [];
2649         $messageparams[] = $USER->id;
2650         $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2651         $messageparams[] = $params['messageid'];
2652         $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2654         if ($message->useridto != $USER->id) {
2655             throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2656         }
2658         \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2660         $results = array(
2661             'messageid' => $message->id,
2662             'warnings' => $warnings
2663         );
2664         return $results;
2665     }
2667     /**
2668      * Returns description of method result value
2669      *
2670      * @return external_description
2671      * @since 2.9
2672      */
2673     public static function mark_message_read_returns() {
2674         return new external_single_structure(
2675             array(
2676                 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2677                 'warnings' => new external_warnings()
2678             )
2679         );
2680     }
2682     /**
2683      * Returns description of method parameters
2684      *
2685      * @return external_function_parameters
2686      */
2687     public static function mark_notification_read_parameters() {
2688         return new external_function_parameters(
2689             array(
2690                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2691                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2692                     VALUE_DEFAULT, 0)
2693             )
2694         );
2695     }
2697     /**
2698      * Mark a single notification as read.
2699      *
2700      * This will trigger a 'notification_viewed' event.
2701      *
2702      * @param int $notificationid id of the notification
2703      * @param int $timeread timestamp for when the notification should be marked read
2704      * @return external_description
2705      * @throws invalid_parameter_exception
2706      * @throws moodle_exception
2707      */
2708     public static function mark_notification_read($notificationid, $timeread) {
2709         global $CFG, $DB, $USER;
2711         // Check if private messaging between users is allowed.
2712         if (empty($CFG->messaging)) {
2713             throw new moodle_exception('disabled', 'message');
2714         }
2716         // Warnings array, it can be empty at the end but is mandatory.
2717         $warnings = array();
2719         // Validate params.
2720         $params = array(
2721             'notificationid' => $notificationid,
2722             'timeread' => $timeread
2723         );
2724         $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2726         if (empty($params['timeread'])) {
2727             $timeread = time();
2728         } else {
2729             $timeread = $params['timeread'];
2730         }
2732         // Validate context.
2733         $context = context_system::instance();
2734         self::validate_context($context);
2736         $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2738         if ($notification->useridto != $USER->id) {
2739             throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2740                 'notification as read');
2741         }
2743         \core_message\api::mark_notification_as_read($notification, $timeread);
2745         $results = array(
2746             'notificationid' => $notification->id,
2747             'warnings' => $warnings
2748         );
2750         return $results;
2751     }
2753     /**
2754      * Returns description of method result value
2755      *
2756      * @return external_description
2757      */
2758     public static function mark_notification_read_returns() {
2759         return new external_single_structure(
2760             array(
2761                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2762                 'warnings' => new external_warnings()
2763             )
2764         );
2765     }
2767     /**
2768      * Mark all messages as read parameters description.
2769      *
2770      * @deprecated since 3.6
2771      * @return external_function_parameters
2772      * @since 3.2
2773      */
2774     public static function mark_all_messages_as_read_parameters() {
2775         return new external_function_parameters(
2776             array(
2777                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2778                 'useridfrom' => new external_value(
2779                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2780                     VALUE_DEFAULT, 0),
2781             )
2782         );
2783     }
2785     /**
2786      * Mark all messages as read function.
2787      *
2788      * @deprecated since 3.6
2789      * @throws invalid_parameter_exception
2790      * @throws moodle_exception
2791      * @param  int      $useridto       the user id who received the message
2792      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2793      * @return external_description
2794      * @since  3.2
2795      */
2796     public static function mark_all_messages_as_read($useridto, $useridfrom) {
2797         global $USER, $CFG;
2799         // Check if messaging is enabled.
2800         if (empty($CFG->messaging)) {
2801             throw new moodle_exception('disabled', 'message');
2802         }
2804         $params = self::validate_parameters(
2805             self::mark_all_messages_as_read_parameters(),
2806             array(
2807                 'useridto' => $useridto,
2808                 'useridfrom' => $useridfrom,
2809             )
2810         );
2812         $context = context_system::instance();
2813         self::validate_context($context);
2815         $useridto = $params['useridto'];
2816         $useridfrom = $params['useridfrom'];
2818         if (!empty($useridto)) {
2819             if (core_user::is_real_user($useridto)) {
2820                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2821             } else {
2822                 throw new moodle_exception('invaliduser');
2823             }
2824         }
2826         if (!empty($useridfrom)) {
2827             // We use get_user here because the from user can be the noreply or support user.
2828             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2829         }
2831         // Check if the current user is the sender/receiver or just a privileged user.
2832         if ($useridto != $USER->id and $useridfrom != $USER->id and
2833             // The deleteanymessage cap seems more reasonable here than readallmessages.
2834              !has_capability('moodle/site:deleteanymessage', $context)) {
2835             throw new moodle_exception('accessdenied', 'admin');
2836         }
2838         if ($useridfrom) {
2839             if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
2840                 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
2841             }
2842         } else {
2843             \core_message\api::mark_all_messages_as_read($useridto);
2844         }
2846         return true;
2847     }
2849     /**
2850      * Mark all messages as read return description.
2851      *
2852      * @deprecated since 3.6
2853      * @return external_single_structure
2854      * @since 3.2
2855      */
2856     public static function mark_all_messages_as_read_returns() {
2857         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2858     }
2860     /**
2861      * Marking the method as deprecated.
2862      *
2863      * @return bool
2864      */
2865     public static function mark_all_messages_as_read_is_deprecated() {
2866         return true;
2867     }
2869     /**
2870      * Mark all conversation messages as read parameters description.
2871      *
2872      * @return external_function_parameters
2873      * @since 3.6
2874      */
2875     public static function mark_all_conversation_messages_as_read_parameters() {
2876         return new external_function_parameters(
2877             array(
2878                 'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2879                 'conversationid' =>
2880                     new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2881             )
2882         );
2883     }
2885     /**
2886      * Mark all conversation messages as read function.
2887      *
2888      * @param int $userid The user id of who we want to delete the conversation for
2889      * @param int $conversationid The id of the conversations
2890      * @since 3.6
2891      */
2892     public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2893         global $CFG;
2895         // Check if messaging is enabled.
2896         if (empty($CFG->messaging)) {
2897             throw new moodle_exception('disabled', 'message');
2898         }
2900         $params = array(
2901             'userid' => $userid,
2902             'conversationid' => $conversationid,
2903         );
2904         $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2906         $context = context_system::instance();
2907         self::validate_context($context);
2909         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2910         core_user::require_active_user($user);
2912         if (\core_message\api::can_mark_all_messages_as_read($userid, $conversationid)) {
2913             \core_message\api::mark_all_messages_as_read($userid, $conversationid);
2914         } else {
2915             throw new moodle_exception('accessdenied', 'admin');
2916         }
2917     }
2919     /**
2920      * Mark all conversation messages as read return description.
2921      *
2922      * @return external_warnings
2923      * @since 3.6
2924      */
2925     public static function mark_all_conversation_messages_as_read_returns() {
2926         return new external_warnings();
2927     }
2929     /**
2930      * Returns description of method parameters.
2931      *
2932      * @deprecated since 3.6
2933      * @return external_function_parameters
2934      * @since 3.2
2935      */
2936     public static function delete_conversation_parameters() {
2937         return new external_function_parameters(
2938             array(
2939                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2940                 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
2941             )
2942         );
2943     }
2945     /**
2946      * Deletes a conversation.
2947      *
2948      * @deprecated since 3.6
2949      * @param int $userid The user id of who we want to delete the conversation for
2950      * @param int $otheruserid The user id of the other user in the conversation
2951      * @return array
2952      * @throws moodle_exception
2953      * @since 3.2
2954      */
2955     public static function delete_conversation($userid, $otheruserid) {
2956         global $CFG;
2958         // Check if private messaging between users is allowed.
2959         if (empty($CFG->messaging)) {
2960             throw new moodle_exception('disabled', 'message');
2961         }
2963         // Warnings array, it can be empty at the end but is mandatory.
2964         $warnings = array();
2966         // Validate params.
2967         $params = array(
2968             'userid' => $userid,
2969             'otheruserid' => $otheruserid,
2970         );
2971         $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
2973         // Validate context.
2974         $context = context_system::instance();
2975         self::validate_context($context);
2977         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2978         core_user::require_active_user($user);
2980         if (!$conversationid = \core_message\api::get_conversation_between_users([$userid, $otheruserid])) {
2981             return [];
2982         }
2984         if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2985             \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2986             $status = true;
2987         } else {
2988             throw new moodle_exception('You do not have permission to delete messages');
2989         }
2991         $results = array(
2992             'status' => $status,
2993             'warnings' => $warnings
2994         );
2996         return $results;
2997     }
2999     /**
3000      * Returns description of method result value.
3001      *
3002      * @deprecated since 3.6
3003      * @return external_description
3004      * @since 3.2
3005      */
3006     public static function delete_conversation_returns() {
3007         return new external_single_structure(
3008             array(
3009                 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
3010                 'warnings' => new external_warnings()
3011             )
3012         );
3013     }
3015     /**
3016      * Marking the method as deprecated.
3017      *
3018      * @return bool
3019      */
3020     public static function delete_conversation_is_deprecated() {
3021         return true;
3022     }
3024     /**
3025      * Returns description of method parameters.
3026      *
3027      * @return external_function_parameters
3028      * @since 3.6
3029      */
3030     public static function delete_conversations_by_id_parameters() {
3031         return new external_function_parameters(
3032             array(
3033                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
3034                 'conversationids' => new external_multiple_structure(
3035                     new external_value(PARAM_INT, 'The id of the conversation'),
3036                     'List of conversation IDs'
3037                 ),
3038             )
3039         );
3040     }
3042     /**
3043      * Deletes a conversation.
3044      *
3045      * @param int $userid The user id of who we want to delete the conversation for
3046      * @param int[] $conversationids The ids of the conversations
3047      * @return array
3048      * @throws moodle_exception
3049      * @since 3.6
3050      */
3051     public static function delete_conversations_by_id($userid, array $conversationids) {
3052         global $CFG;
3054         // Check if private messaging between users is allowed.
3055         if (empty($CFG->messaging)) {
3056             throw new moodle_exception('disabled', 'message');
3057         }
3059         // Validate params.
3060         $params = [
3061             'userid' => $userid,
3062             'conversationids' => $conversationids,
3063         ];
3064         $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
3066         // Validate context.
3067         $context = context_system::instance();
3068         self::validate_context($context);
3070         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3071         core_user::require_active_user($user);
3073         foreach ($conversationids as $conversationid) {
3074             if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
3075                 \core_message\api::delete_conversation_by_id($user->id, $conversationid);
3076             } else {
3077                 throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
3078             }
3079         }
3081         return [];
3082     }
3084     /**
3085      * Returns description of method result value.
3086      *
3087      * @return external_description
3088      * @since 3.6
3089      */
3090     public static function delete_conversations_by_id_returns() {
3091         return new external_warnings();
3092     }
3094     /**
3095      * Returns description of method parameters
3096      *
3097      * @return external_function_parameters
3098      * @since 3.1
3099      */
3100     public static function delete_message_parameters() {
3101         return new external_function_parameters(
3102             array(
3103                 'messageid' => new external_value(PARAM_INT, 'The message id'),
3104                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
3105                 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
3106             )
3107         );
3108     }
3110     /**
3111      * Deletes a message
3112      *
3113      * @param  int $messageid the message id
3114      * @param  int $userid the user id of who we want to delete the message for
3115      * @param  bool $read if is a message read (default to true)
3116      * @return external_description
3117      * @throws moodle_exception
3118      * @since 3.1
3119      */
3120     public static function delete_message($messageid, $userid, $read = true) {
3121         global $CFG;
3123         // Check if private messaging between users is allowed.
3124         if (empty($CFG->messaging)) {
3125             throw new moodle_exception('disabled', 'message');
3126         }
3128         // Warnings array, it can be empty at the end but is mandatory.
3129         $warnings = array();
3131         // Validate params.
3132         $params = array(
3133             'messageid' => $messageid,
3134             'userid' => $userid,
3135             'read' => $read
3136         );
3137         $params = self::validate_parameters(self::delete_message_parameters(), $params);
3139         // Validate context.
3140         $context = context_system::instance();
3141         self::validate_context($context);
3143         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3144         core_user::require_active_user($user);
3146         if (\core_message\api::can_delete_message($user->id, $messageid)) {
3147             $status = \core_message\api::delete_message($user->id, $messageid);
3148         } else {
3149             throw new moodle_exception('You do not have permission to delete this message');
3150         }
3152         $results = array(
3153             'status' => $status,
3154             'warnings' => $warnings
3155         );
3156         return $results;
3157     }
3159     /**
3160      * Returns description of method result value
3161      *
3162      * @return external_description
3163      * @since 3.1
3164      */
3165     public static function delete_message_returns() {
3166         return new external_single_structure(
3167             array(
3168                 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
3169                 'warnings' => new external_warnings()
3170             )
3171         );
3172     }
3174     /**
3175      * Returns description of method parameters
3176      *
3177      * @return external_function_parameters
3178      * @since 3.2
3179      */
3180     public static function message_processor_config_form_parameters() {
3181         return new external_function_parameters(
3182             array(
3183                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
3184                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
3185                 'formvalues' => new external_multiple_structure(
3186                     new external_single_structure(
3187                         array(
3188                             'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
3189                             'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
3190                         )
3191                     ),
3192                     'Config form values',
3193                     VALUE_REQUIRED
3194                 ),
3195             )
3196         );
3197     }
3199     /**
3200      * Processes a message processor config form.
3201      *
3202      * @param  int $userid the user id
3203      * @param  string $name the name of the processor
3204      * @param  array $formvalues the form values
3205      * @return external_description
3206      * @throws moodle_exception
3207      * @since 3.2
3208      */
3209     public static function message_processor_config_form($userid, $name, $formvalues) {
3210         global $USER, $CFG;
3212         // Check if messaging is enabled.
3213         if (empty($CFG->messaging)) {
3214             throw new moodle_exception('disabled', 'message');
3215         }
3217         $params = self::validate_parameters(
3218             self::message_processor_config_form_parameters(),
3219             array(
3220                 'userid' => $userid,
3221                 'name' => $name,
3222                 'formvalues' => $formvalues,
3223             )
3224         );
3226         $user = self::validate_preferences_permissions($params['userid']);
3228         $processor = get_message_processor($name);
3229         $preferences = [];
3230         $form = new stdClass();
3232         foreach ($formvalues as $formvalue) {
3233             // Curly braces to ensure interpretation is consistent between
3234             // php 5 and php 7.
3235             $form->{$formvalue['name']} = $formvalue['value'];
3236         }
3238         $processor->process_form($form, $preferences);
3240         if (!empty($preferences)) {
3241             set_user_preferences($preferences, $userid);
3242         }
3243     }
3245     /**
3246      * Returns description of method result value
3247      *
3248      * @return external_description
3249      * @since 3.2
3250      */
3251     public static function message_processor_config_form_returns() {
3252         return null;
3253     }
3255     /**
3256      * Returns description of method parameters
3257      *
3258      * @return external_function_parameters
3259      * @since 3.2
3260      */
3261     public static function get_message_processor_parameters() {
3262         return new external_function_parameters(
3263             array(
3264                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
3265                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
3266             )
3267         );
3268     }
3270     /**
3271      * Get a message processor.
3272      *
3273      * @param int $userid
3274      * @param string $name the name of the processor
3275      * @return external_description
3276      * @throws moodle_exception
3277      * @since 3.2
3278      */
3279     public static function get_message_processor($userid = 0, $name) {
3280         global $USER, $PAGE, $CFG;
3282         // Check if messaging is enabled.
3283         if (empty($CFG->messaging)) {
3284             throw new moodle_exception('disabled', 'message');
3285         }
3287         $params = self::validate_parameters(
3288             self::get_message_processor_parameters(),
3289             array(
3290                 'userid' => $userid,
3291                 'name' => $name,
3292             )
3293         );
3295         if (empty($params['userid'])) {
3296             $params['userid'] = $USER->id;
3297         }
3299         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
3300         core_user::require_active_user($user);
3301         self::validate_context(context_user::instance($params['userid']));
3303         $processor = get_message_processor($name);
3305         $processoroutput = new \core_message\output\processor($processor, $user);
3306         $renderer = $PAGE->get_renderer('core_message');
3308         return $processoroutput->export_for_template($renderer);
3309     }
3311     /**
3312      * Returns description of method result value
3313      *
3314      * @return external_description
3315      * @since 3.2
3316      */
3317     public static function get_message_processor_returns() {
3318         return new external_function_parameters(
3319             array(
3320                 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
3321                 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
3322             )
3323         );
3324     }
3326     /**
3327      * Check that the user has enough permission to retrieve message or notifications preferences.
3328      *
3329      * @param  int $userid the user id requesting the preferences
3330      * @return stdClass full user object
3331      * @throws moodle_exception
3332      * @since  Moodle 3.2
3333      */
3334     protected static function validate_preferences_permissions($userid) {
3335         global $USER;
3337         if (empty($userid)) {
3338             $user = $USER;
3339         } else {
3340             $user = core_user::get_user($userid, '*', MUST_EXIST);
3341             core_user::require_active_user($user);
3342         }
3344         $systemcontext = context_system::instance();
3345         self::validate_context($systemcontext);
3347         // Check access control.
3348         if ($user->id == $USER->id) {
3349             // Editing own message profile.
3350             require_capability('moodle/user:editownmessageprofile', $systemcontext);
3351         } else {
3352             // Teachers, parents, etc.
3353             $personalcontext = context_user::instance($user->id);
3354             require_capability('moodle/user:editmessageprofile', $personalcontext);
3355         }
3356         return $user;
3357     }
3359     /**
3360      * Returns a notification or message preference structure.
3361      *
3362      * @return external_single_structure the structure
3363      * @since  Moodle 3.2
3364      */
3365     protected static function get_preferences_structure() {
3366         return new external_single_structure(
3367             array(
3368                 'userid' => new external_value(PARAM_INT, 'User id'),
3369                 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3370                 'processors' => new external_multiple_structure(
3371                     new external_single_structure(
3372                         array(
3373                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3374                             'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3375                             'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3376                             'contextid' => new external_value(PARAM_INT, 'Context id'),
3377                             'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3378                         )
3379                     ),
3380                     'Config form values'
3381                 ),
3382                 'components' => new external_multiple_structure(
3383                     new external_single_structure(
3384                         array(
3385                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3386                             'notifications' => new external_multiple_structure(
3387                                 new external_single_structure(
3388                                     array(
3389                                         'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3390                                         'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3391                                         'processors' => new external_multiple_structure(
3392                                             new external_single_structure(
3393                                                 array(
3394                                                     'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3395                                                     'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3396                                                     'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3397                                                     'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3398                                                     'loggedin' => new external_single_structure(
3399                                                         array(
3400                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
3401                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3402                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3403                                                         )
3404                                                     ),
3405                                                     'loggedoff' => new external_single_structure(
3406                                                         array(
3407                                       &nb