MDL-63426 repository_dropbox: Use post 2017 icon
[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                 // We need to get the user from the query.
1541                 if (empty($userfromfullname)) {
1542                     // Check for non-reply and support users.
1543                     if (core_user::is_real_user($message->useridfrom)) {
1544                         $user = new stdClass();
1545                         $user = username_load_fields_from_object($user, $message, 'userfrom');
1546                         $message->userfromfullname = fullname($user, $canviewfullname);
1547                     } else {
1548                         $user = core_user::get_user($message->useridfrom);
1549                         $message->userfromfullname = fullname($user, $canviewfullname);
1550                     }
1551                 } else {
1552                     $message->userfromfullname = $userfromfullname;
1553                 }
1555                 // We need to get the user from the query.
1556                 if (empty($usertofullname)) {
1557                     $user = new stdClass();
1558                     $user = username_load_fields_from_object($user, $message, 'userto');
1559                     $message->usertofullname = fullname($user, $canviewfullname);
1560                 } else {
1561                     $message->usertofullname = $usertofullname;
1562                 }
1564                 $message->text = message_format_message_text($message);
1565                 $messages[$mid] = (array) $message;
1566             }
1567         }
1569         $results = array(
1570             'messages' => $messages,
1571             'warnings' => $warnings
1572         );
1574         return $results;
1575     }
1577     /**
1578      * Get messages return description.
1579      *
1580      * @return external_single_structure
1581      * @since 2.8
1582      */
1583     public static function get_messages_returns() {
1584         return new external_single_structure(
1585             array(
1586                 'messages' => new external_multiple_structure(
1587                     new external_single_structure(
1588                         array(
1589                             'id' => new external_value(PARAM_INT, 'Message id'),
1590                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
1591                             'useridto' => new external_value(PARAM_INT, 'User to id'),
1592                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
1593                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
1594                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
1595                             'fullmessageformat' => new external_format_value('fullmessage'),
1596                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
1597                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
1598                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
1599                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
1600                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
1601                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
1602                             'timeread' => new external_value(PARAM_INT, 'Time read'),
1603                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
1604                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
1605                         ), 'message'
1606                     )
1607                 ),
1608                 'warnings' => new external_warnings()
1609             )
1610         );
1611     }
1613     /**
1614      * Mark all notifications as read parameters description.
1615      *
1616      * @return external_function_parameters
1617      * @since 3.2
1618      */
1619     public static function mark_all_notifications_as_read_parameters() {
1620         return new external_function_parameters(
1621             array(
1622                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1623                 'useridfrom' => new external_value(
1624                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1625                     VALUE_DEFAULT, 0),
1626             )
1627         );
1628     }
1630     /**
1631      * Mark all notifications as read function.
1632      *
1633      * @since  3.2
1634      * @throws invalid_parameter_exception
1635      * @throws moodle_exception
1636      * @param  int      $useridto       the user id who received the message
1637      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
1638      * @return external_description
1639      */
1640     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
1641         global $USER;
1643         $params = self::validate_parameters(
1644             self::mark_all_notifications_as_read_parameters(),
1645             array(
1646                 'useridto' => $useridto,
1647                 'useridfrom' => $useridfrom,
1648             )
1649         );
1651         $context = context_system::instance();
1652         self::validate_context($context);
1654         $useridto = $params['useridto'];
1655         $useridfrom = $params['useridfrom'];
1657         if (!empty($useridto)) {
1658             if (core_user::is_real_user($useridto)) {
1659                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
1660             } else {
1661                 throw new moodle_exception('invaliduser');
1662             }
1663         }
1665         if (!empty($useridfrom)) {
1666             // We use get_user here because the from user can be the noreply or support user.
1667             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
1668         }
1670         // Check if the current user is the sender/receiver or just a privileged user.
1671         if ($useridto != $USER->id and $useridfrom != $USER->id and
1672             // The deleteanymessage cap seems more reasonable here than readallmessages.
1673              !has_capability('moodle/site:deleteanymessage', $context)) {
1674             throw new moodle_exception('accessdenied', 'admin');
1675         }
1677         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
1679         return true;
1680     }
1682     /**
1683      * Mark all notifications as read return description.
1684      *
1685      * @return external_single_structure
1686      * @since 3.2
1687      */
1688     public static function mark_all_notifications_as_read_returns() {
1689         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
1690     }
1692     /**
1693      * Get unread conversations count parameters description.
1694      *
1695      * @return external_function_parameters
1696      * @since 3.2
1697      */
1698     public static function get_unread_conversations_count_parameters() {
1699         return new external_function_parameters(
1700             array(
1701                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1702             )
1703         );
1704     }
1706     /**
1707      * Get unread messages count function.
1708      *
1709      * @since  3.2
1710      * @throws invalid_parameter_exception
1711      * @throws moodle_exception
1712      * @param  int      $useridto       the user id who received the message
1713      * @return external_description
1714      */
1715     public static function get_unread_conversations_count($useridto) {
1716         global $USER, $CFG;
1718         // Check if messaging is enabled.
1719         if (empty($CFG->messaging)) {
1720             throw new moodle_exception('disabled', 'message');
1721         }
1723         $params = self::validate_parameters(
1724             self::get_unread_conversations_count_parameters(),
1725             array('useridto' => $useridto)
1726         );
1728         $context = context_system::instance();
1729         self::validate_context($context);
1731         $useridto = $params['useridto'];
1733         if (!empty($useridto)) {
1734             if (core_user::is_real_user($useridto)) {
1735                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
1736             } else {
1737                 throw new moodle_exception('invaliduser');
1738             }
1739         } else {
1740             $useridto = $USER->id;
1741         }
1743         // Check if the current user is the receiver or just a privileged user.
1744         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
1745             throw new moodle_exception('accessdenied', 'admin');
1746         }
1748         return \core_message\api::count_unread_conversations($userto);
1749     }
1751     /**
1752      * Get unread conversations count return description.
1753      *
1754      * @return external_single_structure
1755      * @since 3.2
1756      */
1757     public static function get_unread_conversations_count_returns() {
1758         return new external_value(PARAM_INT, 'The count of unread messages for the user');
1759     }
1761     /**
1762      * Get blocked users parameters description.
1763      *
1764      * @return external_function_parameters
1765      * @since 2.9
1766      */
1767     public static function get_blocked_users_parameters() {
1768         return new external_function_parameters(
1769             array(
1770                 'userid' => new external_value(PARAM_INT,
1771                                 'the user whose blocked users we want to retrieve',
1772                                 VALUE_REQUIRED),
1773             )
1774         );
1775     }
1777     /**
1778      * Retrieve a list of users blocked
1779      *
1780      * @param  int $userid the user whose blocked users we want to retrieve
1781      * @return external_description
1782      * @since 2.9
1783      */
1784     public static function get_blocked_users($userid) {
1785         global $CFG, $USER, $PAGE;
1787         // Warnings array, it can be empty at the end but is mandatory.
1788         $warnings = array();
1790         // Validate params.
1791         $params = array(
1792             'userid' => $userid
1793         );
1794         $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
1795         $userid = $params['userid'];
1797         // Validate context.
1798         $context = context_system::instance();
1799         self::validate_context($context);
1801         // Check if private messaging between users is allowed.
1802         if (empty($CFG->messaging)) {
1803             throw new moodle_exception('disabled', 'message');
1804         }
1806         $user = core_user::get_user($userid, '*', MUST_EXIST);
1807         core_user::require_active_user($user);
1809         // Check if we have permissions for retrieve the information.
1810         $capability = 'moodle/site:manageallmessaging';
1811         if (($USER->id != $userid) && !has_capability($capability, $context)) {
1812             throw new required_capability_exception($context, $capability, 'nopermissions', '');
1813         }
1815         // Now, we can get safely all the blocked users.
1816         $users = \core_message\api::get_blocked_users($user->id);
1818         $blockedusers = array();
1819         foreach ($users as $user) {
1820             $newuser = array(
1821                 'id' => $user->id,
1822                 'fullname' => fullname($user),
1823             );
1825             $userpicture = new user_picture($user);
1826             $userpicture->size = 1; // Size f1.
1827             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1829             $blockedusers[] = $newuser;
1830         }
1832         $results = array(
1833             'users' => $blockedusers,
1834             'warnings' => $warnings
1835         );
1836         return $results;
1837     }
1839     /**
1840      * Get blocked users return description.
1841      *
1842      * @return external_single_structure
1843      * @since 2.9
1844      */
1845     public static function get_blocked_users_returns() {
1846         return new external_single_structure(
1847             array(
1848                 'users' => new external_multiple_structure(
1849                     new external_single_structure(
1850                         array(
1851                             'id' => new external_value(PARAM_INT, 'User ID'),
1852                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1853                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
1854                         )
1855                     ),
1856                     'List of blocked users'
1857                 ),
1858                 'warnings' => new external_warnings()
1859             )
1860         );
1861     }
1863     /**
1864      * Returns description of method parameters
1865      *
1866      * @return external_function_parameters
1867      * @since 2.9
1868      */
1869     public static function mark_message_read_parameters() {
1870         return new external_function_parameters(
1871             array(
1872                 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
1873                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
1874                     VALUE_DEFAULT, 0)
1875             )
1876         );
1877     }
1879     /**
1880      * Mark a single message as read, trigger message_viewed event
1881      *
1882      * @param  int $messageid id of the message (in the message table)
1883      * @param  int $timeread timestamp for when the message should be marked read
1884      * @return external_description
1885      * @throws invalid_parameter_exception
1886      * @throws moodle_exception
1887      * @since 2.9
1888      */
1889     public static function mark_message_read($messageid, $timeread) {
1890         global $CFG, $DB, $USER;
1892         // Check if private messaging between users is allowed.
1893         if (empty($CFG->messaging)) {
1894             throw new moodle_exception('disabled', 'message');
1895         }
1897         // Warnings array, it can be empty at the end but is mandatory.
1898         $warnings = array();
1900         // Validate params.
1901         $params = array(
1902             'messageid' => $messageid,
1903             'timeread' => $timeread
1904         );
1905         $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
1907         if (empty($params['timeread'])) {
1908             $timeread = time();
1909         } else {
1910             $timeread = $params['timeread'];
1911         }
1913         // Validate context.
1914         $context = context_system::instance();
1915         self::validate_context($context);
1917         $sql = "SELECT m.*, mcm.userid as useridto
1918                   FROM {messages} m
1919             INNER JOIN {message_conversations} mc
1920                     ON m.conversationid = mc.id
1921             INNER JOIN {message_conversation_members} mcm
1922                     ON mcm.conversationid = mc.id
1923              LEFT JOIN {message_user_actions} mua
1924                     ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
1925                  WHERE mua.id is NULL
1926                    AND mcm.userid != m.useridfrom
1927                    AND m.id = ?";
1928         $messageparams = [];
1929         $messageparams[] = $USER->id;
1930         $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
1931         $messageparams[] = $params['messageid'];
1932         $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
1934         if ($message->useridto != $USER->id) {
1935             throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
1936         }
1938         \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
1940         $results = array(
1941             'messageid' => $message->id,
1942             'warnings' => $warnings
1943         );
1944         return $results;
1945     }
1947     /**
1948      * Returns description of method result value
1949      *
1950      * @return external_description
1951      * @since 2.9
1952      */
1953     public static function mark_message_read_returns() {
1954         return new external_single_structure(
1955             array(
1956                 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
1957                 'warnings' => new external_warnings()
1958             )
1959         );
1960     }
1962     /**
1963      * Returns description of method parameters
1964      *
1965      * @return external_function_parameters
1966      */
1967     public static function mark_notification_read_parameters() {
1968         return new external_function_parameters(
1969             array(
1970                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
1971                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
1972                     VALUE_DEFAULT, 0)
1973             )
1974         );
1975     }
1977     /**
1978      * Mark a single notification as read.
1979      *
1980      * This will trigger a 'notification_viewed' event.
1981      *
1982      * @param int $notificationid id of the notification
1983      * @param int $timeread timestamp for when the notification should be marked read
1984      * @return external_description
1985      * @throws invalid_parameter_exception
1986      * @throws moodle_exception
1987      */
1988     public static function mark_notification_read($notificationid, $timeread) {
1989         global $CFG, $DB, $USER;
1991         // Check if private messaging between users is allowed.
1992         if (empty($CFG->messaging)) {
1993             throw new moodle_exception('disabled', 'message');
1994         }
1996         // Warnings array, it can be empty at the end but is mandatory.
1997         $warnings = array();
1999         // Validate params.
2000         $params = array(
2001             'notificationid' => $notificationid,
2002             'timeread' => $timeread
2003         );
2004         $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2006         if (empty($params['timeread'])) {
2007             $timeread = time();
2008         } else {
2009             $timeread = $params['timeread'];
2010         }
2012         // Validate context.
2013         $context = context_system::instance();
2014         self::validate_context($context);
2016         $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2018         if ($notification->useridto != $USER->id) {
2019             throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2020                 'notification as read');
2021         }
2023         \core_message\api::mark_notification_as_read($notification, $timeread);
2025         $results = array(
2026             'notificationid' => $notification->id,
2027             'warnings' => $warnings
2028         );
2030         return $results;
2031     }
2033     /**
2034      * Returns description of method result value
2035      *
2036      * @return external_description
2037      */
2038     public static function mark_notification_read_returns() {
2039         return new external_single_structure(
2040             array(
2041                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2042                 'warnings' => new external_warnings()
2043             )
2044         );
2045     }
2047     /**
2048      * Mark all messages as read parameters description.
2049      *
2050      * @return external_function_parameters
2051      * @since 3.2
2052      */
2053     public static function mark_all_messages_as_read_parameters() {
2054         return new external_function_parameters(
2055             array(
2056                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2057                 'useridfrom' => new external_value(
2058                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2059                     VALUE_DEFAULT, 0),
2060             )
2061         );
2062     }
2064     /**
2065      * Mark all notifications as read function.
2066      *
2067      * @since  3.2
2068      * @throws invalid_parameter_exception
2069      * @throws moodle_exception
2070      * @param  int      $useridto       the user id who received the message
2071      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2072      * @return external_description
2073      */
2074     public static function mark_all_messages_as_read($useridto, $useridfrom) {
2075         global $USER, $CFG;
2077         // Check if messaging is enabled.
2078         if (empty($CFG->messaging)) {
2079             throw new moodle_exception('disabled', 'message');
2080         }
2082         $params = self::validate_parameters(
2083             self::mark_all_messages_as_read_parameters(),
2084             array(
2085                 'useridto' => $useridto,
2086                 'useridfrom' => $useridfrom,
2087             )
2088         );
2090         $context = context_system::instance();
2091         self::validate_context($context);
2093         $useridto = $params['useridto'];
2094         $useridfrom = $params['useridfrom'];
2096         if (!empty($useridto)) {
2097             if (core_user::is_real_user($useridto)) {
2098                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2099             } else {
2100                 throw new moodle_exception('invaliduser');
2101             }
2102         }
2104         if (!empty($useridfrom)) {
2105             // We use get_user here because the from user can be the noreply or support user.
2106             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2107         }
2109         // Check if the current user is the sender/receiver or just a privileged user.
2110         if ($useridto != $USER->id and $useridfrom != $USER->id and
2111             // The deleteanymessage cap seems more reasonable here than readallmessages.
2112              !has_capability('moodle/site:deleteanymessage', $context)) {
2113             throw new moodle_exception('accessdenied', 'admin');
2114         }
2116         if ($useridfrom) {
2117             if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
2118                 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
2119             }
2120         } else {
2121             \core_message\api::mark_all_messages_as_read($useridto);
2122         }
2124         return true;
2125     }
2127     /**
2128      * Mark all notifications as read return description.
2129      *
2130      * @return external_single_structure
2131      * @since 3.2
2132      */
2133     public static function mark_all_messages_as_read_returns() {
2134         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2135     }
2137     /**
2138      * Returns description of method parameters.
2139      *
2140      * @return external_function_parameters
2141      * @since 3.2
2142      */
2143     public static function delete_conversation_parameters() {
2144         return new external_function_parameters(
2145             array(
2146                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2147                 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
2148             )
2149         );
2150     }
2152     /**
2153      * Deletes a conversation.
2154      *
2155      * @param int $userid The user id of who we want to delete the conversation for
2156      * @param int $otheruserid The user id of the other user in the conversation
2157      * @return array
2158      * @throws moodle_exception
2159      * @since 3.2
2160      */
2161     public static function delete_conversation($userid, $otheruserid) {
2162         global $CFG;
2164         // Check if private messaging between users is allowed.
2165         if (empty($CFG->messaging)) {
2166             throw new moodle_exception('disabled', 'message');
2167         }
2169         // Warnings array, it can be empty at the end but is mandatory.
2170         $warnings = array();
2172         // Validate params.
2173         $params = array(
2174             'userid' => $userid,
2175             'otheruserid' => $otheruserid,
2176         );
2177         $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
2179         // Validate context.
2180         $context = context_system::instance();
2181         self::validate_context($context);
2183         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2184         core_user::require_active_user($user);
2186         if (\core_message\api::can_delete_conversation($user->id)) {
2187             $status = \core_message\api::delete_conversation($user->id, $otheruserid);
2188         } else {
2189             throw new moodle_exception('You do not have permission to delete messages');
2190         }
2192         $results = array(
2193             'status' => $status,
2194             'warnings' => $warnings
2195         );
2197         return $results;
2198     }
2200     /**
2201      * Returns description of method result value.
2202      *
2203      * @return external_description
2204      * @since 3.2
2205      */
2206     public static function delete_conversation_returns() {
2207         return new external_single_structure(
2208             array(
2209                 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
2210                 'warnings' => new external_warnings()
2211             )
2212         );
2213     }
2215     /**
2216      * Returns description of method parameters
2217      *
2218      * @return external_function_parameters
2219      * @since 3.1
2220      */
2221     public static function delete_message_parameters() {
2222         return new external_function_parameters(
2223             array(
2224                 'messageid' => new external_value(PARAM_INT, 'The message id'),
2225                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2226                 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2227             )
2228         );
2229     }
2231     /**
2232      * Deletes a message
2233      *
2234      * @param  int $messageid the message id
2235      * @param  int $userid the user id of who we want to delete the message for
2236      * @param  bool $read if is a message read (default to true)
2237      * @return external_description
2238      * @throws moodle_exception
2239      * @since 3.1
2240      */
2241     public static function delete_message($messageid, $userid, $read = true) {
2242         global $CFG;
2244         // Check if private messaging between users is allowed.
2245         if (empty($CFG->messaging)) {
2246             throw new moodle_exception('disabled', 'message');
2247         }
2249         // Warnings array, it can be empty at the end but is mandatory.
2250         $warnings = array();
2252         // Validate params.
2253         $params = array(
2254             'messageid' => $messageid,
2255             'userid' => $userid,
2256             'read' => $read
2257         );
2258         $params = self::validate_parameters(self::delete_message_parameters(), $params);
2260         // Validate context.
2261         $context = context_system::instance();
2262         self::validate_context($context);
2264         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2265         core_user::require_active_user($user);
2267         if (\core_message\api::can_delete_message($user->id, $messageid)) {
2268             $status = \core_message\api::delete_message($user->id, $messageid);
2269         } else {
2270             throw new moodle_exception('You do not have permission to delete this message');
2271         }
2273         $results = array(
2274             'status' => $status,
2275             'warnings' => $warnings
2276         );
2277         return $results;
2278     }
2280     /**
2281      * Returns description of method result value
2282      *
2283      * @return external_description
2284      * @since 3.1
2285      */
2286     public static function delete_message_returns() {
2287         return new external_single_structure(
2288             array(
2289                 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2290                 'warnings' => new external_warnings()
2291             )
2292         );
2293     }
2295     /**
2296      * Returns description of method parameters
2297      *
2298      * @return external_function_parameters
2299      * @since 3.2
2300      */
2301     public static function message_processor_config_form_parameters() {
2302         return new external_function_parameters(
2303             array(
2304                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2305                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
2306                 'formvalues' => new external_multiple_structure(
2307                     new external_single_structure(
2308                         array(
2309                             'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2310                             'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2311                         )
2312                     ),
2313                     'Config form values',
2314                     VALUE_REQUIRED
2315                 ),
2316             )
2317         );
2318     }
2320     /**
2321      * Processes a message processor config form.
2322      *
2323      * @param  int $userid the user id
2324      * @param  string $name the name of the processor
2325      * @param  array $formvalues the form values
2326      * @return external_description
2327      * @throws moodle_exception
2328      * @since 3.2
2329      */
2330     public static function message_processor_config_form($userid, $name, $formvalues) {
2331         global $USER, $CFG;
2333         // Check if messaging is enabled.
2334         if (empty($CFG->messaging)) {
2335             throw new moodle_exception('disabled', 'message');
2336         }
2338         $params = self::validate_parameters(
2339             self::message_processor_config_form_parameters(),
2340             array(
2341                 'userid' => $userid,
2342                 'name' => $name,
2343                 'formvalues' => $formvalues,
2344             )
2345         );
2347         $user = self::validate_preferences_permissions($params['userid']);
2349         $processor = get_message_processor($name);
2350         $preferences = [];
2351         $form = new stdClass();
2353         foreach ($formvalues as $formvalue) {
2354             // Curly braces to ensure interpretation is consistent between
2355             // php 5 and php 7.
2356             $form->{$formvalue['name']} = $formvalue['value'];
2357         }
2359         $processor->process_form($form, $preferences);
2361         if (!empty($preferences)) {
2362             set_user_preferences($preferences, $userid);
2363         }
2364     }
2366     /**
2367      * Returns description of method result value
2368      *
2369      * @return external_description
2370      * @since 3.2
2371      */
2372     public static function message_processor_config_form_returns() {
2373         return null;
2374     }
2376     /**
2377      * Returns description of method parameters
2378      *
2379      * @return external_function_parameters
2380      * @since 3.2
2381      */
2382     public static function get_message_processor_parameters() {
2383         return new external_function_parameters(
2384             array(
2385                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2386                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
2387             )
2388         );
2389     }
2391     /**
2392      * Get a message processor.
2393      *
2394      * @param int $userid
2395      * @param string $name the name of the processor
2396      * @return external_description
2397      * @throws moodle_exception
2398      * @since 3.2
2399      */
2400     public static function get_message_processor($userid = 0, $name) {
2401         global $USER, $PAGE, $CFG;
2403         // Check if messaging is enabled.
2404         if (empty($CFG->messaging)) {
2405             throw new moodle_exception('disabled', 'message');
2406         }
2408         $params = self::validate_parameters(
2409             self::get_message_processor_parameters(),
2410             array(
2411                 'userid' => $userid,
2412                 'name' => $name,
2413             )
2414         );
2416         if (empty($params['userid'])) {
2417             $params['userid'] = $USER->id;
2418         }
2420         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2421         core_user::require_active_user($user);
2422         self::validate_context(context_user::instance($params['userid']));
2424         $processor = get_message_processor($name);
2426         $processoroutput = new \core_message\output\processor($processor, $user);
2427         $renderer = $PAGE->get_renderer('core_message');
2429         return $processoroutput->export_for_template($renderer);
2430     }
2432     /**
2433      * Returns description of method result value
2434      *
2435      * @return external_description
2436      * @since 3.2
2437      */
2438     public static function get_message_processor_returns() {
2439         return new external_function_parameters(
2440             array(
2441                 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2442                 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2443             )
2444         );
2445     }
2447     /**
2448      * Check that the user has enough permission to retrieve message or notifications preferences.
2449      *
2450      * @param  int $userid the user id requesting the preferences
2451      * @return stdClass full user object
2452      * @throws moodle_exception
2453      * @since  Moodle 3.2
2454      */
2455     protected static function validate_preferences_permissions($userid) {
2456         global $USER;
2458         if (empty($userid)) {
2459             $user = $USER;
2460         } else {
2461             $user = core_user::get_user($userid, '*', MUST_EXIST);
2462             core_user::require_active_user($user);
2463         }
2465         $systemcontext = context_system::instance();
2466         self::validate_context($systemcontext);
2468         // Check access control.
2469         if ($user->id == $USER->id) {
2470             // Editing own message profile.
2471             require_capability('moodle/user:editownmessageprofile', $systemcontext);
2472         } else {
2473             // Teachers, parents, etc.
2474             $personalcontext = context_user::instance($user->id);
2475             require_capability('moodle/user:editmessageprofile', $personalcontext);
2476         }
2477         return $user;
2478     }
2480     /**
2481      * Returns a notification or message preference structure.
2482      *
2483      * @return external_single_structure the structure
2484      * @since  Moodle 3.2
2485      */
2486     protected static function get_preferences_structure() {
2487         return new external_single_structure(
2488             array(
2489                 'userid' => new external_value(PARAM_INT, 'User id'),
2490                 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
2491                 'processors' => new external_multiple_structure(
2492                     new external_single_structure(
2493                         array(
2494                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2495                             'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
2496                             'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
2497                             'contextid' => new external_value(PARAM_INT, 'Context id'),
2498                             'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
2499                         )
2500                     ),
2501                     'Config form values'
2502                 ),
2503                 'components' => new external_multiple_structure(
2504                     new external_single_structure(
2505                         array(
2506                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2507                             'notifications' => new external_multiple_structure(
2508                                 new external_single_structure(
2509                                     array(
2510                                         'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2511                                         'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
2512                                         'processors' => new external_multiple_structure(
2513                                             new external_single_structure(
2514                                                 array(
2515                                                     'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2516                                                     'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
2517                                                     'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
2518                                                     'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
2519                                                     'loggedin' => new external_single_structure(
2520                                                         array(
2521                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
2522                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2523                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
2524                                                         )
2525                                                     ),
2526                                                     'loggedoff' => new external_single_structure(
2527                                                         array(
2528                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
2529                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2530                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
2531                                                         )
2532                                                     ),
2533                                                 )
2534                                             ),
2535                                             'Processors values for this notification'
2536                                         ),
2537                                     )
2538                                 ),
2539                                 'List of notificaitons for the component'
2540                             ),
2541                         )
2542                     ),
2543                     'Available components'
2544                 ),
2545             )
2546         );
2547     }
2549     /**
2550      * Returns description of method parameters
2551      *
2552      * @return external_function_parameters
2553      * @since 3.2
2554      */
2555     public static function get_user_notification_preferences_parameters() {
2556         return new external_function_parameters(
2557             array(
2558                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
2559             )
2560         );
2561     }
2563     /**
2564      * Get the notification preferences for a given user.
2565      *
2566      * @param int $userid id of the user, 0 for current user
2567      * @return external_description
2568      * @throws moodle_exception
2569      * @since 3.2
2570      */
2571     public static function get_user_notification_preferences($userid = 0) {
2572         global $PAGE;
2574         $params = self::validate_parameters(
2575             self::get_user_notification_preferences_parameters(),
2576             array(
2577                 'userid' => $userid,
2578             )
2579         );
2580         $user = self::validate_preferences_permissions($params['userid']);
2582         $processors = get_message_processors();
2583         $providers = message_get_providers_for_user($user->id);
2584         $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
2585         $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
2587         $renderer = $PAGE->get_renderer('core_message');
2589         $result = array(
2590             'warnings' => array(),
2591             'preferences' => $notificationlist->export_for_template($renderer)
2592         );
2593         return $result;
2594     }
2596     /**
2597      * Returns description of method result value
2598      *
2599      * @return external_description
2600      * @since 3.2
2601      */
2602     public static function get_user_notification_preferences_returns() {
2603         return new external_function_parameters(
2604             array(
2605                 'preferences' => self::get_preferences_structure(),
2606                 'warnings' => new external_warnings(),
2607             )
2608         );
2609     }
2612     /**
2613      * Returns description of method parameters
2614      *
2615      * @return external_function_parameters
2616      * @since 3.2
2617      */
2618     public static function get_user_message_preferences_parameters() {
2619         return new external_function_parameters(
2620             array(
2621                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
2622             )
2623         );
2624     }
2626     /**
2627      * Get the notification preferences for a given user.
2628      *
2629      * @param int $userid id of the user, 0 for current user
2630      * @return external_description
2631      * @throws moodle_exception
2632      * @since 3.2
2633      */
2634     public static function get_user_message_preferences($userid = 0) {
2635         global $PAGE;
2637         $params = self::validate_parameters(
2638             self::get_user_message_preferences_parameters(),
2639             array(
2640                 'userid' => $userid,
2641             )
2642         );
2644         $user = self::validate_preferences_permissions($params['userid']);
2646         // Filter out enabled, available system_configured and user_configured processors only.
2647         $readyprocessors = array_filter(get_message_processors(), function($processor) {
2648             return $processor->enabled &&
2649                 $processor->configured &&
2650                 $processor->object->is_user_configured() &&
2651                 // Filter out processors that don't have and message preferences to configure.
2652                 $processor->object->has_message_preferences();
2653         });
2655         $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
2656             return $provider->component === 'moodle';
2657         });
2658         $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
2659         $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
2660             $providers, $preferences, $user);
2662         $renderer = $PAGE->get_renderer('core_message');
2664         $result = array(
2665             'warnings' => array(),
2666             'preferences' => $notificationlistoutput->export_for_template($renderer),
2667             'blocknoncontacts' => get_user_preferences('message_blocknoncontacts', '', $user->id) ? true : false,
2668         );
2669         return $result;
2670     }
2672     /**
2673      * Returns description of method result value
2674      *
2675      * @return external_description
2676      * @since 3.2
2677      */
2678     public static function get_user_message_preferences_returns() {
2679         return new external_function_parameters(
2680             array(
2681                 'preferences' => self::get_preferences_structure(),
2682                 'blocknoncontacts' => new external_value(PARAM_BOOL, 'Whether to block or not messages from non contacts'),
2683                 'warnings' => new external_warnings(),
2684             )
2685         );
2686     }