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