528ace771f47d82f2a30e39e48fe9264947fa547
[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      * @return external_function_parameters
195      * @since Moodle 2.5
196      */
197     public static function create_contacts_parameters() {
198         return new external_function_parameters(
199             array(
200                 'userids' => new external_multiple_structure(
201                     new external_value(PARAM_INT, 'User ID'),
202                     'List of user IDs'
203                 ),
204                 'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
205                     current user', VALUE_DEFAULT, 0)
206             )
207         );
208     }
210     /**
211      * Create contacts.
212      *
213      * @param array $userids array of user IDs.
214      * @param int $userid The id of the user we are creating the contacts for
215      * @return external_description
216      * @since Moodle 2.5
217      */
218     public static function create_contacts($userids, $userid = 0) {
219         global $CFG, $USER;
221         // Check if messaging is enabled.
222         if (empty($CFG->messaging)) {
223             throw new moodle_exception('disabled', 'message');
224         }
226         if (empty($userid)) {
227             $userid = $USER->id;
228         }
230         // Validate context.
231         $context = context_system::instance();
232         self::validate_context($context);
234         $capability = 'moodle/site:manageallmessaging';
235         if (($USER->id != $userid) && !has_capability($capability, $context)) {
236             throw new required_capability_exception($context, $capability, 'nopermissions', '');
237         }
239         $params = array('userids' => $userids, 'userid' => $userid);
240         $params = self::validate_parameters(self::create_contacts_parameters(), $params);
242         $warnings = array();
243         foreach ($params['userids'] as $id) {
244             if (!message_add_contact($id, 0, $userid)) {
245                 $warnings[] = array(
246                     'item' => 'user',
247                     'itemid' => $id,
248                     'warningcode' => 'contactnotcreated',
249                     'message' => 'The contact could not be created'
250                 );
251             }
252         }
253         return $warnings;
254     }
256     /**
257      * Create contacts return description.
258      *
259      * @return external_description
260      * @since Moodle 2.5
261      */
262     public static function create_contacts_returns() {
263         return new external_warnings();
264     }
266     /**
267      * Delete contacts parameters description.
268      *
269      * @return external_function_parameters
270      * @since Moodle 2.5
271      */
272     public static function delete_contacts_parameters() {
273         return new external_function_parameters(
274             array(
275                 'userids' => new external_multiple_structure(
276                     new external_value(PARAM_INT, 'User ID'),
277                     'List of user IDs'
278                 ),
279                 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
280                     current user', VALUE_DEFAULT, 0)
281             )
282         );
283     }
285     /**
286      * Delete contacts.
287      *
288      * @param array $userids array of user IDs.
289      * @param int $userid The id of the user we are deleting the contacts for
290      * @return null
291      * @since Moodle 2.5
292      */
293     public static function delete_contacts($userids, $userid = 0) {
294         global $CFG, $USER;
296         // Check if messaging is enabled.
297         if (empty($CFG->messaging)) {
298             throw new moodle_exception('disabled', 'message');
299         }
301         if (empty($userid)) {
302             $userid = $USER->id;
303         }
305         // Validate context.
306         $context = context_system::instance();
307         self::validate_context($context);
309         $capability = 'moodle/site:manageallmessaging';
310         if (($USER->id != $userid) && !has_capability($capability, $context)) {
311             throw new required_capability_exception($context, $capability, 'nopermissions', '');
312         }
314         $params = array('userids' => $userids, 'userid' => $userid);
315         $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
317         foreach ($params['userids'] as $id) {
318             message_remove_contact($id, $userid);
319         }
321         return null;
322     }
324     /**
325      * Delete contacts return description.
326      *
327      * @return external_description
328      * @since Moodle 2.5
329      */
330     public static function delete_contacts_returns() {
331         return null;
332     }
334     /**
335      * Block contacts parameters description.
336      *
337      * @return external_function_parameters
338      * @since Moodle 2.5
339      */
340     public static function block_contacts_parameters() {
341         return new external_function_parameters(
342             array(
343                 'userids' => new external_multiple_structure(
344                     new external_value(PARAM_INT, 'User ID'),
345                     'List of user IDs'
346                 ),
347                 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
348                     current user', VALUE_DEFAULT, 0)
349             )
350         );
351     }
353     /**
354      * Block contacts.
355      *
356      * @param array $userids array of user IDs.
357      * @param int $userid The id of the user we are blocking the contacts for
358      * @return external_description
359      * @since Moodle 2.5
360      */
361     public static function block_contacts($userids, $userid = 0) {
362         global $CFG, $USER;
364         // Check if messaging is enabled.
365         if (empty($CFG->messaging)) {
366             throw new moodle_exception('disabled', 'message');
367         }
369         if (empty($userid)) {
370             $userid = $USER->id;
371         }
373         // Validate context.
374         $context = context_system::instance();
375         self::validate_context($context);
377         $capability = 'moodle/site:manageallmessaging';
378         if (($USER->id != $userid) && !has_capability($capability, $context)) {
379             throw new required_capability_exception($context, $capability, 'nopermissions', '');
380         }
382         $params = array('userids' => $userids, 'userid' => $userid);
383         $params = self::validate_parameters(self::block_contacts_parameters(), $params);
385         $warnings = array();
386         foreach ($params['userids'] as $id) {
387             if (!message_block_contact($id, $userid)) {
388                 $warnings[] = array(
389                     'item' => 'user',
390                     'itemid' => $id,
391                     'warningcode' => 'contactnotblocked',
392                     'message' => 'The contact could not be blocked'
393                 );
394             }
395         }
396         return $warnings;
397     }
399     /**
400      * Block contacts return description.
401      *
402      * @return external_description
403      * @since Moodle 2.5
404      */
405     public static function block_contacts_returns() {
406         return new external_warnings();
407     }
409     /**
410      * Unblock contacts parameters description.
411      *
412      * @return external_function_parameters
413      * @since Moodle 2.5
414      */
415     public static function unblock_contacts_parameters() {
416         return new external_function_parameters(
417             array(
418                 'userids' => new external_multiple_structure(
419                     new external_value(PARAM_INT, 'User ID'),
420                     'List of user IDs'
421                 ),
422                 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
423                     current user', VALUE_DEFAULT, 0)
424             )
425         );
426     }
428     /**
429      * Unblock contacts.
430      *
431      * @param array $userids array of user IDs.
432      * @param int $userid The id of the user we are unblocking the contacts for
433      * @return null
434      * @since Moodle 2.5
435      */
436     public static function unblock_contacts($userids, $userid = 0) {
437         global $CFG, $USER;
439         // Check if messaging is enabled.
440         if (empty($CFG->messaging)) {
441             throw new moodle_exception('disabled', 'message');
442         }
444         if (empty($userid)) {
445             $userid = $USER->id;
446         }
448         // Validate context.
449         $context = context_system::instance();
450         self::validate_context($context);
452         $capability = 'moodle/site:manageallmessaging';
453         if (($USER->id != $userid) && !has_capability($capability, $context)) {
454             throw new required_capability_exception($context, $capability, 'nopermissions', '');
455         }
457         $params = array('userids' => $userids, 'userid' => $userid);
458         $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
460         foreach ($params['userids'] as $id) {
461             message_unblock_contact($id, $userid);
462         }
464         return null;
465     }
467     /**
468      * Unblock contacts return description.
469      *
470      * @return external_description
471      * @since Moodle 2.5
472      */
473     public static function unblock_contacts_returns() {
474         return null;
475     }
477     /**
478      * Return the structure of a message area contact.
479      *
480      * @return external_single_structure
481      * @since Moodle 3.2
482      */
483     private static function get_messagearea_contact_structure() {
484         return new external_single_structure(
485             array(
486                 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
487                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
488                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
489                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
490                 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
491                 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
492                 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
493                 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
494                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
495                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
496                 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
497                 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
498                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
499                     VALUE_DEFAULT, null),
500             )
501         );
502     }
504     /**
505      * Return the structure of a message area message.
506      *
507      * @return external_single_structure
508      * @since Moodle 3.2
509      */
510     private static function get_messagearea_message_structure() {
511         return new external_single_structure(
512             array(
513                 'id' => new external_value(PARAM_INT, 'The id of the message'),
514                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
515                 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
516                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
517                 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
518                 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
519                 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
520                 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
521                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
522                 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
523             )
524         );
525     }
527     /**
528      * Get messagearea search users in course parameters.
529      *
530      * @return external_function_parameters
531      * @since 3.2
532      */
533     public static function data_for_messagearea_search_users_in_course_parameters() {
534         return new external_function_parameters(
535             array(
536                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
537                 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
538                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
539                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
540                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
541             )
542         );
543     }
545     /**
546      * Get messagearea search users in course results.
547      *
548      * @param int $userid The id of the user who is performing the search
549      * @param int $courseid The id of the course
550      * @param string $search The string being searched
551      * @param int $limitfrom
552      * @param int $limitnum
553      * @return stdClass
554      * @throws moodle_exception
555      * @since 3.2
556      */
557     public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
558                                                                        $limitnum = 0) {
559         global $CFG, $PAGE, $USER;
561         // Check if messaging is enabled.
562         if (empty($CFG->messaging)) {
563             throw new moodle_exception('disabled', 'message');
564         }
566         $systemcontext = context_system::instance();
568         $params = array(
569             'userid' => $userid,
570             'courseid' => $courseid,
571             'search' => $search,
572             'limitfrom' => $limitfrom,
573             'limitnum' => $limitnum
574         );
575         self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
576         self::validate_context($systemcontext);
578         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
579             throw new moodle_exception('You do not have permission to perform this action.');
580         }
582         $users = \core_message\api::search_users_in_course($userid, $courseid, $search, $limitfrom, $limitnum);
583         $results = new \core_message\output\messagearea\user_search_results($users);
585         $renderer = $PAGE->get_renderer('core_message');
586         return $results->export_for_template($renderer);
587     }
589     /**
590      * Get messagearea search users in course returns.
591      *
592      * @return external_single_structure
593      * @since 3.2
594      */
595     public static function data_for_messagearea_search_users_in_course_returns() {
596         return new external_single_structure(
597             array(
598                 'contacts' => new external_multiple_structure(
599                     self::get_messagearea_contact_structure()
600                 ),
601             )
602         );
603     }
605     /**
606      * Get messagearea search users parameters.
607      *
608      * @return external_function_parameters
609      * @since 3.2
610      */
611     public static function data_for_messagearea_search_users_parameters() {
612         return new external_function_parameters(
613             array(
614                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
615                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
616                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
617             )
618         );
619     }
621     /**
622      * Get messagearea search users results.
623      *
624      * @param int $userid The id of the user who is performing the search
625      * @param string $search The string being searched
626      * @param int $limitnum
627      * @return stdClass
628      * @throws moodle_exception
629      * @since 3.2
630      */
631     public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
632         global $CFG, $PAGE, $USER;
634         // Check if messaging is enabled.
635         if (empty($CFG->messaging)) {
636             throw new moodle_exception('disabled', 'message');
637         }
639         $systemcontext = context_system::instance();
641         $params = array(
642             'userid' => $userid,
643             'search' => $search,
644             'limitnum' => $limitnum
645         );
646         self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
647         self::validate_context($systemcontext);
649         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
650             throw new moodle_exception('You do not have permission to perform this action.');
651         }
653         list($contacts, $courses, $noncontacts) = \core_message\api::search_users($userid, $search, $limitnum);
654         $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
656         $renderer = $PAGE->get_renderer('core_message');
657         return $search->export_for_template($renderer);
658     }
660     /**
661      * Get messagearea search users returns.
662      *
663      * @return external_single_structure
664      * @since 3.2
665      */
666     public static function data_for_messagearea_search_users_returns() {
667         return new external_single_structure(
668             array(
669                 'contacts' => new external_multiple_structure(
670                     self::get_messagearea_contact_structure()
671                 ),
672                 'courses' => new external_multiple_structure(
673                     new external_single_structure(
674                         array(
675                             'id' => new external_value(PARAM_INT, 'The course id'),
676                             'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
677                             'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
678                         )
679                     )
680                 ),
681                 'noncontacts' => new external_multiple_structure(
682                     self::get_messagearea_contact_structure()
683                 )
684             )
685         );
686     }
688     /**
689      * Get messagearea search messages parameters.
690      *
691      * @return external_function_parameters
692      * @since 3.2
693      */
694     public static function data_for_messagearea_search_messages_parameters() {
695         return new external_function_parameters(
696             array(
697                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
698                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
699                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
700                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
701             )
702         );
703     }
705     /**
706      * Get messagearea search messages results.
707      *
708      * @param int $userid The id of the user who is performing the search
709      * @param string $search The string being searched
710      * @param int $limitfrom
711      * @param int $limitnum
712      * @return stdClass
713      * @throws moodle_exception
714      * @since 3.2
715      */
716     public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
717         global $CFG, $PAGE, $USER;
719         // Check if messaging is enabled.
720         if (empty($CFG->messaging)) {
721             throw new moodle_exception('disabled', 'message');
722         }
724         $systemcontext = context_system::instance();
726         $params = array(
727             'userid' => $userid,
728             'search' => $search,
729             'limitfrom' => $limitfrom,
730             'limitnum' => $limitnum
732         );
733         self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
734         self::validate_context($systemcontext);
736         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
737             throw new moodle_exception('You do not have permission to perform this action.');
738         }
740         $messages = \core_message\api::search_messages($userid, $search, $limitfrom, $limitnum);
741         $results = new \core_message\output\messagearea\message_search_results($messages);
743         $renderer = $PAGE->get_renderer('core_message');
744         return $results->export_for_template($renderer);
745     }
747     /**
748      * Get messagearea search messages returns.
749      *
750      * @return external_single_structure
751      * @since 3.2
752      */
753     public static function data_for_messagearea_search_messages_returns() {
754         return new external_single_structure(
755             array(
756                 'contacts' => new external_multiple_structure(
757                     self::get_messagearea_contact_structure()
758                 )
759             )
760         );
761     }
763     /**
764      * The messagearea conversations parameters.
765      *
766      * @return external_function_parameters
767      * @since 3.2
768      */
769     public static function data_for_messagearea_conversations_parameters() {
770         return new external_function_parameters(
771             array(
772                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
773                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
774                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
775             )
776         );
777     }
779     /**
780      * Get messagearea conversations.
781      *
782      * @param int $userid The id of the user who we are viewing conversations for
783      * @param int $limitfrom
784      * @param int $limitnum
785      * @return stdClass
786      * @throws moodle_exception
787      * @since 3.2
788      */
789     public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
790         global $CFG, $PAGE, $USER;
792         // Check if messaging is enabled.
793         if (empty($CFG->messaging)) {
794             throw new moodle_exception('disabled', 'message');
795         }
797         $systemcontext = context_system::instance();
799         $params = array(
800             'userid' => $userid,
801             'limitfrom' => $limitfrom,
802             'limitnum' => $limitnum
803         );
804         self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
805         self::validate_context($systemcontext);
807         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
808             throw new moodle_exception('You do not have permission to perform this action.');
809         }
811         $conversations = \core_message\api::get_conversations($userid, $limitfrom, $limitnum);
812         $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
814         $renderer = $PAGE->get_renderer('core_message');
815         return $conversations->export_for_template($renderer);
816     }
818     /**
819      * The messagearea conversations return structure.
820      *
821      * @return external_single_structure
822      * @since 3.2
823      */
824     public static function data_for_messagearea_conversations_returns() {
825         return new external_single_structure(
826             array(
827                 'contacts' => new external_multiple_structure(
828                     self::get_messagearea_contact_structure()
829                 )
830             )
831         );
832     }
834     /**
835      * The messagearea contacts return parameters.
836      *
837      * @return external_function_parameters
838      * @since 3.2
839      */
840     public static function data_for_messagearea_contacts_parameters() {
841         return self::data_for_messagearea_conversations_parameters();
842     }
844     /**
845      * Get messagearea contacts parameters.
846      *
847      * @param int $userid The id of the user who we are viewing conversations for
848      * @param int $limitfrom
849      * @param int $limitnum
850      * @return stdClass
851      * @throws moodle_exception
852      * @since 3.2
853      */
854     public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
855         global $CFG, $PAGE, $USER;
857         // Check if messaging is enabled.
858         if (empty($CFG->messaging)) {
859             throw new moodle_exception('disabled', 'message');
860         }
862         $systemcontext = context_system::instance();
864         $params = array(
865             'userid' => $userid,
866             'limitfrom' => $limitfrom,
867             'limitnum' => $limitnum
868         );
869         self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
870         self::validate_context($systemcontext);
872         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
873             throw new moodle_exception('You do not have permission to perform this action.');
874         }
876         $contacts = \core_message\api::get_contacts($userid, $limitfrom, $limitnum);
877         $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
879         $renderer = $PAGE->get_renderer('core_message');
880         return $contacts->export_for_template($renderer);
881     }
883     /**
884      * The messagearea contacts return structure.
885      *
886      * @return external_single_structure
887      * @since 3.2
888      */
889     public static function data_for_messagearea_contacts_returns() {
890         return self::data_for_messagearea_conversations_returns();
891     }
893     /**
894      * The messagearea messages parameters.
895      *
896      * @return external_function_parameters
897      * @since 3.2
898      */
899     public static function data_for_messagearea_messages_parameters() {
900         return new external_function_parameters(
901             array(
902                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
903                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
904                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
905                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
906                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
907                 'timefrom' => new external_value(PARAM_INT,
908                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
909             )
910         );
911     }
913     /**
914      * Get messagearea messages.
915      *
916      * @param int $currentuserid The current user's id
917      * @param int $otheruserid The other user's id
918      * @param int $limitfrom
919      * @param int $limitnum
920      * @param boolean $newest
921      * @return stdClass
922      * @throws moodle_exception
923      * @since 3.2
924      */
925     public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
926                                                          $newest = false, $timefrom = 0) {
927         global $CFG, $PAGE, $USER;
929         // Check if messaging is enabled.
930         if (empty($CFG->messaging)) {
931             throw new moodle_exception('disabled', 'message');
932         }
934         $systemcontext = context_system::instance();
936         $params = array(
937             'currentuserid' => $currentuserid,
938             'otheruserid' => $otheruserid,
939             'limitfrom' => $limitfrom,
940             'limitnum' => $limitnum,
941             'newest' => $newest,
942             'timefrom' => $timefrom,
943         );
944         self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
945         self::validate_context($systemcontext);
947         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
948             throw new moodle_exception('You do not have permission to perform this action.');
949         }
951         if ($newest) {
952             $sort = 'timecreated DESC';
953         } else {
954             $sort = 'timecreated ASC';
955         }
957         // We need to enforce a one second delay on messages to avoid race conditions of current
958         // messages still being sent.
959         //
960         // There is a chance that we could request messages before the current time's
961         // second has elapsed and while other messages are being sent in that same second. In which
962         // case those messages will be lost.
963         //
964         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
965         if (!empty($timefrom)) {
966             $timeto = time() - 1;
967         } else {
968             $timeto = 0;
969         }
971         // No requesting messages from the current time, as stated above.
972         if ($timefrom == time()) {
973             $messages = [];
974         } else {
975             $messages = \core_message\api::get_messages($currentuserid, $otheruserid, $limitfrom,
976                                                         $limitnum, $sort, $timefrom, $timeto);
977         }
979         $messages = new \core_message\output\messagearea\messages($currentuserid, $otheruserid, $messages);
981         $renderer = $PAGE->get_renderer('core_message');
982         return $messages->export_for_template($renderer);
983     }
985     /**
986      * The messagearea messages return structure.
987      *
988      * @return external_single_structure
989      * @since 3.2
990      */
991     public static function data_for_messagearea_messages_returns() {
992         return new external_single_structure(
993             array(
994                 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
995                     the messages on behalf of?'),
996                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
997                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
998                 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
999                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1000                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1001                 'messages' => new external_multiple_structure(
1002                     self::get_messagearea_message_structure()
1003                 ),
1004                 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1005             )
1006         );
1007     }
1009     /**
1010      * The get most recent message return parameters.
1011      *
1012      * @return external_function_parameters
1013      * @since 3.2
1014      */
1015     public static function data_for_messagearea_get_most_recent_message_parameters() {
1016         return new external_function_parameters(
1017             array(
1018                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1019                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1020             )
1021         );
1022     }
1024     /**
1025      * Get the most recent message in a conversation.
1026      *
1027      * @param int $currentuserid The current user's id
1028      * @param int $otheruserid The other user's id
1029      * @return stdClass
1030      * @throws moodle_exception
1031      * @since 3.2
1032      */
1033     public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
1034         global $CFG, $PAGE, $USER;
1036         // Check if messaging is enabled.
1037         if (empty($CFG->messaging)) {
1038             throw new moodle_exception('disabled', 'message');
1039         }
1041         $systemcontext = context_system::instance();
1043         $params = array(
1044             'currentuserid' => $currentuserid,
1045             'otheruserid' => $otheruserid
1046         );
1047         self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
1048         self::validate_context($systemcontext);
1050         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1051             throw new moodle_exception('You do not have permission to perform this action.');
1052         }
1054         $message = \core_message\api::get_most_recent_message($currentuserid, $otheruserid);
1055         $message = new \core_message\output\messagearea\message($message);
1057         $renderer = $PAGE->get_renderer('core_message');
1058         return $message->export_for_template($renderer);
1059     }
1061     /**
1062      * The get most recent message return structure.
1063      *
1064      * @return external_single_structure
1065      * @since 3.2
1066      */
1067     public static function data_for_messagearea_get_most_recent_message_returns() {
1068         return self::get_messagearea_message_structure();
1069     }
1071     /**
1072      * The get profile parameters.
1073      *
1074      * @return external_function_parameters
1075      * @since 3.2
1076      */
1077     public static function data_for_messagearea_get_profile_parameters() {
1078         return new external_function_parameters(
1079             array(
1080                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1081                 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
1082             )
1083         );
1084     }
1086     /**
1087      * Get the profile information for a contact.
1088      *
1089      * @param int $currentuserid The current user's id
1090      * @param int $otheruserid The id of the user whose profile we are viewing
1091      * @return stdClass
1092      * @throws moodle_exception
1093      * @since 3.2
1094      */
1095     public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
1096         global $CFG, $PAGE, $USER;
1098         // Check if messaging is enabled.
1099         if (empty($CFG->messaging)) {
1100             throw new moodle_exception('disabled', 'message');
1101         }
1103         $systemcontext = context_system::instance();
1105         $params = array(
1106             'currentuserid' => $currentuserid,
1107             'otheruserid' => $otheruserid
1108         );
1109         self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
1110         self::validate_context($systemcontext);
1112         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1113             throw new moodle_exception('You do not have permission to perform this action.');
1114         }
1116         $profile = \core_message\api::get_profile($currentuserid, $otheruserid);
1117         $profile = new \core_message\output\messagearea\profile($profile);
1119         $renderer = $PAGE->get_renderer('core_message');
1120         return $profile->export_for_template($renderer);
1121     }
1123     /**
1124      * The get profile return structure.
1125      *
1126      * @return external_single_structure
1127      * @since 3.2
1128      */
1129     public static function data_for_messagearea_get_profile_returns() {
1130         return new external_single_structure(
1131             array(
1132                 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
1133                 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
1134                 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
1135                 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
1136                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1137                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1138                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1139                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1140                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1141                 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
1142                 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
1143             )
1144         );
1145     }
1147     /**
1148      * Get contacts parameters description.
1149      *
1150      * @return external_function_parameters
1151      * @since Moodle 2.5
1152      */
1153     public static function get_contacts_parameters() {
1154         return new external_function_parameters(array());
1155     }
1157     /**
1158      * Get contacts.
1159      *
1160      * @return external_description
1161      * @since Moodle 2.5
1162      */
1163     public static function get_contacts() {
1164         global $CFG, $PAGE, $USER;
1166         // Check if messaging is enabled.
1167         if (empty($CFG->messaging)) {
1168             throw new moodle_exception('disabled', 'message');
1169         }
1171         require_once($CFG->dirroot . '/user/lib.php');
1173         $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
1174         $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
1175         foreach ($contacts as $contact) {
1176             // Set the mode.
1177             $mode = 'offline';
1178             if (\core_message\helper::is_online($contact->lastaccess)) {
1179                 $mode = 'online';
1180             }
1182             $newcontact = array(
1183                 'id' => $contact->id,
1184                 'fullname' => fullname($contact),
1185                 'unread' => $contact->messagecount
1186             );
1188             $userpicture = new user_picture($contact);
1189             $userpicture->size = 1; // Size f1.
1190             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1191             $userpicture->size = 0; // Size f2.
1192             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1194             $allcontacts[$mode][$contact->id] = $newcontact;
1195         }
1197         $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
1198         foreach ($strangers as $contact) {
1199             $newcontact = array(
1200                 'id' => $contact->id,
1201                 'fullname' => fullname($contact),
1202                 'unread' => $contact->messagecount
1203             );
1205             $userpicture = new user_picture($contact);
1206             $userpicture->size = 1; // Size f1.
1207             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1208             $userpicture->size = 0; // Size f2.
1209             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1211             $allcontacts['strangers'][$contact->id] = $newcontact;
1212         }
1214         // Add noreply user and support user to the list, if they don't exist.
1215         $supportuser = core_user::get_support_user();
1216         if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
1217             $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
1218             if ($supportuser->messagecount > 0) {
1219                 $supportuser->fullname = fullname($supportuser);
1220                 $supportuser->unread = $supportuser->messagecount;
1221                 $allcontacts['strangers'][$supportuser->id] = $supportuser;
1222             }
1223         }
1225         $noreplyuser = core_user::get_noreply_user();
1226         if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
1227             $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
1228             if ($noreplyuser->messagecount > 0) {
1229                 $noreplyuser->fullname = fullname($noreplyuser);
1230                 $noreplyuser->unread = $noreplyuser->messagecount;
1231                 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
1232             }
1233         }
1235         return $allcontacts;
1236     }
1238     /**
1239      * Get contacts return description.
1240      *
1241      * @return external_description
1242      * @since Moodle 2.5
1243      */
1244     public static function get_contacts_returns() {
1245         return new external_single_structure(
1246             array(
1247                 'online' => new external_multiple_structure(
1248                     new external_single_structure(
1249                         array(
1250                             'id' => new external_value(PARAM_INT, 'User ID'),
1251                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1252                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1253                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1254                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1255                         )
1256                     ),
1257                     'List of online contacts'
1258                 ),
1259                 'offline' => new external_multiple_structure(
1260                     new external_single_structure(
1261                         array(
1262                             'id' => new external_value(PARAM_INT, 'User ID'),
1263                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1264                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1265                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1266                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1267                         )
1268                     ),
1269                     'List of offline contacts'
1270                 ),
1271                 'strangers' => new external_multiple_structure(
1272                     new external_single_structure(
1273                         array(
1274                             'id' => new external_value(PARAM_INT, 'User ID'),
1275                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1276                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1277                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1278                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1279                         )
1280                     ),
1281                     'List of users that are not in the user\'s contact list but have sent a message'
1282                 )
1283             )
1284         );
1285     }
1287     /**
1288      * Search contacts parameters description.
1289      *
1290      * @return external_function_parameters
1291      * @since Moodle 2.5
1292      */
1293     public static function search_contacts_parameters() {
1294         return new external_function_parameters(
1295             array(
1296                 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1297                 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1298                     VALUE_DEFAULT, false)
1299             )
1300         );
1301     }
1303     /**
1304      * Search contacts.
1305      *
1306      * @param string $searchtext query string.
1307      * @param bool $onlymycourses limit the search to the user's courses only.
1308      * @return external_description
1309      * @since Moodle 2.5
1310      */
1311     public static function search_contacts($searchtext, $onlymycourses = false) {
1312         global $CFG, $USER, $PAGE;
1313         require_once($CFG->dirroot . '/user/lib.php');
1315         // Check if messaging is enabled.
1316         if (empty($CFG->messaging)) {
1317             throw new moodle_exception('disabled', 'message');
1318         }
1320         require_once($CFG->libdir . '/enrollib.php');
1322         $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1323         $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1325         // Extra validation, we do not allow empty queries.
1326         if ($params['searchtext'] === '') {
1327             throw new moodle_exception('querystringcannotbeempty');
1328         }
1330         $courseids = array();
1331         if ($params['onlymycourses']) {
1332             $mycourses = enrol_get_my_courses(array('id'));
1333             foreach ($mycourses as $mycourse) {
1334                 $courseids[] = $mycourse->id;
1335             }
1336         } else {
1337             $courseids[] = SITEID;
1338         }
1340         // Retrieving the users matching the query.
1341         $users = message_search_users($courseids, $params['searchtext']);
1342         $results = array();
1343         foreach ($users as $user) {
1344             $results[$user->id] = $user;
1345         }
1347         // Reorganising information.
1348         foreach ($results as &$user) {
1349             $newuser = array(
1350                 'id' => $user->id,
1351                 'fullname' => fullname($user)
1352             );
1354             // Avoid undefined property notice as phone not specified.
1355             $user->phone1 = null;
1356             $user->phone2 = null;
1358             $userpicture = new user_picture($user);
1359             $userpicture->size = 1; // Size f1.
1360             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1361             $userpicture->size = 0; // Size f2.
1362             $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1364             $user = $newuser;
1365         }
1367         return $results;
1368     }
1370     /**
1371      * Search contacts return description.
1372      *
1373      * @return external_description
1374      * @since Moodle 2.5
1375      */
1376     public static function search_contacts_returns() {
1377         return new external_multiple_structure(
1378             new external_single_structure(
1379                 array(
1380                     'id' => new external_value(PARAM_INT, 'User ID'),
1381                     'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1382                     'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1383                     'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1384                 )
1385             ),
1386             'List of contacts'
1387         );
1388     }
1390     /**
1391      * Get messages parameters description.
1392      *
1393      * @return external_function_parameters
1394      * @since 2.8
1395      */
1396     public static function get_messages_parameters() {
1397         return new external_function_parameters(
1398             array(
1399                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1400                 'useridfrom' => new external_value(
1401                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1402                     VALUE_DEFAULT, 0),
1403                 'type' => new external_value(
1404                     PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1405                     VALUE_DEFAULT, 'both'),
1406                 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
1407                 'newestfirst' => new external_value(
1408                     PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1409                     VALUE_DEFAULT, true),
1410                 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1411                 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1412             )
1413         );
1414     }
1416     /**
1417      * Get messages function implementation.
1418      *
1419      * @since  2.8
1420      * @throws invalid_parameter_exception
1421      * @throws moodle_exception
1422      * @param  int      $useridto       the user id who received the message
1423      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
1424      * @param  string   $type           type of message to return, expected values: notifications, conversations and both
1425      * @param  bool     $read           true for retreiving read messages, false for unread
1426      * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
1427      * @param  int      $limitfrom      limit from
1428      * @param  int      $limitnum       limit num
1429      * @return external_description
1430      */
1431     public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
1432                                         $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
1433         global $CFG, $USER;
1435         $warnings = array();
1437         $params = array(
1438             'useridto' => $useridto,
1439             'useridfrom' => $useridfrom,
1440             'type' => $type,
1441             'read' => $read,
1442             'newestfirst' => $newestfirst,
1443             'limitfrom' => $limitfrom,
1444             'limitnum' => $limitnum
1445         );
1447         $params = self::validate_parameters(self::get_messages_parameters(), $params);
1449         $context = context_system::instance();
1450         self::validate_context($context);
1452         $useridto = $params['useridto'];
1453         $useridfrom = $params['useridfrom'];
1454         $type = $params['type'];
1455         $read = $params['read'];
1456         $newestfirst = $params['newestfirst'];
1457         $limitfrom = $params['limitfrom'];
1458         $limitnum = $params['limitnum'];
1460         $allowedvalues = array('notifications', 'conversations', 'both');
1461         if (!in_array($type, $allowedvalues)) {
1462             throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
1463                 'allowed values are: ' . implode(',', $allowedvalues));
1464         }
1466         // Check if private messaging between users is allowed.
1467         if (empty($CFG->messaging)) {
1468             // If we are retreiving only conversations, and messaging is disabled, throw an exception.
1469             if ($type == "conversations") {
1470                 throw new moodle_exception('disabled', 'message');
1471             }
1472             if ($type == "both") {
1473                 $warning = array();
1474                 $warning['item'] = 'message';
1475                 $warning['itemid'] = $USER->id;
1476                 $warning['warningcode'] = '1';
1477                 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
1478                     Only notifications will be returned';
1479                 $warnings[] = $warning;
1480             }
1481         }
1483         if (!empty($useridto)) {
1484             if (core_user::is_real_user($useridto)) {
1485                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
1486             } else {
1487                 throw new moodle_exception('invaliduser');
1488             }
1489         }
1491         if (!empty($useridfrom)) {
1492             // We use get_user here because the from user can be the noreply or support user.
1493             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
1494         }
1496         // Check if the current user is the sender/receiver or just a privileged user.
1497         if ($useridto != $USER->id and $useridfrom != $USER->id and
1498              !has_capability('moodle/site:readallmessages', $context)) {
1499             throw new moodle_exception('accessdenied', 'admin');
1500         }
1502         // Which type of messages to retrieve.
1503         $notifications = -1;
1504         if ($type != 'both') {
1505             $notifications = ($type == 'notifications') ? 1 : 0;
1506         }
1508         $orderdirection = $newestfirst ? 'DESC' : 'ASC';
1509         $sort = "mr.timecreated $orderdirection";
1511         if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
1512             $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
1514             // In some cases, we don't need to get the to/from user objects from the sql query.
1515             $userfromfullname = '';
1516             $usertofullname = '';
1518             // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
1519             if (!empty($useridto)) {
1520                 $usertofullname = fullname($userto, $canviewfullname);
1521                 // The user from may or may not be filled.
1522                 if (!empty($useridfrom)) {
1523                     $userfromfullname = fullname($userfrom, $canviewfullname);
1524                 }
1525             } else {
1526                 // If the useridto field is empty, the useridfrom must be filled.
1527                 $userfromfullname = fullname($userfrom, $canviewfullname);
1528             }
1529             foreach ($messages as $mid => $message) {
1531                 // Do not return deleted messages.
1532                 if (!$message->notification) {
1533                     if (($useridto == $USER->id and $message->timeusertodeleted) or
1534                         ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
1535                         unset($messages[$mid]);
1536                         continue;
1537                     }
1538                 }
1540                 $message->useridto = $useridto;
1542                 // We need to get the user from the query.
1543                 if (empty($userfromfullname)) {
1544                     // Check for non-reply and support users.
1545                     if (core_user::is_real_user($message->useridfrom)) {
1546                         $user = new stdClass();
1547                         $user = username_load_fields_from_object($user, $message, 'userfrom');
1548                         $message->userfromfullname = fullname($user, $canviewfullname);
1549                     } else {
1550                         $user = core_user::get_user($message->useridfrom);
1551                         $message->userfromfullname = fullname($user, $canviewfullname);
1552                     }
1553                 } else {
1554                     $message->userfromfullname = $userfromfullname;
1555                 }
1557                 // We need to get the user from the query.
1558                 if (empty($usertofullname)) {
1559                     $user = new stdClass();
1560                     $user = username_load_fields_from_object($user, $message, 'userto');
1561                     $message->usertofullname = fullname($user, $canviewfullname);
1562                 } else {
1563                     $message->usertofullname = $usertofullname;
1564                 }
1566                 $message->text = message_format_message_text($message);
1567                 $messages[$mid] = (array) $message;
1568             }
1569         }
1571         $results = array(
1572             'messages' => $messages,
1573             'warnings' => $warnings
1574         );
1576         return $results;
1577     }
1579     /**
1580      * Get messages return description.
1581      *
1582      * @return external_single_structure
1583      * @since 2.8
1584      */
1585     public static function get_messages_returns() {
1586         return new external_single_structure(
1587             array(
1588                 'messages' => new external_multiple_structure(
1589                     new external_single_structure(
1590                         array(
1591                             'id' => new external_value(PARAM_INT, 'Message id'),
1592                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
1593                             'useridto' => new external_value(PARAM_INT, 'User to id'),
1594                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
1595                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
1596                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
1597                             'fullmessageformat' => new external_format_value('fullmessage'),
1598                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
1599                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
1600                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
1601                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
1602                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
1603                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
1604                             'timeread' => new external_value(PARAM_INT, 'Time read'),
1605                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
1606                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
1607                         ), 'message'
1608                     )
1609                 ),
1610                 'warnings' => new external_warnings()
1611             )
1612         );
1613     }
1615     /**
1616      * Mark all notifications as read parameters description.
1617      *
1618      * @return external_function_parameters
1619      * @since 3.2
1620      */
1621     public static function mark_all_notifications_as_read_parameters() {
1622         return new external_function_parameters(
1623             array(
1624                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1625                 'useridfrom' => new external_value(
1626                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1627                     VALUE_DEFAULT, 0),
1628             )
1629         );
1630     }
1632     /**
1633      * Mark all notifications as read function.
1634      *
1635      * @since  3.2
1636      * @throws invalid_parameter_exception
1637      * @throws moodle_exception
1638      * @param  int      $useridto       the user id who received the message
1639      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
1640      * @return external_description
1641      */
1642     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
1643         global $USER;
1645         $params = self::validate_parameters(
1646             self::mark_all_notifications_as_read_parameters(),
1647             array(
1648                 'useridto' => $useridto,
1649                 'useridfrom' => $useridfrom,
1650             )
1651         );
1653         $context = context_system::instance();
1654         self::validate_context($context);
1656         $useridto = $params['useridto'];
1657         $useridfrom = $params['useridfrom'];
1659         if (!empty($useridto)) {
1660             if (core_user::is_real_user($useridto)) {
1661                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
1662             } else {
1663                 throw new moodle_exception('invaliduser');
1664             }
1665         }
1667         if (!empty($useridfrom)) {
1668             // We use get_user here because the from user can be the noreply or support user.
1669             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
1670         }
1672         // Check if the current user is the sender/receiver or just a privileged user.
1673         if ($useridto != $USER->id and $useridfrom != $USER->id and
1674             // The deleteanymessage cap seems more reasonable here than readallmessages.
1675              !has_capability('moodle/site:deleteanymessage', $context)) {
1676             throw new moodle_exception('accessdenied', 'admin');
1677         }
1679         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
1681         return true;
1682     }
1684     /**
1685      * Mark all notifications as read return description.
1686      *
1687      * @return external_single_structure
1688      * @since 3.2
1689      */
1690     public static function mark_all_notifications_as_read_returns() {
1691         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
1692     }
1694     /**
1695      * Get unread conversations count parameters description.
1696      *
1697      * @return external_function_parameters
1698      * @since 3.2
1699      */
1700     public static function get_unread_conversations_count_parameters() {
1701         return new external_function_parameters(
1702             array(
1703                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1704             )
1705         );
1706     }
1708     /**
1709      * Get unread messages count function.
1710      *
1711      * @since  3.2
1712      * @throws invalid_parameter_exception
1713      * @throws moodle_exception
1714      * @param  int      $useridto       the user id who received the message
1715      * @return external_description
1716      */
1717     public static function get_unread_conversations_count($useridto) {
1718         global $USER, $CFG;
1720         // Check if messaging is enabled.
1721         if (empty($CFG->messaging)) {
1722             throw new moodle_exception('disabled', 'message');
1723         }
1725         $params = self::validate_parameters(
1726             self::get_unread_conversations_count_parameters(),
1727             array('useridto' => $useridto)
1728         );
1730         $context = context_system::instance();
1731         self::validate_context($context);
1733         $useridto = $params['useridto'];
1735         if (!empty($useridto)) {
1736             if (core_user::is_real_user($useridto)) {
1737                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
1738             } else {
1739                 throw new moodle_exception('invaliduser');
1740             }
1741         } else {
1742             $useridto = $USER->id;
1743         }
1745         // Check if the current user is the receiver or just a privileged user.
1746         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
1747             throw new moodle_exception('accessdenied', 'admin');
1748         }
1750         return \core_message\api::count_unread_conversations($userto);
1751     }
1753     /**
1754      * Get unread conversations count return description.
1755      *
1756      * @return external_single_structure
1757      * @since 3.2
1758      */
1759     public static function get_unread_conversations_count_returns() {
1760         return new external_value(PARAM_INT, 'The count of unread messages for the user');
1761     }
1763     /**
1764      * Get blocked users parameters description.
1765      *
1766      * @return external_function_parameters
1767      * @since 2.9
1768      */
1769     public static function get_blocked_users_parameters() {
1770         return new external_function_parameters(
1771             array(
1772                 'userid' => new external_value(PARAM_INT,
1773                                 'the user whose blocked users we want to retrieve',
1774                                 VALUE_REQUIRED),
1775             )
1776         );
1777     }
1779     /**
1780      * Retrieve a list of users blocked
1781      *
1782      * @param  int $userid the user whose blocked users we want to retrieve
1783      * @return external_description
1784      * @since 2.9
1785      */
1786     public static function get_blocked_users($userid) {
1787         global $CFG, $USER, $PAGE;
1789         // Warnings array, it can be empty at the end but is mandatory.
1790         $warnings = array();
1792         // Validate params.
1793         $params = array(
1794             'userid' => $userid
1795         );
1796         $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
1797         $userid = $params['userid'];
1799         // Validate context.
1800         $context = context_system::instance();
1801         self::validate_context($context);
1803         // Check if private messaging between users is allowed.
1804         if (empty($CFG->messaging)) {
1805             throw new moodle_exception('disabled', 'message');
1806         }
1808         $user = core_user::get_user($userid, '*', MUST_EXIST);
1809         core_user::require_active_user($user);
1811         // Check if we have permissions for retrieve the information.
1812         $capability = 'moodle/site:manageallmessaging';
1813         if (($USER->id != $userid) && !has_capability($capability, $context)) {
1814             throw new required_capability_exception($context, $capability, 'nopermissions', '');
1815         }
1817         // Now, we can get safely all the blocked users.
1818         $users = \core_message\api::get_blocked_users($user->id);
1820         $blockedusers = array();
1821         foreach ($users as $user) {
1822             $newuser = array(
1823                 'id' => $user->id,
1824                 'fullname' => fullname($user),
1825             );
1827             $userpicture = new user_picture($user);
1828             $userpicture->size = 1; // Size f1.
1829             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1831             $blockedusers[] = $newuser;
1832         }
1834         $results = array(
1835             'users' => $blockedusers,
1836             'warnings' => $warnings
1837         );
1838         return $results;
1839     }
1841     /**
1842      * Get blocked users return description.
1843      *
1844      * @return external_single_structure
1845      * @since 2.9
1846      */
1847     public static function get_blocked_users_returns() {
1848         return new external_single_structure(
1849             array(
1850                 'users' => new external_multiple_structure(
1851                     new external_single_structure(
1852                         array(
1853                             'id' => new external_value(PARAM_INT, 'User ID'),
1854                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1855                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
1856                         )
1857                     ),
1858                     'List of blocked users'
1859                 ),
1860                 'warnings' => new external_warnings()
1861             )
1862         );
1863     }
1865     /**
1866      * Returns description of method parameters
1867      *
1868      * @return external_function_parameters
1869      * @since 2.9
1870      */
1871     public static function mark_message_read_parameters() {
1872         return new external_function_parameters(
1873             array(
1874                 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
1875                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
1876                     VALUE_DEFAULT, 0)
1877             )
1878         );
1879     }
1881     /**
1882      * Mark a single message as read, trigger message_viewed event
1883      *
1884      * @param  int $messageid id of the message (in the message table)
1885      * @param  int $timeread timestamp for when the message should be marked read
1886      * @return external_description
1887      * @throws invalid_parameter_exception
1888      * @throws moodle_exception
1889      * @since 2.9
1890      */
1891     public static function mark_message_read($messageid, $timeread) {
1892         global $CFG, $DB, $USER;
1894         // Check if private messaging between users is allowed.
1895         if (empty($CFG->messaging)) {
1896             throw new moodle_exception('disabled', 'message');
1897         }
1899         // Warnings array, it can be empty at the end but is mandatory.
1900         $warnings = array();
1902         // Validate params.
1903         $params = array(
1904             'messageid' => $messageid,
1905             'timeread' => $timeread
1906         );
1907         $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
1909         if (empty($params['timeread'])) {
1910             $timeread = time();
1911         } else {
1912             $timeread = $params['timeread'];
1913         }
1915         // Validate context.
1916         $context = context_system::instance();
1917         self::validate_context($context);
1919         $sql = "SELECT m.*, mcm.userid as useridto
1920                   FROM {messages} m
1921             INNER JOIN {message_conversations} mc
1922                     ON m.conversationid = mc.id
1923             INNER JOIN {message_conversation_members} mcm
1924                     ON mcm.conversationid = mc.id
1925                  WHERE mcm.userid != m.useridfrom
1926                    AND m.id = ?";
1927         $message = $DB->get_record_sql($sql, [$params['messageid']], MUST_EXIST);
1929         if ($message->useridto != $USER->id) {
1930             throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
1931         }
1933         \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
1935         $results = array(
1936             'messageid' => $message->id,
1937             'warnings' => $warnings
1938         );
1939         return $results;
1940     }
1942     /**
1943      * Returns description of method result value
1944      *
1945      * @return external_description
1946      * @since 2.9
1947      */
1948     public static function mark_message_read_returns() {
1949         return new external_single_structure(
1950             array(
1951                 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
1952                 'warnings' => new external_warnings()
1953             )
1954         );
1955     }
1957     /**
1958      * Returns description of method parameters
1959      *
1960      * @return external_function_parameters
1961      */
1962     public static function mark_notification_read_parameters() {
1963         return new external_function_parameters(
1964             array(
1965                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
1966                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
1967                     VALUE_DEFAULT, 0)
1968             )
1969         );
1970     }
1972     /**
1973      * Mark a single notification as read.
1974      *
1975      * This will trigger a 'notification_viewed' event.
1976      *
1977      * @param int $notificationid id of the notification
1978      * @param int $timeread timestamp for when the notification should be marked read
1979      * @return external_description
1980      * @throws invalid_parameter_exception
1981      * @throws moodle_exception
1982      */
1983     public static function mark_notification_read($notificationid, $timeread) {
1984         global $CFG, $DB, $USER;
1986         // Check if private messaging between users is allowed.
1987         if (empty($CFG->messaging)) {
1988             throw new moodle_exception('disabled', 'message');
1989         }
1991         // Warnings array, it can be empty at the end but is mandatory.
1992         $warnings = array();
1994         // Validate params.
1995         $params = array(
1996             'notificationid' => $notificationid,
1997             'timeread' => $timeread
1998         );
1999         $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2001         if (empty($params['timeread'])) {
2002             $timeread = time();
2003         } else {
2004             $timeread = $params['timeread'];
2005         }
2007         // Validate context.
2008         $context = context_system::instance();
2009         self::validate_context($context);
2011         $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2013         if ($notification->useridto != $USER->id) {
2014             throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2015                 'notification as read');
2016         }
2018         \core_message\api::mark_notification_as_read($notification, $timeread);
2020         $results = array(
2021             'notificationid' => $notification->id,
2022             'warnings' => $warnings
2023         );
2025         return $results;
2026     }
2028     /**
2029      * Returns description of method result value
2030      *
2031      * @return external_description
2032      */
2033     public static function mark_notification_read_returns() {
2034         return new external_single_structure(
2035             array(
2036                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2037                 'warnings' => new external_warnings()
2038             )
2039         );
2040     }
2042     /**
2043      * Mark all messages as read parameters description.
2044      *
2045      * @return external_function_parameters
2046      * @since 3.2
2047      */
2048     public static function mark_all_messages_as_read_parameters() {
2049         return new external_function_parameters(
2050             array(
2051                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2052                 'useridfrom' => new external_value(
2053                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2054                     VALUE_DEFAULT, 0),
2055             )
2056         );
2057     }
2059     /**
2060      * Mark all notifications as read function.
2061      *
2062      * @since  3.2
2063      * @throws invalid_parameter_exception
2064      * @throws moodle_exception
2065      * @param  int      $useridto       the user id who received the message
2066      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2067      * @return external_description
2068      */
2069     public static function mark_all_messages_as_read($useridto, $useridfrom) {
2070         global $USER, $CFG;
2072         // Check if messaging is enabled.
2073         if (empty($CFG->messaging)) {
2074             throw new moodle_exception('disabled', 'message');
2075         }
2077         $params = self::validate_parameters(
2078             self::mark_all_messages_as_read_parameters(),
2079             array(
2080                 'useridto' => $useridto,
2081                 'useridfrom' => $useridfrom,
2082             )
2083         );
2085         $context = context_system::instance();
2086         self::validate_context($context);
2088         $useridto = $params['useridto'];
2089         $useridfrom = $params['useridfrom'];
2091         if (!empty($useridto)) {
2092             if (core_user::is_real_user($useridto)) {
2093                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2094             } else {
2095                 throw new moodle_exception('invaliduser');
2096             }
2097         }
2099         if (!empty($useridfrom)) {
2100             // We use get_user here because the from user can be the noreply or support user.
2101             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2102         }
2104         // Check if the current user is the sender/receiver or just a privileged user.
2105         if ($useridto != $USER->id and $useridfrom != $USER->id and
2106             // The deleteanymessage cap seems more reasonable here than readallmessages.
2107              !has_capability('moodle/site:deleteanymessage', $context)) {
2108             throw new moodle_exception('accessdenied', 'admin');
2109         }
2111         if ($useridfrom) {
2112             if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
2113                 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
2114             }
2115         } else {
2116             \core_message\api::mark_all_messages_as_read($useridto);
2117         }
2119         return true;
2120     }
2122     /**
2123      * Mark all notifications as read return description.
2124      *
2125      * @return external_single_structure
2126      * @since 3.2
2127      */
2128     public static function mark_all_messages_as_read_returns() {
2129         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2130     }
2132     /**
2133      * Returns description of method parameters.
2134      *
2135      * @return external_function_parameters
2136      * @since 3.2
2137      */
2138     public static function delete_conversation_parameters() {
2139         return new external_function_parameters(
2140             array(
2141                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2142                 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
2143             )
2144         );
2145     }
2147     /**
2148      * Deletes a conversation.
2149      *
2150      * @param int $userid The user id of who we want to delete the conversation for
2151      * @param int $otheruserid The user id of the other user in the conversation
2152      * @return array
2153      * @throws moodle_exception
2154      * @since 3.2
2155      */
2156     public static function delete_conversation($userid, $otheruserid) {
2157         global $CFG;
2159         // Check if private messaging between users is allowed.
2160         if (empty($CFG->messaging)) {
2161             throw new moodle_exception('disabled', 'message');
2162         }
2164         // Warnings array, it can be empty at the end but is mandatory.
2165         $warnings = array();
2167         // Validate params.
2168         $params = array(
2169             'userid' => $userid,
2170             'otheruserid' => $otheruserid,
2171         );
2172         $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
2174         // Validate context.
2175         $context = context_system::instance();
2176         self::validate_context($context);
2178         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2179         core_user::require_active_user($user);
2181         if (\core_message\api::can_delete_conversation($user->id)) {
2182             $status = \core_message\api::delete_conversation($user->id, $otheruserid);
2183         } else {
2184             throw new moodle_exception('You do not have permission to delete messages');
2185         }
2187         $results = array(
2188             'status' => $status,
2189             'warnings' => $warnings
2190         );
2192         return $results;
2193     }
2195     /**
2196      * Returns description of method result value.
2197      *
2198      * @return external_description
2199      * @since 3.2
2200      */
2201     public static function delete_conversation_returns() {
2202         return new external_single_structure(
2203             array(
2204                 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
2205                 'warnings' => new external_warnings()
2206             )
2207         );
2208     }
2210     /**
2211      * Returns description of method parameters
2212      *
2213      * @return external_function_parameters
2214      * @since 3.1
2215      */
2216     public static function delete_message_parameters() {
2217         return new external_function_parameters(
2218             array(
2219                 'messageid' => new external_value(PARAM_INT, 'The message id'),
2220                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2221                 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2222             )
2223         );
2224     }
2226     /**
2227      * Deletes a message
2228      *
2229      * @param  int $messageid the message id
2230      * @param  int $userid the user id of who we want to delete the message for
2231      * @param  bool $read if is a message read (default to true)
2232      * @return external_description
2233      * @throws moodle_exception
2234      * @since 3.1
2235      */
2236     public static function delete_message($messageid, $userid, $read = true) {
2237         global $CFG;
2239         // Check if private messaging between users is allowed.
2240         if (empty($CFG->messaging)) {
2241             throw new moodle_exception('disabled', 'message');
2242         }
2244         // Warnings array, it can be empty at the end but is mandatory.
2245         $warnings = array();
2247         // Validate params.
2248         $params = array(
2249             'messageid' => $messageid,
2250             'userid' => $userid,
2251             'read' => $read
2252         );
2253         $params = self::validate_parameters(self::delete_message_parameters(), $params);
2255         // Validate context.
2256         $context = context_system::instance();
2257         self::validate_context($context);
2259         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2260         core_user::require_active_user($user);
2262         if (\core_message\api::can_delete_message($user->id, $messageid)) {
2263             $status = \core_message\api::delete_message($user->id, $messageid);
2264         } else {
2265             throw new moodle_exception('You do not have permission to delete this message');
2266         }
2268         $results = array(
2269             'status' => $status,
2270             'warnings' => $warnings
2271         );
2272         return $results;
2273     }
2275     /**
2276      * Returns description of method result value
2277      *
2278      * @return external_description
2279      * @since 3.1
2280      */
2281     public static function delete_message_returns() {
2282         return new external_single_structure(
2283             array(
2284                 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2285                 'warnings' => new external_warnings()
2286             )
2287         );
2288     }
2290     /**
2291      * Returns description of method parameters
2292      *
2293      * @return external_function_parameters
2294      * @since 3.2
2295      */
2296     public static function message_processor_config_form_parameters() {
2297         return new external_function_parameters(
2298             array(
2299                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2300                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
2301                 'formvalues' => new external_multiple_structure(
2302                     new external_single_structure(
2303                         array(
2304                             'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2305                             'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2306                         )
2307                     ),
2308                     'Config form values',
2309                     VALUE_REQUIRED
2310                 ),
2311             )
2312         );
2313     }
2315     /**
2316      * Processes a message processor config form.
2317      *
2318      * @param  int $userid the user id
2319      * @param  string $name the name of the processor
2320      * @param  array $formvalues the form values
2321      * @return external_description
2322      * @throws moodle_exception
2323      * @since 3.2
2324      */
2325     public static function message_processor_config_form($userid, $name, $formvalues) {
2326         global $USER, $CFG;
2328         // Check if messaging is enabled.
2329         if (empty($CFG->messaging)) {
2330             throw new moodle_exception('disabled', 'message');
2331         }
2333         $params = self::validate_parameters(
2334             self::message_processor_config_form_parameters(),
2335             array(
2336                 'userid' => $userid,
2337                 'name' => $name,
2338                 'formvalues' => $formvalues,
2339             )
2340         );
2342         $user = self::validate_preferences_permissions($params['userid']);
2344         $processor = get_message_processor($name);
2345         $preferences = [];
2346         $form = new stdClass();
2348         foreach ($formvalues as $formvalue) {
2349             // Curly braces to ensure interpretation is consistent between
2350             // php 5 and php 7.
2351             $form->{$formvalue['name']} = $formvalue['value'];
2352         }
2354         $processor->process_form($form, $preferences);
2356         if (!empty($preferences)) {
2357             set_user_preferences($preferences, $userid);
2358         }
2359     }
2361     /**
2362      * Returns description of method result value
2363      *
2364      * @return external_description
2365      * @since 3.2
2366      */
2367     public static function message_processor_config_form_returns() {
2368         return null;
2369     }
2371     /**
2372      * Returns description of method parameters
2373      *
2374      * @return external_function_parameters
2375      * @since 3.2
2376      */
2377     public static function get_message_processor_parameters() {
2378         return new external_function_parameters(
2379             array(
2380                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2381                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
2382             )
2383         );
2384     }
2386     /**
2387      * Get a message processor.
2388      *
2389      * @param int $userid
2390      * @param string $name the name of the processor
2391      * @return external_description
2392      * @throws moodle_exception
2393      * @since 3.2
2394      */
2395     public static function get_message_processor($userid = 0, $name) {
2396         global $USER, $PAGE, $CFG;
2398         // Check if messaging is enabled.
2399         if (empty($CFG->messaging)) {
2400             throw new moodle_exception('disabled', 'message');
2401         }
2403         $params = self::validate_parameters(
2404             self::get_message_processor_parameters(),
2405             array(
2406                 'userid' => $userid,
2407                 'name' => $name,
2408             )
2409         );
2411         if (empty($params['userid'])) {
2412             $params['userid'] = $USER->id;
2413         }
2415         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2416         core_user::require_active_user($user);
2417         self::validate_context(context_user::instance($params['userid']));
2419         $processor = get_message_processor($name);
2421         $processoroutput = new \core_message\output\processor($processor, $user);
2422         $renderer = $PAGE->get_renderer('core_message');
2424         return $processoroutput->export_for_template($renderer);
2425     }
2427     /**
2428      * Returns description of method result value
2429      *
2430      * @return external_description
2431      * @since 3.2
2432      */
2433     public static function get_message_processor_returns() {
2434         return new external_function_parameters(
2435             array(
2436                 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2437                 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2438             )
2439         );
2440     }
2442     /**
2443      * Check that the user has enough permission to retrieve message or notifications preferences.
2444      *
2445      * @param  int $userid the user id requesting the preferences
2446      * @return stdClass full user object
2447      * @throws moodle_exception
2448      * @since  Moodle 3.2
2449      */
2450     protected static function validate_preferences_permissions($userid) {
2451         global $USER;
2453         if (empty($userid)) {
2454             $user = $USER;
2455         } else {
2456             $user = core_user::get_user($userid, '*', MUST_EXIST);
2457             core_user::require_active_user($user);
2458         }
2460         $systemcontext = context_system::instance();
2461         self::validate_context($systemcontext);
2463         // Check access control.
2464         if ($user->id == $USER->id) {
2465             // Editing own message profile.
2466             require_capability('moodle/user:editownmessageprofile', $systemcontext);
2467         } else {
2468             // Teachers, parents, etc.
2469             $personalcontext = context_user::instance($user->id);
2470             require_capability('moodle/user:editmessageprofile', $personalcontext);
2471         }
2472         return $user;
2473     }
2475     /**
2476      * Returns a notification or message preference structure.
2477      *
2478      * @return external_single_structure the structure
2479      * @since  Moodle 3.2
2480      */
2481     protected static function get_preferences_structure() {
2482         return new external_single_structure(
2483             array(
2484                 'userid' => new external_value(PARAM_INT, 'User id'),
2485                 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
2486                 'processors' => new external_multiple_structure(
2487                     new external_single_structure(
2488                         array(
2489                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2490                             'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
2491                             'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
2492                             'contextid' => new external_value(PARAM_INT, 'Context id'),
2493                             'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
2494                         )
2495                     ),
2496                     'Config form values'
2497                 ),
2498                 'components' => new external_multiple_structure(
2499                     new external_single_structure(
2500                         array(
2501                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2502                             'notifications' => new external_multiple_structure(
2503                                 new external_single_structure(
2504                                     array(
2505                                         'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2506                                         'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
2507                                         'processors' => new external_multiple_structure(
2508                                             new external_single_structure(
2509                                                 array(
2510                                                     'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2511                                                     'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
2512                                                     'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
2513                                                     'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
2514                                                     'loggedin' => new external_single_structure(
2515                                                         array(
2516                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
2517                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2518                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
2519                                                         )
2520                                                     ),
2521                                                     'loggedoff' => new external_single_structure(
2522                                                         array(
2523                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
2524                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2525                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
2526                                                         )
2527                                                     ),
2528                                                 )
2529                                             ),
2530                                             'Processors values for this notification'
2531                                         ),
2532                                     )
2533                                 ),
2534                                 'List of notificaitons for the component'
2535                             ),
2536                         )
2537                     ),
2538                     'Available components'
2539                 ),
2540             )
2541         );
2542     }
2544     /**
2545      * Returns description of method parameters
2546      *
2547      * @return external_function_parameters
2548      * @since 3.2
2549      */
2550     public static function get_user_notification_preferences_parameters() {
2551         return new external_function_parameters(
2552             array(
2553                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
2554             )
2555         );
2556     }
2558     /**
2559      * Get the notification preferences for a given user.
2560      *
2561      * @param int $userid id of the user, 0 for current user
2562      * @return external_description
2563      * @throws moodle_exception
2564      * @since 3.2
2565      */
2566     public static function get_user_notification_preferences($userid = 0) {
2567         global $PAGE;
2569         $params = self::validate_parameters(
2570             self::get_user_notification_preferences_parameters(),
2571             array(
2572                 'userid' => $userid,
2573             )
2574         );
2575         $user = self::validate_preferences_permissions($params['userid']);
2577         $processors = get_message_processors();
2578         $providers = message_get_providers_for_user($user->id);
2579         $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
2580         $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
2582         $renderer = $PAGE->get_renderer('core_message');
2584         $result = array(
2585             'warnings' => array(),
2586             'preferences' => $notificationlist->export_for_template($renderer)
2587         );
2588         return $result;
2589     }
2591     /**
2592      * Returns description of method result value
2593      *
2594      * @return external_description
2595      * @since 3.2
2596      */
2597     public static function get_user_notification_preferences_returns() {
2598         return new external_function_parameters(
2599             array(
2600                 'preferences' => self::get_preferences_structure(),
2601                 'warnings' => new external_warnings(),
2602             )
2603         );
2604     }
2607     /**
2608      * Returns description of method parameters
2609      *
2610      * @return external_function_parameters
2611      * @since 3.2
2612      */
2613     public static function get_user_message_preferences_parameters() {
2614         return new external_function_parameters(
2615             array(
2616                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
2617             )
2618         );
2619     }
2621     /**
2622      * Get the notification preferences for a given user.
2623      *
2624      * @param int $userid id of the user, 0 for current user
2625      * @return external_description
2626      * @throws moodle_exception
2627      * @since 3.2
2628      */
2629     public static function get_user_message_preferences($userid = 0) {
2630         global $PAGE;
2632         $params = self::validate_parameters(
2633             self::get_user_message_preferences_parameters(),
2634             array(
2635                 'userid' => $userid,
2636             )
2637         );
2639         $user = self::validate_preferences_permissions($params['userid']);
2641         // Filter out enabled, available system_configured and user_configured processors only.
2642         $readyprocessors = array_filter(get_message_processors(), function($processor) {
2643             return $processor->enabled &&
2644                 $processor->configured &&
2645                 $processor->object->is_user_configured() &&
2646                 // Filter out processors that don't have and message preferences to configure.
2647                 $processor->object->has_message_preferences();
2648         });
2650         $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
2651             return $provider->component === 'moodle';
2652         });
2653         $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
2654         $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
2655             $providers, $preferences, $user);
2657         $renderer = $PAGE->get_renderer('core_message');
2659         $result = array(
2660             'warnings' => array(),
2661             'preferences' => $notificationlistoutput->export_for_template($renderer),
2662             'blocknoncontacts' => get_user_preferences('message_blocknoncontacts', '', $user->id) ? true : false,
2663         );
2664         return $result;
2665     }
2667     /**
2668      * Returns description of method result value
2669      *
2670      * @return external_description
2671      * @since 3.2
2672      */
2673     public static function get_user_message_preferences_returns() {
2674         return new external_function_parameters(
2675             array(
2676                 'preferences' => self::get_preferences_structure(),
2677                 'blocknoncontacts' => new external_value(PARAM_BOOL, 'Whether to block or not messages from non contacts'),
2678                 'warnings' => new external_warnings(),
2679             )
2680         );
2681     }