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