43c94f394e063cd131a7431e29ed0f5a71a963f0
[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, SQL_PARAMS_NAMED, 'userid_');
94         $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
95         $blocklist   = array();
96         $contactlist = array();
97         $sqlparams['contactid'] = $USER->id;
98         $rs = $DB->get_recordset_sql("SELECT *
99                                         FROM {message_contacts}
100                                        WHERE userid $sqluserids
101                                              AND contactid = :contactid", $sqlparams);
102         foreach ($rs as $record) {
103             if ($record->blocked) {
104                 // $record->userid is blocking current user
105                 $blocklist[$record->userid] = true;
106             } else {
107                 // $record->userid have current user as contact
108                 $contactlist[$record->userid] = true;
109             }
110         }
111         $rs->close();
113         $canreadallmessages = has_capability('moodle/site:readallmessages', $context);
115         $resultmessages = array();
116         foreach ($params['messages'] as $message) {
117             $resultmsg = array(); //the infos about the success of the operation
119             //we are going to do some checking
120             //code should match /messages/index.php checks
121             $success = true;
123             //check the user exists
124             if (empty($tousers[$message['touserid']])) {
125                 $success = false;
126                 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
127             }
129             //check that the touser is not blocking the current user
130             if ($success and !empty($blocklist[$message['touserid']]) and !$canreadallmessages) {
131                 $success = false;
132                 $errormessage = get_string('userisblockingyou', 'message');
133             }
135             // Check if the user is a contact
136             //TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
137             $blocknoncontacts = get_user_preferences('message_blocknoncontacts', NULL, $message['touserid']);
138             // message_blocknoncontacts option is on and current user is not in contact list
139             if ($success && empty($contactlist[$message['touserid']]) && !empty($blocknoncontacts)) {
140                 // The user isn't a contact and they have selected to block non contacts so this message won't be sent.
141                 $success = false;
142                 $errormessage = get_string('userisblockingyounoncontact', 'message',
143                         fullname(core_user::get_user($message['touserid'])));
144             }
146             //now we can send the message (at least try)
147             if ($success) {
148                 //TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object
149                 $success = message_post_message($USER, $tousers[$message['touserid']],
150                         $message['text'], external_validate_format($message['textformat']));
151             }
153             //build the resultmsg
154             if (isset($message['clientmsgid'])) {
155                 $resultmsg['clientmsgid'] = $message['clientmsgid'];
156             }
157             if ($success) {
158                 $resultmsg['msgid'] = $success;
159             } else {
160                 // WARNINGS: for backward compatibility we return this errormessage.
161                 //          We should have thrown exceptions as these errors prevent results to be returned.
162                 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
163                 $resultmsg['msgid'] = -1;
164                 $resultmsg['errormessage'] = $errormessage;
165             }
167             $resultmessages[] = $resultmsg;
168         }
170         return $resultmessages;
171     }
173     /**
174      * Returns description of method result value
175      *
176      * @return external_description
177      * @since Moodle 2.2
178      */
179     public static function send_instant_messages_returns() {
180         return new external_multiple_structure(
181             new external_single_structure(
182                 array(
183                     'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
184                     'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
185                     'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
186                 )
187             )
188         );
189     }
191     /**
192      * Create contacts parameters description.
193      *
194      * @deprecated since Moodle 3.6
195      * @return external_function_parameters
196      * @since Moodle 2.5
197      */
198     public static function create_contacts_parameters() {
199         return new external_function_parameters(
200             array(
201                 'userids' => new external_multiple_structure(
202                     new external_value(PARAM_INT, 'User ID'),
203                     'List of user IDs'
204                 ),
205                 'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
206                     current user', VALUE_DEFAULT, 0)
207             )
208         );
209     }
211     /**
212      * Create contacts.
213      *
214      * @deprecated since Moodle 3.6
215      * @param array $userids array of user IDs.
216      * @param int $userid The id of the user we are creating the contacts for
217      * @return external_description
218      * @since Moodle 2.5
219      */
220     public static function create_contacts($userids, $userid = 0) {
221         global $CFG, $USER;
223         // Check if messaging is enabled.
224         if (empty($CFG->messaging)) {
225             throw new moodle_exception('disabled', 'message');
226         }
228         if (empty($userid)) {
229             $userid = $USER->id;
230         }
232         // Validate context.
233         $context = context_system::instance();
234         self::validate_context($context);
236         $capability = 'moodle/site:manageallmessaging';
237         if (($USER->id != $userid) && !has_capability($capability, $context)) {
238             throw new required_capability_exception($context, $capability, 'nopermissions', '');
239         }
241         $params = array('userids' => $userids, 'userid' => $userid);
242         $params = self::validate_parameters(self::create_contacts_parameters(), $params);
244         $warnings = array();
245         foreach ($params['userids'] as $id) {
246             if (!message_add_contact($id, 0, $userid)) {
247                 $warnings[] = array(
248                     'item' => 'user',
249                     'itemid' => $id,
250                     'warningcode' => 'contactnotcreated',
251                     'message' => 'The contact could not be created'
252                 );
253             }
254         }
255         return $warnings;
256     }
258     /**
259      * Create contacts return description.
260      *
261      * @deprecated since Moodle 3.6
262      * @return external_description
263      * @since Moodle 2.5
264      */
265     public static function create_contacts_returns() {
266         return new external_warnings();
267     }
269     /**
270      * Marking the method as deprecated.
271      *
272      * @return bool
273      */
274     public static function create_contacts_is_deprecated() {
275         return true;
276     }
278     /**
279      * Delete contacts parameters description.
280      *
281      * @return external_function_parameters
282      * @since Moodle 2.5
283      */
284     public static function delete_contacts_parameters() {
285         return new external_function_parameters(
286             array(
287                 'userids' => new external_multiple_structure(
288                     new external_value(PARAM_INT, 'User ID'),
289                     'List of user IDs'
290                 ),
291                 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
292                     current user', VALUE_DEFAULT, 0)
293             )
294         );
295     }
297     /**
298      * Delete contacts.
299      *
300      * @param array $userids array of user IDs.
301      * @param int $userid The id of the user we are deleting the contacts for
302      * @return null
303      * @since Moodle 2.5
304      */
305     public static function delete_contacts($userids, $userid = 0) {
306         global $CFG, $USER;
308         // Check if messaging is enabled.
309         if (empty($CFG->messaging)) {
310             throw new moodle_exception('disabled', 'message');
311         }
313         if (empty($userid)) {
314             $userid = $USER->id;
315         }
317         // Validate context.
318         $context = context_system::instance();
319         self::validate_context($context);
321         $capability = 'moodle/site:manageallmessaging';
322         if (($USER->id != $userid) && !has_capability($capability, $context)) {
323             throw new required_capability_exception($context, $capability, 'nopermissions', '');
324         }
326         $params = array('userids' => $userids, 'userid' => $userid);
327         $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
329         foreach ($params['userids'] as $id) {
330             message_remove_contact($id, $userid);
331         }
333         return null;
334     }
336     /**
337      * Delete contacts return description.
338      *
339      * @return external_description
340      * @since Moodle 2.5
341      */
342     public static function delete_contacts_returns() {
343         return null;
344     }
346     /**
347      * Block contacts parameters description.
348      *
349      * @deprecated since Moodle 3.6
350      * @return external_function_parameters
351      * @since Moodle 2.5
352      */
353     public static function block_contacts_parameters() {
354         return new external_function_parameters(
355             array(
356                 'userids' => new external_multiple_structure(
357                     new external_value(PARAM_INT, 'User ID'),
358                     'List of user IDs'
359                 ),
360                 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
361                     current user', VALUE_DEFAULT, 0)
362             )
363         );
364     }
366     /**
367      * Block contacts.
368      *
369      * @deprecated since Moodle 3.6
370      * @param array $userids array of user IDs.
371      * @param int $userid The id of the user we are blocking the contacts for
372      * @return external_description
373      * @since Moodle 2.5
374      */
375     public static function block_contacts($userids, $userid = 0) {
376         global $CFG, $USER;
378         // Check if messaging is enabled.
379         if (empty($CFG->messaging)) {
380             throw new moodle_exception('disabled', 'message');
381         }
383         if (empty($userid)) {
384             $userid = $USER->id;
385         }
387         // Validate context.
388         $context = context_system::instance();
389         self::validate_context($context);
391         $capability = 'moodle/site:manageallmessaging';
392         if (($USER->id != $userid) && !has_capability($capability, $context)) {
393             throw new required_capability_exception($context, $capability, 'nopermissions', '');
394         }
396         $params = array('userids' => $userids, 'userid' => $userid);
397         $params = self::validate_parameters(self::block_contacts_parameters(), $params);
399         $warnings = array();
400         foreach ($params['userids'] as $id) {
401             if (!message_block_contact($id, $userid)) {
402                 $warnings[] = array(
403                     'item' => 'user',
404                     'itemid' => $id,
405                     'warningcode' => 'contactnotblocked',
406                     'message' => 'The contact could not be blocked'
407                 );
408             }
409         }
410         return $warnings;
411     }
413     /**
414      * Block contacts return description.
415      *
416      * @deprecated since Moodle 3.6
417      * @return external_description
418      * @since Moodle 2.5
419      */
420     public static function block_contacts_returns() {
421         return new external_warnings();
422     }
424     /**
425      * Marking the method as deprecated.
426      *
427      * @return bool
428      */
429     public static function block_contacts_is_deprecated() {
430         return true;
431     }
433     /**
434      * Unblock contacts parameters description.
435      *
436      * @deprecated since Moodle 3.6
437      * @return external_function_parameters
438      * @since Moodle 2.5
439      */
440     public static function unblock_contacts_parameters() {
441         return new external_function_parameters(
442             array(
443                 'userids' => new external_multiple_structure(
444                     new external_value(PARAM_INT, 'User ID'),
445                     'List of user IDs'
446                 ),
447                 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
448                     current user', VALUE_DEFAULT, 0)
449             )
450         );
451     }
453     /**
454      * Unblock contacts.
455      *
456      * @deprecated since Moodle 3.6
457      * @param array $userids array of user IDs.
458      * @param int $userid The id of the user we are unblocking the contacts for
459      * @return null
460      * @since Moodle 2.5
461      */
462     public static function unblock_contacts($userids, $userid = 0) {
463         global $CFG, $USER;
465         // Check if messaging is enabled.
466         if (empty($CFG->messaging)) {
467             throw new moodle_exception('disabled', 'message');
468         }
470         if (empty($userid)) {
471             $userid = $USER->id;
472         }
474         // Validate context.
475         $context = context_system::instance();
476         self::validate_context($context);
478         $capability = 'moodle/site:manageallmessaging';
479         if (($USER->id != $userid) && !has_capability($capability, $context)) {
480             throw new required_capability_exception($context, $capability, 'nopermissions', '');
481         }
483         $params = array('userids' => $userids, 'userid' => $userid);
484         $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
486         foreach ($params['userids'] as $id) {
487             message_unblock_contact($id, $userid);
488         }
490         return null;
491     }
493     /**
494      * Unblock contacts return description.
495      *
496      * @deprecated since Moodle 3.6
497      * @return external_description
498      * @since Moodle 2.5
499      */
500     public static function unblock_contacts_returns() {
501         return null;
502     }
504     /**
505      * Marking the method as deprecated.
506      *
507      * @return bool
508      */
509     public static function unblock_contacts_is_deprecated() {
510         return true;
511     }
513     /**
514      * Return the structure of a message area contact.
515      *
516      * @return external_single_structure
517      * @since Moodle 3.2
518      */
519     private static function get_messagearea_contact_structure() {
520         return new external_single_structure(
521             array(
522                 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
523                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
524                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
525                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
526                 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
527                 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
528                 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
529                 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
530                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
531                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
532                 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
533                 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
534                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
535                     VALUE_DEFAULT, null),
536             )
537         );
538     }
540     /**
541      * Return the structure of a message area message.
542      *
543      * @return external_single_structure
544      * @since Moodle 3.2
545      */
546     private static function get_messagearea_message_structure() {
547         return new external_single_structure(
548             array(
549                 'id' => new external_value(PARAM_INT, 'The id of the message'),
550                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
551                 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
552                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
553                 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
554                 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
555                 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
556                 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
557                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
558                 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
559             )
560         );
561     }
563     /**
564      * Get messagearea search users in course parameters.
565      *
566      * @return external_function_parameters
567      * @since 3.2
568      */
569     public static function data_for_messagearea_search_users_in_course_parameters() {
570         return new external_function_parameters(
571             array(
572                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
573                 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
574                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
575                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
576                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
577             )
578         );
579     }
581     /**
582      * Get messagearea search users in course results.
583      *
584      * @param int $userid The id of the user who is performing the search
585      * @param int $courseid The id of the course
586      * @param string $search The string being searched
587      * @param int $limitfrom
588      * @param int $limitnum
589      * @return stdClass
590      * @throws moodle_exception
591      * @since 3.2
592      */
593     public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
594                                                                        $limitnum = 0) {
595         global $CFG, $PAGE, $USER;
597         // Check if messaging is enabled.
598         if (empty($CFG->messaging)) {
599             throw new moodle_exception('disabled', 'message');
600         }
602         $systemcontext = context_system::instance();
604         $params = array(
605             'userid' => $userid,
606             'courseid' => $courseid,
607             'search' => $search,
608             'limitfrom' => $limitfrom,
609             'limitnum' => $limitnum
610         );
611         self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
612         self::validate_context($systemcontext);
614         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
615             throw new moodle_exception('You do not have permission to perform this action.');
616         }
618         $users = \core_message\api::search_users_in_course($userid, $courseid, $search, $limitfrom, $limitnum);
619         $results = new \core_message\output\messagearea\user_search_results($users);
621         $renderer = $PAGE->get_renderer('core_message');
622         return $results->export_for_template($renderer);
623     }
625     /**
626      * Get messagearea search users in course returns.
627      *
628      * @return external_single_structure
629      * @since 3.2
630      */
631     public static function data_for_messagearea_search_users_in_course_returns() {
632         return new external_single_structure(
633             array(
634                 'contacts' => new external_multiple_structure(
635                     self::get_messagearea_contact_structure()
636                 ),
637             )
638         );
639     }
641     /**
642      * Get messagearea search users parameters.
643      *
644      * @return external_function_parameters
645      * @since 3.2
646      */
647     public static function data_for_messagearea_search_users_parameters() {
648         return new external_function_parameters(
649             array(
650                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
651                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
652                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
653             )
654         );
655     }
657     /**
658      * Get messagearea search users results.
659      *
660      * @param int $userid The id of the user who is performing the search
661      * @param string $search The string being searched
662      * @param int $limitnum
663      * @return stdClass
664      * @throws moodle_exception
665      * @since 3.2
666      */
667     public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
668         global $CFG, $PAGE, $USER;
670         // Check if messaging is enabled.
671         if (empty($CFG->messaging)) {
672             throw new moodle_exception('disabled', 'message');
673         }
675         $systemcontext = context_system::instance();
677         $params = array(
678             'userid' => $userid,
679             'search' => $search,
680             'limitnum' => $limitnum
681         );
682         self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
683         self::validate_context($systemcontext);
685         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
686             throw new moodle_exception('You do not have permission to perform this action.');
687         }
689         list($contacts, $courses, $noncontacts) = \core_message\api::search_users($userid, $search, $limitnum);
690         $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
692         $renderer = $PAGE->get_renderer('core_message');
693         return $search->export_for_template($renderer);
694     }
696     /**
697      * Get messagearea search users returns.
698      *
699      * @return external_single_structure
700      * @since 3.2
701      */
702     public static function data_for_messagearea_search_users_returns() {
703         return new external_single_structure(
704             array(
705                 'contacts' => new external_multiple_structure(
706                     self::get_messagearea_contact_structure()
707                 ),
708                 'courses' => new external_multiple_structure(
709                     new external_single_structure(
710                         array(
711                             'id' => new external_value(PARAM_INT, 'The course id'),
712                             'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
713                             'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
714                         )
715                     )
716                 ),
717                 'noncontacts' => new external_multiple_structure(
718                     self::get_messagearea_contact_structure()
719                 )
720             )
721         );
722     }
724     /**
725      * Get messagearea search messages parameters.
726      *
727      * @return external_function_parameters
728      * @since 3.2
729      */
730     public static function data_for_messagearea_search_messages_parameters() {
731         return new external_function_parameters(
732             array(
733                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
734                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
735                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
736                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
737             )
738         );
739     }
741     /**
742      * Get messagearea search messages results.
743      *
744      * @param int $userid The id of the user who is performing the search
745      * @param string $search The string being searched
746      * @param int $limitfrom
747      * @param int $limitnum
748      * @return stdClass
749      * @throws moodle_exception
750      * @since 3.2
751      */
752     public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
753         global $CFG, $PAGE, $USER;
755         // Check if messaging is enabled.
756         if (empty($CFG->messaging)) {
757             throw new moodle_exception('disabled', 'message');
758         }
760         $systemcontext = context_system::instance();
762         $params = array(
763             'userid' => $userid,
764             'search' => $search,
765             'limitfrom' => $limitfrom,
766             'limitnum' => $limitnum
768         );
769         self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
770         self::validate_context($systemcontext);
772         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
773             throw new moodle_exception('You do not have permission to perform this action.');
774         }
776         $messages = \core_message\api::search_messages($userid, $search, $limitfrom, $limitnum);
777         $results = new \core_message\output\messagearea\message_search_results($messages);
779         $renderer = $PAGE->get_renderer('core_message');
780         return $results->export_for_template($renderer);
781     }
783     /**
784      * Get messagearea search messages returns.
785      *
786      * @return external_single_structure
787      * @since 3.2
788      */
789     public static function data_for_messagearea_search_messages_returns() {
790         return new external_single_structure(
791             array(
792                 'contacts' => new external_multiple_structure(
793                     self::get_messagearea_contact_structure()
794                 )
795             )
796         );
797     }
799     /**
800      * The messagearea conversations parameters.
801      *
802      * @return external_function_parameters
803      * @since 3.2
804      */
805     public static function data_for_messagearea_conversations_parameters() {
806         return new external_function_parameters(
807             array(
808                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
809                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
810                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
811             )
812         );
813     }
815     /**
816      * Get messagearea conversations.
817      *
818      * @param int $userid The id of the user who we are viewing conversations for
819      * @param int $limitfrom
820      * @param int $limitnum
821      * @return stdClass
822      * @throws moodle_exception
823      * @since 3.2
824      */
825     public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
826         global $CFG, $PAGE, $USER;
828         // Check if messaging is enabled.
829         if (empty($CFG->messaging)) {
830             throw new moodle_exception('disabled', 'message');
831         }
833         $systemcontext = context_system::instance();
835         $params = array(
836             'userid' => $userid,
837             'limitfrom' => $limitfrom,
838             'limitnum' => $limitnum
839         );
840         self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
841         self::validate_context($systemcontext);
843         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
844             throw new moodle_exception('You do not have permission to perform this action.');
845         }
847         $conversations = \core_message\api::get_conversations($userid, $limitfrom, $limitnum);
848         $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
850         $renderer = $PAGE->get_renderer('core_message');
851         return $conversations->export_for_template($renderer);
852     }
854     /**
855      * The messagearea conversations return structure.
856      *
857      * @return external_single_structure
858      * @since 3.2
859      */
860     public static function data_for_messagearea_conversations_returns() {
861         return new external_single_structure(
862             array(
863                 'contacts' => new external_multiple_structure(
864                     self::get_messagearea_contact_structure()
865                 )
866             )
867         );
868     }
870     /**
871      * The messagearea contacts return parameters.
872      *
873      * @return external_function_parameters
874      * @since 3.2
875      */
876     public static function data_for_messagearea_contacts_parameters() {
877         return self::data_for_messagearea_conversations_parameters();
878     }
880     /**
881      * Get messagearea contacts parameters.
882      *
883      * @param int $userid The id of the user who we are viewing conversations for
884      * @param int $limitfrom
885      * @param int $limitnum
886      * @return stdClass
887      * @throws moodle_exception
888      * @since 3.2
889      */
890     public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
891         global $CFG, $PAGE, $USER;
893         // Check if messaging is enabled.
894         if (empty($CFG->messaging)) {
895             throw new moodle_exception('disabled', 'message');
896         }
898         $systemcontext = context_system::instance();
900         $params = array(
901             'userid' => $userid,
902             'limitfrom' => $limitfrom,
903             'limitnum' => $limitnum
904         );
905         self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
906         self::validate_context($systemcontext);
908         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
909             throw new moodle_exception('You do not have permission to perform this action.');
910         }
912         $contacts = \core_message\api::get_contacts($userid, $limitfrom, $limitnum);
913         $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
915         $renderer = $PAGE->get_renderer('core_message');
916         return $contacts->export_for_template($renderer);
917     }
919     /**
920      * The messagearea contacts return structure.
921      *
922      * @return external_single_structure
923      * @since 3.2
924      */
925     public static function data_for_messagearea_contacts_returns() {
926         return self::data_for_messagearea_conversations_returns();
927     }
929     /**
930      * The messagearea messages parameters.
931      *
932      * @return external_function_parameters
933      * @since 3.2
934      */
935     public static function data_for_messagearea_messages_parameters() {
936         return new external_function_parameters(
937             array(
938                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
939                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
940                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
941                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
942                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
943                 'timefrom' => new external_value(PARAM_INT,
944                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
945             )
946         );
947     }
949     /**
950      * Get messagearea messages.
951      *
952      * @param int $currentuserid The current user's id
953      * @param int $otheruserid The other user's id
954      * @param int $limitfrom
955      * @param int $limitnum
956      * @param boolean $newest
957      * @return stdClass
958      * @throws moodle_exception
959      * @since 3.2
960      */
961     public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
962                                                          $newest = false, $timefrom = 0) {
963         global $CFG, $PAGE, $USER;
965         // Check if messaging is enabled.
966         if (empty($CFG->messaging)) {
967             throw new moodle_exception('disabled', 'message');
968         }
970         $systemcontext = context_system::instance();
972         $params = array(
973             'currentuserid' => $currentuserid,
974             'otheruserid' => $otheruserid,
975             'limitfrom' => $limitfrom,
976             'limitnum' => $limitnum,
977             'newest' => $newest,
978             'timefrom' => $timefrom,
979         );
980         self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
981         self::validate_context($systemcontext);
983         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
984             throw new moodle_exception('You do not have permission to perform this action.');
985         }
987         if ($newest) {
988             $sort = 'timecreated DESC';
989         } else {
990             $sort = 'timecreated ASC';
991         }
993         // We need to enforce a one second delay on messages to avoid race conditions of current
994         // messages still being sent.
995         //
996         // There is a chance that we could request messages before the current time's
997         // second has elapsed and while other messages are being sent in that same second. In which
998         // case those messages will be lost.
999         //
1000         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1001         if (!empty($timefrom)) {
1002             $timeto = time() - 1;
1003         } else {
1004             $timeto = 0;
1005         }
1007         // No requesting messages from the current time, as stated above.
1008         if ($timefrom == time()) {
1009             $messages = [];
1010         } else {
1011             $messages = \core_message\api::get_messages($currentuserid, $otheruserid, $limitfrom,
1012                                                         $limitnum, $sort, $timefrom, $timeto);
1013         }
1015         $messages = new \core_message\output\messagearea\messages($currentuserid, $otheruserid, $messages);
1017         $renderer = $PAGE->get_renderer('core_message');
1018         return $messages->export_for_template($renderer);
1019     }
1021     /**
1022      * The messagearea messages return structure.
1023      *
1024      * @return external_single_structure
1025      * @since 3.2
1026      */
1027     public static function data_for_messagearea_messages_returns() {
1028         return new external_single_structure(
1029             array(
1030                 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1031                     the messages on behalf of?'),
1032                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1033                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1034                 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1035                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1036                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1037                 'messages' => new external_multiple_structure(
1038                     self::get_messagearea_message_structure()
1039                 ),
1040                 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1041             )
1042         );
1043     }
1045     /**
1046      * The get most recent message return parameters.
1047      *
1048      * @return external_function_parameters
1049      * @since 3.2
1050      */
1051     public static function data_for_messagearea_get_most_recent_message_parameters() {
1052         return new external_function_parameters(
1053             array(
1054                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1055                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1056             )
1057         );
1058     }
1060     /**
1061      * Get the most recent message in a conversation.
1062      *
1063      * @param int $currentuserid The current user's id
1064      * @param int $otheruserid The other user's id
1065      * @return stdClass
1066      * @throws moodle_exception
1067      * @since 3.2
1068      */
1069     public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
1070         global $CFG, $PAGE, $USER;
1072         // Check if messaging is enabled.
1073         if (empty($CFG->messaging)) {
1074             throw new moodle_exception('disabled', 'message');
1075         }
1077         $systemcontext = context_system::instance();
1079         $params = array(
1080             'currentuserid' => $currentuserid,
1081             'otheruserid' => $otheruserid
1082         );
1083         self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
1084         self::validate_context($systemcontext);
1086         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1087             throw new moodle_exception('You do not have permission to perform this action.');
1088         }
1090         $message = \core_message\api::get_most_recent_message($currentuserid, $otheruserid);
1091         $message = new \core_message\output\messagearea\message($message);
1093         $renderer = $PAGE->get_renderer('core_message');
1094         return $message->export_for_template($renderer);
1095     }
1097     /**
1098      * The get most recent message return structure.
1099      *
1100      * @return external_single_structure
1101      * @since 3.2
1102      */
1103     public static function data_for_messagearea_get_most_recent_message_returns() {
1104         return self::get_messagearea_message_structure();
1105     }
1107     /**
1108      * The get profile parameters.
1109      *
1110      * @return external_function_parameters
1111      * @since 3.2
1112      */
1113     public static function data_for_messagearea_get_profile_parameters() {
1114         return new external_function_parameters(
1115             array(
1116                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1117                 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
1118             )
1119         );
1120     }
1122     /**
1123      * Get the profile information for a contact.
1124      *
1125      * @param int $currentuserid The current user's id
1126      * @param int $otheruserid The id of the user whose profile we are viewing
1127      * @return stdClass
1128      * @throws moodle_exception
1129      * @since 3.2
1130      */
1131     public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
1132         global $CFG, $PAGE, $USER;
1134         // Check if messaging is enabled.
1135         if (empty($CFG->messaging)) {
1136             throw new moodle_exception('disabled', 'message');
1137         }
1139         $systemcontext = context_system::instance();
1141         $params = array(
1142             'currentuserid' => $currentuserid,
1143             'otheruserid' => $otheruserid
1144         );
1145         self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
1146         self::validate_context($systemcontext);
1148         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1149             throw new moodle_exception('You do not have permission to perform this action.');
1150         }
1152         $profile = \core_message\api::get_profile($currentuserid, $otheruserid);
1153         $profile = new \core_message\output\messagearea\profile($profile);
1155         $renderer = $PAGE->get_renderer('core_message');
1156         return $profile->export_for_template($renderer);
1157     }
1159     /**
1160      * The get profile return structure.
1161      *
1162      * @return external_single_structure
1163      * @since 3.2
1164      */
1165     public static function data_for_messagearea_get_profile_returns() {
1166         return new external_single_structure(
1167             array(
1168                 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
1169                 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
1170                 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
1171                 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
1172                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1173                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1174                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1175                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1176                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1177                 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
1178                 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
1179             )
1180         );
1181     }
1183     /**
1184      * Get contacts parameters description.
1185      *
1186      * @return external_function_parameters
1187      * @since Moodle 2.5
1188      */
1189     public static function get_contacts_parameters() {
1190         return new external_function_parameters(array());
1191     }
1193     /**
1194      * Get contacts.
1195      *
1196      * @return external_description
1197      * @since Moodle 2.5
1198      */
1199     public static function get_contacts() {
1200         global $CFG, $PAGE, $USER;
1202         // Check if messaging is enabled.
1203         if (empty($CFG->messaging)) {
1204             throw new moodle_exception('disabled', 'message');
1205         }
1207         require_once($CFG->dirroot . '/user/lib.php');
1209         $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
1210         $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
1211         foreach ($contacts as $contact) {
1212             // Set the mode.
1213             $mode = 'offline';
1214             if (\core_message\helper::is_online($contact->lastaccess)) {
1215                 $mode = 'online';
1216             }
1218             $newcontact = array(
1219                 'id' => $contact->id,
1220                 'fullname' => fullname($contact),
1221                 'unread' => $contact->messagecount
1222             );
1224             $userpicture = new user_picture($contact);
1225             $userpicture->size = 1; // Size f1.
1226             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1227             $userpicture->size = 0; // Size f2.
1228             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1230             $allcontacts[$mode][$contact->id] = $newcontact;
1231         }
1233         $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
1234         foreach ($strangers as $contact) {
1235             $newcontact = array(
1236                 'id' => $contact->id,
1237                 'fullname' => fullname($contact),
1238                 'unread' => $contact->messagecount
1239             );
1241             $userpicture = new user_picture($contact);
1242             $userpicture->size = 1; // Size f1.
1243             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1244             $userpicture->size = 0; // Size f2.
1245             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1247             $allcontacts['strangers'][$contact->id] = $newcontact;
1248         }
1250         // Add noreply user and support user to the list, if they don't exist.
1251         $supportuser = core_user::get_support_user();
1252         if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
1253             $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
1254             if ($supportuser->messagecount > 0) {
1255                 $supportuser->fullname = fullname($supportuser);
1256                 $supportuser->unread = $supportuser->messagecount;
1257                 $allcontacts['strangers'][$supportuser->id] = $supportuser;
1258             }
1259         }
1261         $noreplyuser = core_user::get_noreply_user();
1262         if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
1263             $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
1264             if ($noreplyuser->messagecount > 0) {
1265                 $noreplyuser->fullname = fullname($noreplyuser);
1266                 $noreplyuser->unread = $noreplyuser->messagecount;
1267                 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
1268             }
1269         }
1271         return $allcontacts;
1272     }
1274     /**
1275      * Get contacts return description.
1276      *
1277      * @return external_description
1278      * @since Moodle 2.5
1279      */
1280     public static function get_contacts_returns() {
1281         return new external_single_structure(
1282             array(
1283                 'online' => new external_multiple_structure(
1284                     new external_single_structure(
1285                         array(
1286                             'id' => new external_value(PARAM_INT, 'User ID'),
1287                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1288                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1289                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1290                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1291                         )
1292                     ),
1293                     'List of online contacts'
1294                 ),
1295                 'offline' => new external_multiple_structure(
1296                     new external_single_structure(
1297                         array(
1298                             'id' => new external_value(PARAM_INT, 'User ID'),
1299                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1300                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1301                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1302                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1303                         )
1304                     ),
1305                     'List of offline contacts'
1306                 ),
1307                 'strangers' => new external_multiple_structure(
1308                     new external_single_structure(
1309                         array(
1310                             'id' => new external_value(PARAM_INT, 'User ID'),
1311                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1312                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1313                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1314                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1315                         )
1316                     ),
1317                     'List of users that are not in the user\'s contact list but have sent a message'
1318                 )
1319             )
1320         );
1321     }
1323     /**
1324      * Search contacts parameters description.
1325      *
1326      * @return external_function_parameters
1327      * @since Moodle 2.5
1328      */
1329     public static function search_contacts_parameters() {
1330         return new external_function_parameters(
1331             array(
1332                 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1333                 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1334                     VALUE_DEFAULT, false)
1335             )
1336         );
1337     }
1339     /**
1340      * Search contacts.
1341      *
1342      * @param string $searchtext query string.
1343      * @param bool $onlymycourses limit the search to the user's courses only.
1344      * @return external_description
1345      * @since Moodle 2.5
1346      */
1347     public static function search_contacts($searchtext, $onlymycourses = false) {
1348         global $CFG, $USER, $PAGE;
1349         require_once($CFG->dirroot . '/user/lib.php');
1351         // Check if messaging is enabled.
1352         if (empty($CFG->messaging)) {
1353             throw new moodle_exception('disabled', 'message');
1354         }
1356         require_once($CFG->libdir . '/enrollib.php');
1358         $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1359         $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1361         // Extra validation, we do not allow empty queries.
1362         if ($params['searchtext'] === '') {
1363             throw new moodle_exception('querystringcannotbeempty');
1364         }
1366         $courseids = array();
1367         if ($params['onlymycourses']) {
1368             $mycourses = enrol_get_my_courses(array('id'));
1369             foreach ($mycourses as $mycourse) {
1370                 $courseids[] = $mycourse->id;
1371             }
1372         } else {
1373             $courseids[] = SITEID;
1374         }
1376         // Retrieving the users matching the query.
1377         $users = message_search_users($courseids, $params['searchtext']);
1378         $results = array();
1379         foreach ($users as $user) {
1380             $results[$user->id] = $user;
1381         }
1383         // Reorganising information.
1384         foreach ($results as &$user) {
1385             $newuser = array(
1386                 'id' => $user->id,
1387                 'fullname' => fullname($user)
1388             );
1390             // Avoid undefined property notice as phone not specified.
1391             $user->phone1 = null;
1392             $user->phone2 = null;
1394             $userpicture = new user_picture($user);
1395             $userpicture->size = 1; // Size f1.
1396             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1397             $userpicture->size = 0; // Size f2.
1398             $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1400             $user = $newuser;
1401         }
1403         return $results;
1404     }
1406     /**
1407      * Search contacts return description.
1408      *
1409      * @return external_description
1410      * @since Moodle 2.5
1411      */
1412     public static function search_contacts_returns() {
1413         return new external_multiple_structure(
1414             new external_single_structure(
1415                 array(
1416                     'id' => new external_value(PARAM_INT, 'User ID'),
1417                     'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1418                     'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1419                     'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1420                 )
1421             ),
1422             'List of contacts'
1423         );
1424     }
1426     /**
1427      * Get messages parameters description.
1428      *
1429      * @return external_function_parameters
1430      * @since 2.8
1431      */
1432     public static function get_messages_parameters() {
1433         return new external_function_parameters(
1434             array(
1435                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1436                 'useridfrom' => new external_value(
1437                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1438                     VALUE_DEFAULT, 0),
1439                 'type' => new external_value(
1440                     PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1441                     VALUE_DEFAULT, 'both'),
1442                 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
1443                 'newestfirst' => new external_value(
1444                     PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1445                     VALUE_DEFAULT, true),
1446                 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1447                 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1448             )
1449         );
1450     }
1452     /**
1453      * Get messages function implementation.
1454      *
1455      * @since  2.8
1456      * @throws invalid_parameter_exception
1457      * @throws moodle_exception
1458      * @param  int      $useridto       the user id who received the message
1459      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
1460      * @param  string   $type           type of message to return, expected values: notifications, conversations and both
1461      * @param  bool     $read           true for retreiving read messages, false for unread
1462      * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
1463      * @param  int      $limitfrom      limit from
1464      * @param  int      $limitnum       limit num
1465      * @return external_description
1466      */
1467     public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
1468                                         $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
1469         global $CFG, $USER;
1471         $warnings = array();
1473         $params = array(
1474             'useridto' => $useridto,
1475             'useridfrom' => $useridfrom,
1476             'type' => $type,
1477             'read' => $read,
1478             'newestfirst' => $newestfirst,
1479             'limitfrom' => $limitfrom,
1480             'limitnum' => $limitnum
1481         );
1483         $params = self::validate_parameters(self::get_messages_parameters(), $params);
1485         $context = context_system::instance();
1486         self::validate_context($context);
1488         $useridto = $params['useridto'];
1489         $useridfrom = $params['useridfrom'];
1490         $type = $params['type'];
1491         $read = $params['read'];
1492         $newestfirst = $params['newestfirst'];
1493         $limitfrom = $params['limitfrom'];
1494         $limitnum = $params['limitnum'];
1496         $allowedvalues = array('notifications', 'conversations', 'both');
1497         if (!in_array($type, $allowedvalues)) {
1498             throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
1499                 'allowed values are: ' . implode(',', $allowedvalues));
1500         }
1502         // Check if private messaging between users is allowed.
1503         if (empty($CFG->messaging)) {
1504             // If we are retreiving only conversations, and messaging is disabled, throw an exception.
1505             if ($type == "conversations") {
1506                 throw new moodle_exception('disabled', 'message');
1507             }
1508             if ($type == "both") {
1509                 $warning = array();
1510                 $warning['item'] = 'message';
1511                 $warning['itemid'] = $USER->id;
1512                 $warning['warningcode'] = '1';
1513                 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
1514                     Only notifications will be returned';
1515                 $warnings[] = $warning;
1516             }
1517         }
1519         if (!empty($useridto)) {
1520             if (core_user::is_real_user($useridto)) {
1521                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
1522             } else {
1523                 throw new moodle_exception('invaliduser');
1524             }
1525         }
1527         if (!empty($useridfrom)) {
1528             // We use get_user here because the from user can be the noreply or support user.
1529             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
1530         }
1532         // Check if the current user is the sender/receiver or just a privileged user.
1533         if ($useridto != $USER->id and $useridfrom != $USER->id and
1534              !has_capability('moodle/site:readallmessages', $context)) {
1535             throw new moodle_exception('accessdenied', 'admin');
1536         }
1538         // Which type of messages to retrieve.
1539         $notifications = -1;
1540         if ($type != 'both') {
1541             $notifications = ($type == 'notifications') ? 1 : 0;
1542         }
1544         $orderdirection = $newestfirst ? 'DESC' : 'ASC';
1545         $sort = "mr.timecreated $orderdirection";
1547         if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
1548             $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
1550             // In some cases, we don't need to get the to/from user objects from the sql query.
1551             $userfromfullname = '';
1552             $usertofullname = '';
1554             // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
1555             if (!empty($useridto)) {
1556                 $usertofullname = fullname($userto, $canviewfullname);
1557                 // The user from may or may not be filled.
1558                 if (!empty($useridfrom)) {
1559                     $userfromfullname = fullname($userfrom, $canviewfullname);
1560                 }
1561             } else {
1562                 // If the useridto field is empty, the useridfrom must be filled.
1563                 $userfromfullname = fullname($userfrom, $canviewfullname);
1564             }
1565             foreach ($messages as $mid => $message) {
1567                 // Do not return deleted messages.
1568                 if (!$message->notification) {
1569                     if (($useridto == $USER->id and $message->timeusertodeleted) or
1570                         ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
1571                         unset($messages[$mid]);
1572                         continue;
1573                     }
1574                 }
1576                 // We need to get the user from the query.
1577                 if (empty($userfromfullname)) {
1578                     // Check for non-reply and support users.
1579                     if (core_user::is_real_user($message->useridfrom)) {
1580                         $user = new stdClass();
1581                         $user = username_load_fields_from_object($user, $message, 'userfrom');
1582                         $message->userfromfullname = fullname($user, $canviewfullname);
1583                     } else {
1584                         $user = core_user::get_user($message->useridfrom);
1585                         $message->userfromfullname = fullname($user, $canviewfullname);
1586                     }
1587                 } else {
1588                     $message->userfromfullname = $userfromfullname;
1589                 }
1591                 // We need to get the user from the query.
1592                 if (empty($usertofullname)) {
1593                     $user = new stdClass();
1594                     $user = username_load_fields_from_object($user, $message, 'userto');
1595                     $message->usertofullname = fullname($user, $canviewfullname);
1596                 } else {
1597                     $message->usertofullname = $usertofullname;
1598                 }
1600                 $message->text = message_format_message_text($message);
1601                 $messages[$mid] = (array) $message;
1602             }
1603         }
1605         $results = array(
1606             'messages' => $messages,
1607             'warnings' => $warnings
1608         );
1610         return $results;
1611     }
1613     /**
1614      * Get messages return description.
1615      *
1616      * @return external_single_structure
1617      * @since 2.8
1618      */
1619     public static function get_messages_returns() {
1620         return new external_single_structure(
1621             array(
1622                 'messages' => new external_multiple_structure(
1623                     new external_single_structure(
1624                         array(
1625                             'id' => new external_value(PARAM_INT, 'Message id'),
1626                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
1627                             'useridto' => new external_value(PARAM_INT, 'User to id'),
1628                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
1629                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
1630                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
1631                             'fullmessageformat' => new external_format_value('fullmessage'),
1632                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
1633                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
1634                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
1635                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
1636                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
1637                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
1638                             'timeread' => new external_value(PARAM_INT, 'Time read'),
1639                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
1640                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
1641                         ), 'message'
1642                     )
1643                 ),
1644                 'warnings' => new external_warnings()
1645             )
1646         );
1647     }
1649     /**
1650      * Mark all notifications as read parameters description.
1651      *
1652      * @return external_function_parameters
1653      * @since 3.2
1654      */
1655     public static function mark_all_notifications_as_read_parameters() {
1656         return new external_function_parameters(
1657             array(
1658                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1659                 'useridfrom' => new external_value(
1660                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1661                     VALUE_DEFAULT, 0),
1662             )
1663         );
1664     }
1666     /**
1667      * Mark all notifications as read function.
1668      *
1669      * @since  3.2
1670      * @throws invalid_parameter_exception
1671      * @throws moodle_exception
1672      * @param  int      $useridto       the user id who received the message
1673      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
1674      * @return external_description
1675      */
1676     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
1677         global $USER;
1679         $params = self::validate_parameters(
1680             self::mark_all_notifications_as_read_parameters(),
1681             array(
1682                 'useridto' => $useridto,
1683                 'useridfrom' => $useridfrom,
1684             )
1685         );
1687         $context = context_system::instance();
1688         self::validate_context($context);
1690         $useridto = $params['useridto'];
1691         $useridfrom = $params['useridfrom'];
1693         if (!empty($useridto)) {
1694             if (core_user::is_real_user($useridto)) {
1695                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
1696             } else {
1697                 throw new moodle_exception('invaliduser');
1698             }
1699         }
1701         if (!empty($useridfrom)) {
1702             // We use get_user here because the from user can be the noreply or support user.
1703             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
1704         }
1706         // Check if the current user is the sender/receiver or just a privileged user.
1707         if ($useridto != $USER->id and $useridfrom != $USER->id and
1708             // The deleteanymessage cap seems more reasonable here than readallmessages.
1709              !has_capability('moodle/site:deleteanymessage', $context)) {
1710             throw new moodle_exception('accessdenied', 'admin');
1711         }
1713         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
1715         return true;
1716     }
1718     /**
1719      * Mark all notifications as read return description.
1720      *
1721      * @return external_single_structure
1722      * @since 3.2
1723      */
1724     public static function mark_all_notifications_as_read_returns() {
1725         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
1726     }
1728     /**
1729      * Get unread conversations count parameters description.
1730      *
1731      * @return external_function_parameters
1732      * @since 3.2
1733      */
1734     public static function get_unread_conversations_count_parameters() {
1735         return new external_function_parameters(
1736             array(
1737                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1738             )
1739         );
1740     }
1742     /**
1743      * Get unread messages count function.
1744      *
1745      * @since  3.2
1746      * @throws invalid_parameter_exception
1747      * @throws moodle_exception
1748      * @param  int      $useridto       the user id who received the message
1749      * @return external_description
1750      */
1751     public static function get_unread_conversations_count($useridto) {
1752         global $USER, $CFG;
1754         // Check if messaging is enabled.
1755         if (empty($CFG->messaging)) {
1756             throw new moodle_exception('disabled', 'message');
1757         }
1759         $params = self::validate_parameters(
1760             self::get_unread_conversations_count_parameters(),
1761             array('useridto' => $useridto)
1762         );
1764         $context = context_system::instance();
1765         self::validate_context($context);
1767         $useridto = $params['useridto'];
1769         if (!empty($useridto)) {
1770             if (core_user::is_real_user($useridto)) {
1771                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
1772             } else {
1773                 throw new moodle_exception('invaliduser');
1774             }
1775         } else {
1776             $useridto = $USER->id;
1777         }
1779         // Check if the current user is the receiver or just a privileged user.
1780         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
1781             throw new moodle_exception('accessdenied', 'admin');
1782         }
1784         return \core_message\api::count_unread_conversations($userto);
1785     }
1787     /**
1788      * Get unread conversations count return description.
1789      *
1790      * @return external_single_structure
1791      * @since 3.2
1792      */
1793     public static function get_unread_conversations_count_returns() {
1794         return new external_value(PARAM_INT, 'The count of unread messages for the user');
1795     }
1797     /**
1798      * Get blocked users parameters description.
1799      *
1800      * @return external_function_parameters
1801      * @since 2.9
1802      */
1803     public static function get_blocked_users_parameters() {
1804         return new external_function_parameters(
1805             array(
1806                 'userid' => new external_value(PARAM_INT,
1807                                 'the user whose blocked users we want to retrieve',
1808                                 VALUE_REQUIRED),
1809             )
1810         );
1811     }
1813     /**
1814      * Retrieve a list of users blocked
1815      *
1816      * @param  int $userid the user whose blocked users we want to retrieve
1817      * @return external_description
1818      * @since 2.9
1819      */
1820     public static function get_blocked_users($userid) {
1821         global $CFG, $USER, $PAGE;
1823         // Warnings array, it can be empty at the end but is mandatory.
1824         $warnings = array();
1826         // Validate params.
1827         $params = array(
1828             'userid' => $userid
1829         );
1830         $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
1831         $userid = $params['userid'];
1833         // Validate context.
1834         $context = context_system::instance();
1835         self::validate_context($context);
1837         // Check if private messaging between users is allowed.
1838         if (empty($CFG->messaging)) {
1839             throw new moodle_exception('disabled', 'message');
1840         }
1842         $user = core_user::get_user($userid, '*', MUST_EXIST);
1843         core_user::require_active_user($user);
1845         // Check if we have permissions for retrieve the information.
1846         $capability = 'moodle/site:manageallmessaging';
1847         if (($USER->id != $userid) && !has_capability($capability, $context)) {
1848             throw new required_capability_exception($context, $capability, 'nopermissions', '');
1849         }
1851         // Now, we can get safely all the blocked users.
1852         $users = \core_message\api::get_blocked_users($user->id);
1854         $blockedusers = array();
1855         foreach ($users as $user) {
1856             $newuser = array(
1857                 'id' => $user->id,
1858                 'fullname' => fullname($user),
1859             );
1861             $userpicture = new user_picture($user);
1862             $userpicture->size = 1; // Size f1.
1863             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1865             $blockedusers[] = $newuser;
1866         }
1868         $results = array(
1869             'users' => $blockedusers,
1870             'warnings' => $warnings
1871         );
1872         return $results;
1873     }
1875     /**
1876      * Get blocked users return description.
1877      *
1878      * @return external_single_structure
1879      * @since 2.9
1880      */
1881     public static function get_blocked_users_returns() {
1882         return new external_single_structure(
1883             array(
1884                 'users' => new external_multiple_structure(
1885                     new external_single_structure(
1886                         array(
1887                             'id' => new external_value(PARAM_INT, 'User ID'),
1888                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1889                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
1890                         )
1891                     ),
1892                     'List of blocked users'
1893                 ),
1894                 'warnings' => new external_warnings()
1895             )
1896         );
1897     }
1899     /**
1900      * Returns description of method parameters
1901      *
1902      * @return external_function_parameters
1903      * @since 2.9
1904      */
1905     public static function mark_message_read_parameters() {
1906         return new external_function_parameters(
1907             array(
1908                 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
1909                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
1910                     VALUE_DEFAULT, 0)
1911             )
1912         );
1913     }
1915     /**
1916      * Mark a single message as read, trigger message_viewed event
1917      *
1918      * @param  int $messageid id of the message (in the message table)
1919      * @param  int $timeread timestamp for when the message should be marked read
1920      * @return external_description
1921      * @throws invalid_parameter_exception
1922      * @throws moodle_exception
1923      * @since 2.9
1924      */
1925     public static function mark_message_read($messageid, $timeread) {
1926         global $CFG, $DB, $USER;
1928         // Check if private messaging between users is allowed.
1929         if (empty($CFG->messaging)) {
1930             throw new moodle_exception('disabled', 'message');
1931         }
1933         // Warnings array, it can be empty at the end but is mandatory.
1934         $warnings = array();
1936         // Validate params.
1937         $params = array(
1938             'messageid' => $messageid,
1939             'timeread' => $timeread
1940         );
1941         $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
1943         if (empty($params['timeread'])) {
1944             $timeread = time();
1945         } else {
1946             $timeread = $params['timeread'];
1947         }
1949         // Validate context.
1950         $context = context_system::instance();
1951         self::validate_context($context);
1953         $sql = "SELECT m.*, mcm.userid as useridto
1954                   FROM {messages} m
1955             INNER JOIN {message_conversations} mc
1956                     ON m.conversationid = mc.id
1957             INNER JOIN {message_conversation_members} mcm
1958                     ON mcm.conversationid = mc.id
1959              LEFT JOIN {message_user_actions} mua
1960                     ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
1961                  WHERE mua.id is NULL
1962                    AND mcm.userid != m.useridfrom
1963                    AND m.id = ?";
1964         $messageparams = [];
1965         $messageparams[] = $USER->id;
1966         $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
1967         $messageparams[] = $params['messageid'];
1968         $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
1970         if ($message->useridto != $USER->id) {
1971             throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
1972         }
1974         \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
1976         $results = array(
1977             'messageid' => $message->id,
1978             'warnings' => $warnings
1979         );
1980         return $results;
1981     }
1983     /**
1984      * Returns description of method result value
1985      *
1986      * @return external_description
1987      * @since 2.9
1988      */
1989     public static function mark_message_read_returns() {
1990         return new external_single_structure(
1991             array(
1992                 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
1993                 'warnings' => new external_warnings()
1994             )
1995         );
1996     }
1998     /**
1999      * Returns description of method parameters
2000      *
2001      * @return external_function_parameters
2002      */
2003     public static function mark_notification_read_parameters() {
2004         return new external_function_parameters(
2005             array(
2006                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2007                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2008                     VALUE_DEFAULT, 0)
2009             )
2010         );
2011     }
2013     /**
2014      * Mark a single notification as read.
2015      *
2016      * This will trigger a 'notification_viewed' event.
2017      *
2018      * @param int $notificationid id of the notification
2019      * @param int $timeread timestamp for when the notification should be marked read
2020      * @return external_description
2021      * @throws invalid_parameter_exception
2022      * @throws moodle_exception
2023      */
2024     public static function mark_notification_read($notificationid, $timeread) {
2025         global $CFG, $DB, $USER;
2027         // Check if private messaging between users is allowed.
2028         if (empty($CFG->messaging)) {
2029             throw new moodle_exception('disabled', 'message');
2030         }
2032         // Warnings array, it can be empty at the end but is mandatory.
2033         $warnings = array();
2035         // Validate params.
2036         $params = array(
2037             'notificationid' => $notificationid,
2038             'timeread' => $timeread
2039         );
2040         $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2042         if (empty($params['timeread'])) {
2043             $timeread = time();
2044         } else {
2045             $timeread = $params['timeread'];
2046         }
2048         // Validate context.
2049         $context = context_system::instance();
2050         self::validate_context($context);
2052         $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2054         if ($notification->useridto != $USER->id) {
2055             throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2056                 'notification as read');
2057         }
2059         \core_message\api::mark_notification_as_read($notification, $timeread);
2061         $results = array(
2062             'notificationid' => $notification->id,
2063             'warnings' => $warnings
2064         );
2066         return $results;
2067     }
2069     /**
2070      * Returns description of method result value
2071      *
2072      * @return external_description
2073      */
2074     public static function mark_notification_read_returns() {
2075         return new external_single_structure(
2076             array(
2077                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2078                 'warnings' => new external_warnings()
2079             )
2080         );
2081     }
2083     /**
2084      * Mark all messages as read parameters description.
2085      *
2086      * @return external_function_parameters
2087      * @since 3.2
2088      */
2089     public static function mark_all_messages_as_read_parameters() {
2090         return new external_function_parameters(
2091             array(
2092                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2093                 'useridfrom' => new external_value(
2094                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2095                     VALUE_DEFAULT, 0),
2096             )
2097         );
2098     }
2100     /**
2101      * Mark all notifications as read function.
2102      *
2103      * @since  3.2
2104      * @throws invalid_parameter_exception
2105      * @throws moodle_exception
2106      * @param  int      $useridto       the user id who received the message
2107      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2108      * @return external_description
2109      */
2110     public static function mark_all_messages_as_read($useridto, $useridfrom) {
2111         global $USER, $CFG;
2113         // Check if messaging is enabled.
2114         if (empty($CFG->messaging)) {
2115             throw new moodle_exception('disabled', 'message');
2116         }
2118         $params = self::validate_parameters(
2119             self::mark_all_messages_as_read_parameters(),
2120             array(
2121                 'useridto' => $useridto,
2122                 'useridfrom' => $useridfrom,
2123             )
2124         );
2126         $context = context_system::instance();
2127         self::validate_context($context);
2129         $useridto = $params['useridto'];
2130         $useridfrom = $params['useridfrom'];
2132         if (!empty($useridto)) {
2133             if (core_user::is_real_user($useridto)) {
2134                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2135             } else {
2136                 throw new moodle_exception('invaliduser');
2137             }
2138         }
2140         if (!empty($useridfrom)) {
2141             // We use get_user here because the from user can be the noreply or support user.
2142             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2143         }
2145         // Check if the current user is the sender/receiver or just a privileged user.
2146         if ($useridto != $USER->id and $useridfrom != $USER->id and
2147             // The deleteanymessage cap seems more reasonable here than readallmessages.
2148              !has_capability('moodle/site:deleteanymessage', $context)) {
2149             throw new moodle_exception('accessdenied', 'admin');
2150         }
2152         if ($useridfrom) {
2153             if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
2154                 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
2155             }
2156         } else {
2157             \core_message\api::mark_all_messages_as_read($useridto);
2158         }
2160         return true;
2161     }
2163     /**
2164      * Mark all notifications as read return description.
2165      *
2166      * @return external_single_structure
2167      * @since 3.2
2168      */
2169     public static function mark_all_messages_as_read_returns() {
2170         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2171     }
2173     /**
2174      * Returns description of method parameters.
2175      *
2176      * @return external_function_parameters
2177      * @since 3.2
2178      */
2179     public static function delete_conversation_parameters() {
2180         return new external_function_parameters(
2181             array(
2182                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2183                 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
2184             )
2185         );
2186     }
2188     /**
2189      * Deletes a conversation.
2190      *
2191      * @param int $userid The user id of who we want to delete the conversation for
2192      * @param int $otheruserid The user id of the other user in the conversation
2193      * @return array
2194      * @throws moodle_exception
2195      * @since 3.2
2196      */
2197     public static function delete_conversation($userid, $otheruserid) {
2198         global $CFG;
2200         // Check if private messaging between users is allowed.
2201         if (empty($CFG->messaging)) {
2202             throw new moodle_exception('disabled', 'message');
2203         }
2205         // Warnings array, it can be empty at the end but is mandatory.
2206         $warnings = array();
2208         // Validate params.
2209         $params = array(
2210             'userid' => $userid,
2211             'otheruserid' => $otheruserid,
2212         );
2213         $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
2215         // Validate context.
2216         $context = context_system::instance();
2217         self::validate_context($context);
2219         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2220         core_user::require_active_user($user);
2222         if (\core_message\api::can_delete_conversation($user->id)) {
2223             $status = \core_message\api::delete_conversation($user->id, $otheruserid);
2224         } else {
2225             throw new moodle_exception('You do not have permission to delete messages');
2226         }
2228         $results = array(
2229             'status' => $status,
2230             'warnings' => $warnings
2231         );
2233         return $results;
2234     }
2236     /**
2237      * Returns description of method result value.
2238      *
2239      * @return external_description
2240      * @since 3.2
2241      */
2242     public static function delete_conversation_returns() {
2243         return new external_single_structure(
2244             array(
2245                 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
2246                 'warnings' => new external_warnings()
2247             )
2248         );
2249     }
2251     /**
2252      * Returns description of method parameters
2253      *
2254      * @return external_function_parameters
2255      * @since 3.1
2256      */
2257     public static function delete_message_parameters() {
2258         return new external_function_parameters(
2259             array(
2260                 'messageid' => new external_value(PARAM_INT, 'The message id'),
2261                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2262                 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2263             )
2264         );
2265     }
2267     /**
2268      * Deletes a message
2269      *
2270      * @param  int $messageid the message id
2271      * @param  int $userid the user id of who we want to delete the message for
2272      * @param  bool $read if is a message read (default to true)
2273      * @return external_description
2274      * @throws moodle_exception
2275      * @since 3.1
2276      */
2277     public static function delete_message($messageid, $userid, $read = true) {
2278         global $CFG;
2280         // Check if private messaging between users is allowed.
2281         if (empty($CFG->messaging)) {
2282             throw new moodle_exception('disabled', 'message');
2283         }
2285         // Warnings array, it can be empty at the end but is mandatory.
2286         $warnings = array();
2288         // Validate params.
2289         $params = array(
2290             'messageid' => $messageid,
2291             'userid' => $userid,
2292             'read' => $read
2293         );
2294         $params = self::validate_parameters(self::delete_message_parameters(), $params);
2296         // Validate context.
2297         $context = context_system::instance();
2298         self::validate_context($context);
2300         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2301         core_user::require_active_user($user);
2303         if (\core_message\api::can_delete_message($user->id, $messageid)) {
2304             $status = \core_message\api::delete_message($user->id, $messageid);
2305         } else {
2306             throw new moodle_exception('You do not have permission to delete this message');
2307         }
2309         $results = array(
2310             'status' => $status,
2311             'warnings' => $warnings
2312         );
2313         return $results;
2314     }
2316     /**
2317      * Returns description of method result value
2318      *
2319      * @return external_description
2320      * @since 3.1
2321      */
2322     public static function delete_message_returns() {
2323         return new external_single_structure(
2324             array(
2325                 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2326                 'warnings' => new external_warnings()
2327             )
2328         );
2329     }
2331     /**
2332      * Returns description of method parameters
2333      *
2334      * @return external_function_parameters
2335      * @since 3.2
2336      */
2337     public static function message_processor_config_form_parameters() {
2338         return new external_function_parameters(
2339             array(
2340                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2341                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
2342                 'formvalues' => new external_multiple_structure(
2343                     new external_single_structure(
2344                         array(
2345                             'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2346                             'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2347                         )
2348                     ),
2349                     'Config form values',
2350                     VALUE_REQUIRED
2351                 ),
2352             )
2353         );
2354     }
2356     /**
2357      * Processes a message processor config form.
2358      *
2359      * @param  int $userid the user id
2360      * @param  string $name the name of the processor
2361      * @param  array $formvalues the form values
2362      * @return external_description
2363      * @throws moodle_exception
2364      * @since 3.2
2365      */
2366     public static function message_processor_config_form($userid, $name, $formvalues) {
2367         global $USER, $CFG;
2369         // Check if messaging is enabled.
2370         if (empty($CFG->messaging)) {
2371             throw new moodle_exception('disabled', 'message');
2372         }
2374         $params = self::validate_parameters(
2375             self::message_processor_config_form_parameters(),
2376             array(
2377                 'userid' => $userid,
2378                 'name' => $name,
2379                 'formvalues' => $formvalues,
2380             )
2381         );
2383         $user = self::validate_preferences_permissions($params['userid']);
2385         $processor = get_message_processor($name);
2386         $preferences = [];
2387         $form = new stdClass();
2389         foreach ($formvalues as $formvalue) {
2390             // Curly braces to ensure interpretation is consistent between
2391             // php 5 and php 7.
2392             $form->{$formvalue['name']} = $formvalue['value'];
2393         }
2395         $processor->process_form($form, $preferences);
2397         if (!empty($preferences)) {
2398             set_user_preferences($preferences, $userid);
2399         }
2400     }
2402     /**
2403      * Returns description of method result value
2404      *
2405      * @return external_description
2406      * @since 3.2
2407      */
2408     public static function message_processor_config_form_returns() {
2409         return null;
2410     }
2412     /**
2413      * Returns description of method parameters
2414      *
2415      * @return external_function_parameters
2416      * @since 3.2
2417      */
2418     public static function get_message_processor_parameters() {
2419         return new external_function_parameters(
2420             array(
2421                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2422                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
2423             )
2424         );
2425     }
2427     /**
2428      * Get a message processor.
2429      *
2430      * @param int $userid
2431      * @param string $name the name of the processor
2432      * @return external_description
2433      * @throws moodle_exception
2434      * @since 3.2
2435      */
2436     public static function get_message_processor($userid = 0, $name) {
2437         global $USER, $PAGE, $CFG;
2439         // Check if messaging is enabled.
2440         if (empty($CFG->messaging)) {
2441             throw new moodle_exception('disabled', 'message');
2442         }
2444         $params = self::validate_parameters(
2445             self::get_message_processor_parameters(),
2446             array(
2447                 'userid' => $userid,
2448                 'name' => $name,
2449             )
2450         );
2452         if (empty($params['userid'])) {
2453             $params['userid'] = $USER->id;
2454         }
2456         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2457         core_user::require_active_user($user);
2458         self::validate_context(context_user::instance($params['userid']));
2460         $processor = get_message_processor($name);
2462         $processoroutput = new \core_message\output\processor($processor, $user);
2463         $renderer = $PAGE->get_renderer('core_message');
2465         return $processoroutput->export_for_template($renderer);
2466     }
2468     /**
2469      * Returns description of method result value
2470      *
2471      * @return external_description
2472      * @since 3.2
2473      */
2474     public static function get_message_processor_returns() {
2475         return new external_function_parameters(
2476             array(
2477                 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2478                 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2479             )
2480         );
2481     }
2483     /**
2484      * Check that the user has enough permission to retrieve message or notifications preferences.
2485      *
2486      * @param  int $userid the user id requesting the preferences
2487      * @return stdClass full user object
2488      * @throws moodle_exception
2489      * @since  Moodle 3.2
2490      */
2491     protected static function validate_preferences_permissions($userid) {
2492         global $USER;
2494         if (empty($userid)) {
2495             $user = $USER;
2496         } else {
2497             $user = core_user::get_user($userid, '*', MUST_EXIST);
2498             core_user::require_active_user($user);
2499         }
2501         $systemcontext = context_system::instance();
2502         self::validate_context($systemcontext);
2504         // Check access control.
2505         if ($user->id == $USER->id) {
2506             // Editing own message profile.
2507             require_capability('moodle/user:editownmessageprofile', $systemcontext);
2508         } else {
2509             // Teachers, parents, etc.
2510             $personalcontext = context_user::instance($user->id);
2511             require_capability('moodle/user:editmessageprofile', $personalcontext);
2512         }
2513         return $user;
2514     }
2516     /**
2517      * Returns a notification or message preference structure.
2518      *
2519      * @return external_single_structure the structure
2520      * @since  Moodle 3.2
2521      */
2522     protected static function get_preferences_structure() {
2523         return new external_single_structure(
2524             array(
2525                 'userid' => new external_value(PARAM_INT, 'User id'),
2526                 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
2527                 'processors' => new external_multiple_structure(
2528                     new external_single_structure(
2529                         array(
2530                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2531                             'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
2532                             'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
2533                             'contextid' => new external_value(PARAM_INT, 'Context id'),
2534                             'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
2535                         )
2536                     ),
2537                     'Config form values'
2538                 ),
2539                 'components' => new external_multiple_structure(
2540                     new external_single_structure(
2541                         array(
2542                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2543                             'notifications' => new external_multiple_structure(
2544                                 new external_single_structure(
2545                                     array(
2546                                         'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2547                                         'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
2548                                         'processors' => new external_multiple_structure(
2549                                             new external_single_structure(
2550                                                 array(
2551                                                     'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2552                                                     'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
2553                                                     'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
2554                                                     'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
2555                                                     'loggedin' => new external_single_structure(
2556                                                         array(
2557                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
2558                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2559                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
2560                                                         )
2561                                                     ),
2562                                                     'loggedoff' => new external_single_structure(
2563                                                         array(
2564                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
2565                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2566                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
2567                                                         )
2568                                                     ),
2569                                                 )
2570                                             ),
2571                                             'Processors values for this notification'
2572                                         ),
2573                                     )
2574                                 ),
2575                                 'List of notificaitons for the component'
2576                             ),
2577                         )
2578                     ),
2579                     'Available components'
2580                 ),
2581             )
2582         );
2583     }
2585     /**
2586      * Returns description of method parameters
2587      *
2588      * @return external_function_parameters
2589      * @since 3.2
2590      */
2591     public static function get_user_notification_preferences_parameters() {
2592         return new external_function_parameters(
2593             array(
2594                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
2595             )
2596         );
2597     }
2599     /**
2600      * Get the notification preferences for a given user.
2601      *
2602      * @param int $userid id of the user, 0 for current user
2603      * @return external_description
2604      * @throws moodle_exception
2605      * @since 3.2
2606      */
2607     public static function get_user_notification_preferences($userid = 0) {
2608         global $PAGE;
2610         $params = self::validate_parameters(
2611             self::get_user_notification_preferences_parameters(),
2612             array(
2613                 'userid' => $userid,
2614             )
2615         );
2616         $user = self::validate_preferences_permissions($params['userid']);
2618         $processors = get_message_processors();
2619         $providers = message_get_providers_for_user($user->id);
2620         $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
2621         $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
2623         $renderer = $PAGE->get_renderer('core_message');
2625         $result = array(
2626             'warnings' => array(),
2627             'preferences' => $notificationlist->export_for_template($renderer)
2628         );
2629         return $result;
2630     }
2632     /**
2633      * Returns description of method result value
2634      *
2635      * @return external_description
2636      * @since 3.2
2637      */
2638     public static function get_user_notification_preferences_returns() {
2639         return new external_function_parameters(
2640             array(
2641                 'preferences' => self::get_preferences_structure(),
2642                 'warnings' => new external_warnings(),
2643             )
2644         );
2645     }
2648     /**
2649      * Returns description of method parameters
2650      *
2651      * @return external_function_parameters
2652      * @since 3.2
2653      */
2654     public static function get_user_message_preferences_parameters() {
2655         return new external_function_parameters(
2656             array(
2657                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
2658             )
2659         );
2660     }
2662     /**
2663      * Get the notification preferences for a given user.
2664      *
2665      * @param int $userid id of the user, 0 for current user
2666      * @return external_description
2667      * @throws moodle_exception
2668      * @since 3.2
2669      */
2670     public static function get_user_message_preferences($userid = 0) {
2671         global $PAGE;
2673         $params = self::validate_parameters(
2674             self::get_user_message_preferences_parameters(),
2675             array(
2676                 'userid' => $userid,
2677             )
2678         );
2680         $user = self::validate_preferences_permissions($params['userid']);
2682         // Filter out enabled, available system_configured and user_configured processors only.
2683         $readyprocessors = array_filter(get_message_processors(), function($processor) {
2684             return $processor->enabled &&
2685                 $processor->configured &&
2686                 $processor->object->is_user_configured() &&
2687                 // Filter out processors that don't have and message preferences to configure.
2688                 $processor->object->has_message_preferences();
2689         });
2691         $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
2692             return $provider->component === 'moodle';
2693         });
2694         $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
2695         $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
2696             $providers, $preferences, $user);
2698         $renderer = $PAGE->get_renderer('core_message');
2700         $result = array(
2701             'warnings' => array(),
2702             'preferences' => $notificationlistoutput->export_for_template($renderer),
2703             'blocknoncontacts' => get_user_preferences('message_blocknoncontacts', '', $user->id) ? true : false,
2704         );
2705         return $result;
2706     }
2708     /**
2709      * Returns description of method result value
2710      *
2711      * @return external_description
2712      * @since 3.2
2713      */
2714     public static function get_user_message_preferences_returns() {
2715         return new external_function_parameters(
2716             array(
2717                 'preferences' => self::get_preferences_structure(),
2718                 'blocknoncontacts' => new external_value(PARAM_BOOL, 'Whether to block or not messages from non contacts'),
2719                 'warnings' => new external_warnings(),
2720             )
2721         );
2722     }