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