MDL-65132 core_message: Added API to delete message for all users
[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 {
42     /**
43      * Returns description of method parameters
44      *
45      * @return external_function_parameters
46      * @since Moodle 3.6
47      */
48     public static function send_messages_to_conversation_parameters() {
49         return new external_function_parameters(
50             array(
51                 'conversationid' => new external_value(PARAM_INT, 'id of the conversation'),
52                 'messages' => new external_multiple_structure(
53                     new external_single_structure(
54                         array(
55                             'text' => new external_value(PARAM_RAW, 'the text of the message'),
56                             'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
57                         )
58                     )
59                 )
60             )
61         );
62     }
64     /**
65      * Send messages from the current USER to a conversation.
66      *
67      * This conversation may be any type of conversation, individual or group.
68      *
69      * @param int $conversationid the id of the conversation to which the messages will be sent.
70      * @param array $messages An array of message to send.
71      * @return array the array of messages which were sent (created).
72      * @since Moodle 3.6
73      */
74     public static function send_messages_to_conversation(int $conversationid, array $messages = []) {
75         global $CFG, $USER;
77         // Check if messaging is enabled.
78         if (empty($CFG->messaging)) {
79             throw new moodle_exception('disabled', 'message');
80         }
82         // Ensure the current user is allowed to run this function.
83         $context = context_system::instance();
84         self::validate_context($context);
86         $params = self::validate_parameters(self::send_messages_to_conversation_parameters(), [
87             'conversationid' => $conversationid,
88             'messages' => $messages
89         ]);
91         $messages = [];
92         foreach ($params['messages'] as $message) {
93             $createdmessage = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
94                 $message['textformat']);
95             $createdmessage->text = message_format_message_text((object) [
96                 'smallmessage' => $createdmessage->text,
97                 'fullmessageformat' => external_validate_format($message['textformat']),
98                 'fullmessagetrust' => $createdmessage->fullmessagetrust
99             ]);
100             $messages[] = $createdmessage;
101         }
103         return $messages;
104     }
106     /**
107      * Returns description of method result value.
108      *
109      * @return external_description
110      * @since Moodle 3.6
111      */
112     public static function send_messages_to_conversation_returns() {
113         return new external_multiple_structure(
114             self::get_conversation_message_structure()
115         );
116     }
119     /**
120      * Returns description of method parameters
121      *
122      * @return external_function_parameters
123      * @since Moodle 2.2
124      */
125     public static function send_instant_messages_parameters() {
126         return new external_function_parameters(
127             array(
128                 'messages' => new external_multiple_structure(
129                     new external_single_structure(
130                         array(
131                             'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
132                             'text' => new external_value(PARAM_RAW, 'the text of the message'),
133                             'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
134                             '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),
135                         )
136                     )
137                 )
138             )
139         );
140     }
142     /**
143      * Send private messages from the current USER to other users
144      *
145      * @param array $messages An array of message to send.
146      * @return array
147      * @since Moodle 2.2
148      */
149     public static function send_instant_messages($messages = array()) {
150         global $CFG, $USER, $DB;
152         // Check if messaging is enabled.
153         if (empty($CFG->messaging)) {
154             throw new moodle_exception('disabled', 'message');
155         }
157         // Ensure the current user is allowed to run this function
158         $context = context_system::instance();
159         self::validate_context($context);
160         require_capability('moodle/site:sendmessage', $context);
162         $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
164         //retrieve all tousers of the messages
165         $receivers = array();
166         foreach($params['messages'] as $message) {
167             $receivers[] = $message['touserid'];
168         }
169         list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
170         $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
172         $resultmessages = array();
173         $messageids = array();
174         foreach ($params['messages'] as $message) {
175             $resultmsg = array(); //the infos about the success of the operation
177             // We are going to do some checking.
178             // Code should match /messages/index.php checks.
179             $success = true;
181             // Check the user exists.
182             if (empty($tousers[$message['touserid']])) {
183                 $success = false;
184                 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
185             }
187             // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
188             // Check if the recipient can be messaged by the sender.
189             if ($success && !\core_message\api::can_post_message($tousers[$message['touserid']], $USER)) {
190                 $success = false;
191                 $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
192             }
194             // Now we can send the message (at least try).
195             if ($success) {
196                 // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
197                 $success = message_post_message($USER, $tousers[$message['touserid']],
198                         $message['text'], external_validate_format($message['textformat']));
199             }
201             // Build the resultmsg.
202             if (isset($message['clientmsgid'])) {
203                 $resultmsg['clientmsgid'] = $message['clientmsgid'];
204             }
205             if ($success) {
206                 $resultmsg['msgid'] = $success;
207                 $resultmsg['timecreated'] = time();
208                 $messageids[] = $success;
209             } else {
210                 // WARNINGS: for backward compatibility we return this errormessage.
211                 //          We should have thrown exceptions as these errors prevent results to be returned.
212                 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
213                 $resultmsg['msgid'] = -1;
214                 $resultmsg['errormessage'] = $errormessage;
215             }
217             $resultmessages[] = $resultmsg;
218         }
220         if (!empty($messageids)) {
221             $messagerecords = $DB->get_records_list(
222                 'messages',
223                 'id',
224                 $messageids,
225                 '',
226                 'id, conversationid, smallmessage, fullmessageformat, fullmessagetrust');
227             $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) {
228                 $id = $resultmessage['msgid'];
229                 $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null;
230                 $resultmessage['useridfrom'] = $USER->id;
231                 $resultmessage['text'] = message_format_message_text((object) [
232                     'smallmessage' => $messagerecords[$id]->smallmessage,
233                     'fullmessageformat' => external_validate_format($messagerecords[$id]->fullmessageformat),
234                     'fullmessagetrust' => $messagerecords[$id]->fullmessagetrust
235                 ]);
236                 return $resultmessage;
237             }, $resultmessages);
238         }
240         return $resultmessages;
241     }
243     /**
244      * Returns description of method result value
245      *
246      * @return external_description
247      * @since Moodle 2.2
248      */
249     public static function send_instant_messages_returns() {
250         return new external_multiple_structure(
251             new external_single_structure(
252                 array(
253                     'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
254                     'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
255                     'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL),
256                     'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL),
257                     'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
258                     'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
259                     'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
260                 )
261             )
262         );
263     }
265     /**
266      * Create contacts parameters description.
267      *
268      * @deprecated since Moodle 3.6
269      * @return external_function_parameters
270      * @since Moodle 2.5
271      */
272     public static function create_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 creating the contacts for, 0 for the
280                     current user', VALUE_DEFAULT, 0)
281             )
282         );
283     }
285     /**
286      * Create contacts.
287      *
288      * @deprecated since Moodle 3.6
289      * @param array $userids array of user IDs.
290      * @param int $userid The id of the user we are creating the contacts for
291      * @return external_description
292      * @since Moodle 2.5
293      */
294     public static function create_contacts($userids, $userid = 0) {
295         global $CFG, $USER;
297         // Check if messaging is enabled.
298         if (empty($CFG->messaging)) {
299             throw new moodle_exception('disabled', 'message');
300         }
302         if (empty($userid)) {
303             $userid = $USER->id;
304         }
306         // Validate context.
307         $context = context_system::instance();
308         self::validate_context($context);
310         $params = array('userids' => $userids, 'userid' => $userid);
311         $params = self::validate_parameters(self::create_contacts_parameters(), $params);
313         $capability = 'moodle/site:manageallmessaging';
314         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
315             throw new required_capability_exception($context, $capability, 'nopermissions', '');
316         }
318         $warnings = array();
319         foreach ($params['userids'] as $id) {
320             if (!message_add_contact($id, 0, $params['userid'])) {
321                 $warnings[] = array(
322                     'item' => 'user',
323                     'itemid' => $id,
324                     'warningcode' => 'contactnotcreated',
325                     'message' => 'The contact could not be created'
326                 );
327             }
328         }
329         return $warnings;
330     }
332     /**
333      * Create contacts return description.
334      *
335      * @deprecated since Moodle 3.6
336      * @return external_description
337      * @since Moodle 2.5
338      */
339     public static function create_contacts_returns() {
340         return new external_warnings();
341     }
343     /**
344      * Marking the method as deprecated.
345      *
346      * @return bool
347      */
348     public static function create_contacts_is_deprecated() {
349         return true;
350     }
352     /**
353      * Delete contacts parameters description.
354      *
355      * @return external_function_parameters
356      * @since Moodle 2.5
357      */
358     public static function delete_contacts_parameters() {
359         return new external_function_parameters(
360             array(
361                 'userids' => new external_multiple_structure(
362                     new external_value(PARAM_INT, 'User ID'),
363                     'List of user IDs'
364                 ),
365                 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
366                     current user', VALUE_DEFAULT, 0)
367             )
368         );
369     }
371     /**
372      * Delete contacts.
373      *
374      * @param array $userids array of user IDs.
375      * @param int $userid The id of the user we are deleting the contacts for
376      * @return null
377      * @since Moodle 2.5
378      */
379     public static function delete_contacts($userids, $userid = 0) {
380         global $CFG, $USER;
382         // Check if messaging is enabled.
383         if (empty($CFG->messaging)) {
384             throw new moodle_exception('disabled', 'message');
385         }
387         if (empty($userid)) {
388             $userid = $USER->id;
389         }
391         // Validate context.
392         $context = context_system::instance();
393         self::validate_context($context);
395         $params = array('userids' => $userids, 'userid' => $userid);
396         $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
398         $capability = 'moodle/site:manageallmessaging';
399         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
400             throw new required_capability_exception($context, $capability, 'nopermissions', '');
401         }
403         foreach ($params['userids'] as $id) {
404             \core_message\api::remove_contact($params['userid'], $id);
405         }
407         return null;
408     }
410     /**
411      * Delete contacts return description.
412      *
413      * @return external_description
414      * @since Moodle 2.5
415      */
416     public static function delete_contacts_returns() {
417         return null;
418     }
420     /**
421      * Mute conversations parameters description.
422      *
423      * @return external_function_parameters
424      */
425     public static function mute_conversations_parameters() {
426         return new external_function_parameters(
427             [
428                 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
429                 'conversationids' => new external_multiple_structure(
430                     new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
431                 ),
432             ]
433         );
434     }
436     /**
437      * Mutes conversations.
438      *
439      * @param int $userid The id of the user who is blocking
440      * @param array $conversationids The list of conversations being muted
441      * @return external_description
442      */
443     public static function mute_conversations(int $userid, array $conversationids) {
444         global $CFG, $USER;
446         // Check if messaging is enabled.
447         if (empty($CFG->messaging)) {
448             throw new moodle_exception('disabled', 'message');
449         }
451         // Validate context.
452         $context = context_system::instance();
453         self::validate_context($context);
455         $params = ['userid' => $userid, 'conversationids' => $conversationids];
456         $params = self::validate_parameters(self::mute_conversations_parameters(), $params);
458         $capability = 'moodle/site:manageallmessaging';
459         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
460             throw new required_capability_exception($context, $capability, 'nopermissions', '');
461         }
463         foreach ($params['conversationids'] as $conversationid) {
464             if (!\core_message\api::is_conversation_muted($params['userid'], $conversationid)) {
465                 \core_message\api::mute_conversation($params['userid'], $conversationid);
466             }
467         }
469         return [];
470     }
472     /**
473      * Mute conversations return description.
474      *
475      * @return external_description
476      */
477     public static function mute_conversations_returns() {
478         return new external_warnings();
479     }
481     /**
482      * Unmute conversations parameters description.
483      *
484      * @return external_function_parameters
485      */
486     public static function unmute_conversations_parameters() {
487         return new external_function_parameters(
488             [
489                 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
490                 'conversationids' => new external_multiple_structure(
491                     new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
492                 ),
493             ]
494         );
495     }
497     /**
498      * Unmute conversations.
499      *
500      * @param int $userid The id of the user who is unblocking
501      * @param array $conversationids The list of conversations being muted
502      */
503     public static function unmute_conversations(int $userid, array $conversationids) {
504         global $CFG, $USER;
506         // Check if messaging is enabled.
507         if (empty($CFG->messaging)) {
508             throw new moodle_exception('disabled', 'message');
509         }
511         // Validate context.
512         $context = context_system::instance();
513         self::validate_context($context);
515         $params = ['userid' => $userid, 'conversationids' => $conversationids];
516         $params = self::validate_parameters(self::unmute_conversations_parameters(), $params);
518         $capability = 'moodle/site:manageallmessaging';
519         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
520             throw new required_capability_exception($context, $capability, 'nopermissions', '');
521         }
523         foreach ($params['conversationids'] as $conversationid) {
524             \core_message\api::unmute_conversation($params['userid'], $conversationid);
525         }
527         return [];
528     }
530     /**
531      * Unmute conversations return description.
532      *
533      * @return external_description
534      */
535     public static function unmute_conversations_returns() {
536         return new external_warnings();
537     }
539     /**
540      * Block user parameters description.
541      *
542      * @return external_function_parameters
543      */
544     public static function block_user_parameters() {
545         return new external_function_parameters(
546             [
547                 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
548                 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
549             ]
550         );
551     }
553     /**
554      * Blocks a user.
555      *
556      * @param int $userid The id of the user who is blocking
557      * @param int $blockeduserid The id of the user being blocked
558      * @return external_description
559      */
560     public static function block_user(int $userid, int $blockeduserid) {
561         global $CFG, $USER;
563         // Check if messaging is enabled.
564         if (empty($CFG->messaging)) {
565             throw new moodle_exception('disabled', 'message');
566         }
568         // Validate context.
569         $context = context_system::instance();
570         self::validate_context($context);
572         $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
573         $params = self::validate_parameters(self::block_user_parameters(), $params);
575         $capability = 'moodle/site:manageallmessaging';
576         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
577             throw new required_capability_exception($context, $capability, 'nopermissions', '');
578         }
580         if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
581             \core_message\api::block_user($params['userid'], $params['blockeduserid']);
582         }
584         return [];
585     }
587     /**
588      * Block user return description.
589      *
590      * @return external_description
591      */
592     public static function block_user_returns() {
593         return new external_warnings();
594     }
596     /**
597      * Unblock user parameters description.
598      *
599      * @return external_function_parameters
600      */
601     public static function unblock_user_parameters() {
602         return new external_function_parameters(
603             [
604                 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
605                 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
606             ]
607         );
608     }
610     /**
611      * Unblock user.
612      *
613      * @param int $userid The id of the user who is unblocking
614      * @param int $unblockeduserid The id of the user being unblocked
615      */
616     public static function unblock_user(int $userid, int $unblockeduserid) {
617         global $CFG, $USER;
619         // Check if messaging is enabled.
620         if (empty($CFG->messaging)) {
621             throw new moodle_exception('disabled', 'message');
622         }
624         // Validate context.
625         $context = context_system::instance();
626         self::validate_context($context);
628         $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
629         $params = self::validate_parameters(self::unblock_user_parameters(), $params);
631         $capability = 'moodle/site:manageallmessaging';
632         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
633             throw new required_capability_exception($context, $capability, 'nopermissions', '');
634         }
636         \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
638         return [];
639     }
641     /**
642      * Unblock user return description.
643      *
644      * @return external_description
645      */
646     public static function unblock_user_returns() {
647         return new external_warnings();
648     }
650     /**
651      * Block contacts parameters description.
652      *
653      * @deprecated since Moodle 3.6
654      * @return external_function_parameters
655      * @since Moodle 2.5
656      */
657     public static function block_contacts_parameters() {
658         return new external_function_parameters(
659             array(
660                 'userids' => new external_multiple_structure(
661                     new external_value(PARAM_INT, 'User ID'),
662                     'List of user IDs'
663                 ),
664                 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
665                     current user', VALUE_DEFAULT, 0)
666             )
667         );
668     }
670     /**
671      * Block contacts.
672      *
673      * @deprecated since Moodle 3.6
674      * @param array $userids array of user IDs.
675      * @param int $userid The id of the user we are blocking the contacts for
676      * @return external_description
677      * @since Moodle 2.5
678      */
679     public static function block_contacts($userids, $userid = 0) {
680         global $CFG, $USER;
682         // Check if messaging is enabled.
683         if (empty($CFG->messaging)) {
684             throw new moodle_exception('disabled', 'message');
685         }
687         if (empty($userid)) {
688             $userid = $USER->id;
689         }
691         // Validate context.
692         $context = context_system::instance();
693         self::validate_context($context);
695         $params = array('userids' => $userids, 'userid' => $userid);
696         $params = self::validate_parameters(self::block_contacts_parameters(), $params);
698         $capability = 'moodle/site:manageallmessaging';
699         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
700             throw new required_capability_exception($context, $capability, 'nopermissions', '');
701         }
703         $warnings = array();
704         foreach ($params['userids'] as $id) {
705             if (!message_block_contact($id, $params['userid'])) {
706                 $warnings[] = array(
707                     'item' => 'user',
708                     'itemid' => $id,
709                     'warningcode' => 'contactnotblocked',
710                     'message' => 'The contact could not be blocked'
711                 );
712             }
713         }
714         return $warnings;
715     }
717     /**
718      * Block contacts return description.
719      *
720      * @deprecated since Moodle 3.6
721      * @return external_description
722      * @since Moodle 2.5
723      */
724     public static function block_contacts_returns() {
725         return new external_warnings();
726     }
728     /**
729      * Marking the method as deprecated.
730      *
731      * @return bool
732      */
733     public static function block_contacts_is_deprecated() {
734         return true;
735     }
737     /**
738      * Unblock contacts parameters description.
739      *
740      * @deprecated since Moodle 3.6
741      * @return external_function_parameters
742      * @since Moodle 2.5
743      */
744     public static function unblock_contacts_parameters() {
745         return new external_function_parameters(
746             array(
747                 'userids' => new external_multiple_structure(
748                     new external_value(PARAM_INT, 'User ID'),
749                     'List of user IDs'
750                 ),
751                 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
752                     current user', VALUE_DEFAULT, 0)
753             )
754         );
755     }
757     /**
758      * Unblock contacts.
759      *
760      * @param array $userids array of user IDs.
761      * @param int $userid The id of the user we are unblocking the contacts for
762      * @return null
763      * @since Moodle 2.5
764      */
765     public static function unblock_contacts($userids, $userid = 0) {
766         global $CFG, $USER;
768         // Check if messaging is enabled.
769         if (empty($CFG->messaging)) {
770             throw new moodle_exception('disabled', 'message');
771         }
773         if (empty($userid)) {
774             $userid = $USER->id;
775         }
777         // Validate context.
778         $context = context_system::instance();
779         self::validate_context($context);
781         $params = array('userids' => $userids, 'userid' => $userid);
782         $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
784         $capability = 'moodle/site:manageallmessaging';
785         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
786             throw new required_capability_exception($context, $capability, 'nopermissions', '');
787         }
789         foreach ($params['userids'] as $id) {
790             message_unblock_contact($id, $params['userid']);
791         }
793         return null;
794     }
796     /**
797      * Unblock contacts return description.
798      *
799      * @deprecated since Moodle 3.6
800      * @return external_description
801      * @since Moodle 2.5
802      */
803     public static function unblock_contacts_returns() {
804         return null;
805     }
807     /**
808      * Marking the method as deprecated.
809      *
810      * @return bool
811      */
812     public static function unblock_contacts_is_deprecated() {
813         return true;
814     }
816     /**
817      * Returns contact requests parameters description.
818      *
819      * @return external_function_parameters
820      */
821     public static function get_contact_requests_parameters() {
822         return new external_function_parameters(
823             [
824                 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
825                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
826                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
827             ]
828         );
829     }
831     /**
832      * Handles returning the contact requests for a user.
833      *
834      * This also includes the user data necessary to display information
835      * about the user.
836      *
837      * It will not include blocked users.
838      *
839      * @param int $userid The id of the user we want to get the contact requests for
840      * @param int $limitfrom
841      * @param int $limitnum
842      */
843     public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
844         global $CFG, $USER;
846         // Check if messaging is enabled.
847         if (empty($CFG->messaging)) {
848             throw new moodle_exception('disabled', 'message');
849         }
851         // Validate context.
852         $context = context_system::instance();
853         self::validate_context($context);
855         $params = [
856             'userid' => $userid,
857             'limitfrom' => $limitfrom,
858             'limitnum' => $limitnum
859         ];
860         $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
862         $capability = 'moodle/site:manageallmessaging';
863         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
864             throw new required_capability_exception($context, $capability, 'nopermissions', '');
865         }
867         return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
868     }
870     /**
871      * Returns the contact requests return description.
872      *
873      * @return external_description
874      */
875     public static function get_contact_requests_returns() {
876         return new external_multiple_structure(
877             self::get_conversation_member_structure()
878         );
879     }
881     /**
882      * Returns the number of contact requests the user has received parameters description.
883      *
884      * @return external_function_parameters
885      */
886     public static function get_received_contact_requests_count_parameters() {
887         return new external_function_parameters(
888             array(
889                 'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' .
890                     'received contact requests for', VALUE_REQUIRED),
891             )
892         );
893     }
895     /**
896      * Returns the number of contact requests the user has received.
897      *
898      * @param int $userid The ID of the user we want to return the number of received contact requests for
899      * @return external_value
900      */
901     public static function get_received_contact_requests_count(int $userid) {
902         global $CFG, $USER;
904         // Check if messaging is enabled.
905         if (empty($CFG->messaging)) {
906             throw new moodle_exception('disabled', 'message');
907         }
909         // Validate context.
910         $context = context_system::instance();
911         self::validate_context($context);
913         $params = [
914             'userid' => $userid,
915         ];
916         $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params);
918         $capability = 'moodle/site:manageallmessaging';
919         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
920             throw new required_capability_exception($context, $capability, 'nopermissions', '');
921         }
923         return \core_message\api::get_received_contact_requests_count($params['userid']);
924     }
926     /**
927      * Returns the number of contact requests the user has received return description.
928      *
929      * @return external_value
930      */
931     public static function get_received_contact_requests_count_returns() {
932         return new external_value(PARAM_INT, 'The number of received contact requests');
933     }
935     /**
936      * Returns get conversation members parameters description.
937      *
938      * @return external_function_parameters
939      */
940     public static function get_conversation_members_parameters() {
941         return new external_function_parameters(
942             [
943                 'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
944                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
945                 'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
946                     VALUE_DEFAULT, false),
947                 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?',
948                     VALUE_DEFAULT, false),
949                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
950                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
951             ]
952         );
953     }
955     /**
956      * Returns a list of conversation members.
957      *
958      * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
959      * @param int $conversationid The id of the conversation
960      * @param bool $includecontactrequests Do we want to include contact requests with this data?
961      * @param bool $includeprivacyinfo Do we want to include privacy info?
962      * @param int $limitfrom
963      * @param int $limitnum
964      * @return array
965      */
966     public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
967                                                     bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) {
968         global $CFG, $USER;
970         // Check if messaging is enabled.
971         if (empty($CFG->messaging)) {
972             throw new moodle_exception('disabled', 'message');
973         }
975         // Validate context.
976         $context = context_system::instance();
977         self::validate_context($context);
979         $params = [
980             'userid' => $userid,
981             'conversationid' => $conversationid,
982             'includecontactrequests' => $includecontactrequests,
983             'includeprivacyinfo' => $includeprivacyinfo,
984             'limitfrom' => $limitfrom,
985             'limitnum' => $limitnum
986         ];
987         $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
989         $capability = 'moodle/site:manageallmessaging';
990         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
991             throw new required_capability_exception($context, $capability, 'nopermissions', '');
992         }
994         // The user needs to be a part of the conversation before querying who the members are.
995         if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
996             throw new moodle_exception('You are not a member of this conversation.');
997         }
999         return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
1000             $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']);
1001     }
1003     /**
1004      * Returns the get conversation members return description.
1005      *
1006      * @return external_description
1007      */
1008     public static function get_conversation_members_returns() {
1009         return new external_multiple_structure(
1010             self::get_conversation_member_structure()
1011         );
1012     }
1014     /**
1015      * Creates a contact request parameters description.
1016      *
1017      * @return external_function_parameters
1018      */
1019     public static function create_contact_request_parameters() {
1020         return new external_function_parameters(
1021             [
1022                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
1023                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
1024             ]
1025         );
1026     }
1028     /**
1029      * Creates a contact request.
1030      *
1031      * @param int $userid The id of the user who is creating the contact request
1032      * @param int $requesteduserid The id of the user being requested
1033      */
1034     public static function create_contact_request(int $userid, int $requesteduserid) {
1035         global $CFG, $USER;
1037         // Check if messaging is enabled.
1038         if (empty($CFG->messaging)) {
1039             throw new moodle_exception('disabled', 'message');
1040         }
1042         // Validate context.
1043         $context = context_system::instance();
1044         self::validate_context($context);
1046         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
1047         $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
1049         $capability = 'moodle/site:manageallmessaging';
1050         if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
1051             throw new required_capability_exception($context, $capability, 'nopermissions', '');
1052         }
1054         $result = [
1055             'warnings' => []
1056         ];
1058         if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
1059             $result['warnings'][] = [
1060                 'item' => 'user',
1061                 'itemid' => $params['requesteduserid'],
1062                 'warningcode' => 'cannotcreatecontactrequest',
1063                 'message' => 'You are unable to create a contact request for this user'
1064             ];
1065         } else {
1066             if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
1067                 // There should only ever be one but just in case there are multiple then we can return the first.
1068                 $result['request'] = array_shift($requests);
1069             } else {
1070                 $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
1071             }
1072         }
1074         return $result;
1075     }
1077     /**
1078      * Creates a contact request return description.
1079      *
1080      * @return external_description
1081      */
1082     public static function create_contact_request_returns() {
1083         return new external_single_structure(
1084             array(
1085                 'request' => new external_single_structure(
1086                     array(
1087                         'id' => new external_value(PARAM_INT, 'Message id'),
1088                         'userid' => new external_value(PARAM_INT, 'User from id'),
1089                         'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
1090                         'timecreated' => new external_value(PARAM_INT, 'Time created'),
1091                     ),
1092                     'request record',
1093                     VALUE_OPTIONAL
1094                 ),
1095                 'warnings' => new external_warnings()
1096             )
1097         );
1098     }
1100     /**
1101      * Confirm a contact request parameters description.
1102      *
1103      * @return external_function_parameters
1104      */
1105     public static function confirm_contact_request_parameters() {
1106         return new external_function_parameters(
1107             [
1108                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
1109                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
1110             ]
1111         );
1112     }
1114     /**
1115      * Confirm a contact request.
1116      *
1117      * @param int $userid The id of the user who is creating the contact request
1118      * @param int $requesteduserid The id of the user being requested
1119      */
1120     public static function confirm_contact_request(int $userid, int $requesteduserid) {
1121         global $CFG, $USER;
1123         // Check if messaging is enabled.
1124         if (empty($CFG->messaging)) {
1125             throw new moodle_exception('disabled', 'message');
1126         }
1128         // Validate context.
1129         $context = context_system::instance();
1130         self::validate_context($context);
1132         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
1133         $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
1135         $capability = 'moodle/site:manageallmessaging';
1136         if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
1137             throw new required_capability_exception($context, $capability, 'nopermissions', '');
1138         }
1140         \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
1142         return [];
1143     }
1145     /**
1146      * Confirm a contact request return description.
1147      *
1148      * @return external_description
1149      */
1150     public static function confirm_contact_request_returns() {
1151         return new external_warnings();
1152     }
1154     /**
1155      * Declines a contact request parameters description.
1156      *
1157      * @return external_function_parameters
1158      */
1159     public static function decline_contact_request_parameters() {
1160         return new external_function_parameters(
1161             [
1162                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
1163                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
1164             ]
1165         );
1166     }
1168     /**
1169      * Declines a contact request.
1170      *
1171      * @param int $userid The id of the user who is creating the contact request
1172      * @param int $requesteduserid The id of the user being requested
1173      */
1174     public static function decline_contact_request(int $userid, int $requesteduserid) {
1175         global $CFG, $USER;
1177         // Check if messaging is enabled.
1178         if (empty($CFG->messaging)) {
1179             throw new moodle_exception('disabled', 'message');
1180         }
1182         // Validate context.
1183         $context = context_system::instance();
1184         self::validate_context($context);
1186         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
1187         $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
1189         $capability = 'moodle/site:manageallmessaging';
1190         if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
1191             throw new required_capability_exception($context, $capability, 'nopermissions', '');
1192         }
1194         \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
1196         return [];
1197     }
1199     /**
1200      * Declines a contact request return description.
1201      *
1202      * @return external_description
1203      */
1204     public static function decline_contact_request_returns() {
1205         return new external_warnings();
1206     }
1208     /**
1209      * Return the structure of a message area contact.
1210      *
1211      * @return external_single_structure
1212      * @since Moodle 3.2
1213      */
1214     private static function get_messagearea_contact_structure() {
1215         return new external_single_structure(
1216             array(
1217                 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
1218                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1219                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1220                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1221                 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
1222                 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
1223                 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
1224                 'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null),
1225                 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
1226                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1227                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1228                 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
1229                 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1230                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1231                     VALUE_DEFAULT, null),
1232                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null),
1233             )
1234         );
1235     }
1237     /**
1238      * Return the structure of a conversation.
1239      *
1240      * @return external_single_structure
1241      * @since Moodle 3.6
1242      */
1243     private static function get_conversation_structure() {
1244         return new external_single_structure(
1245             array(
1246                 'id' => new external_value(PARAM_INT, 'The conversation id'),
1247                 'name' => new external_value(PARAM_TEXT, 'The conversation name, if set', VALUE_DEFAULT, null),
1248                 'subname' => new external_value(PARAM_TEXT, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1249                 'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1250                 'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group,3=self)'),
1251                 'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1252                 'ismuted' => new external_value(PARAM_BOOL, 'If the user muted this conversation'),
1253                 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this conversation as a favourite'),
1254                 'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1255                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1256                     VALUE_DEFAULT, null),
1257                 'members' => new external_multiple_structure(
1258                     self::get_conversation_member_structure()
1259                 ),
1260                 'messages' => new external_multiple_structure(
1261                     self::get_conversation_message_structure()
1262                 ),
1263             )
1264         );
1265     }
1267     /**
1268      * Return the structure of a conversation member.
1269      *
1270      * @return external_single_structure
1271      * @since Moodle 3.6
1272      */
1273     private static function get_conversation_member_structure() {
1274         $result = [
1275             'id' => new external_value(PARAM_INT, 'The user id'),
1276             'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1277             'profileurl' => new external_value(PARAM_URL, 'The link to the user\'s profile page'),
1278             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1279             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1280             'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1281             'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1282             'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1283             'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1284             'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1285             'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1286             'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1287         ];
1289         $result['contactrequests'] = new external_multiple_structure(
1290             new external_single_structure(
1291                 [
1292                     'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1293                     'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1294                     'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1295                     'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1296                 ]
1297             ), 'The contact requests', VALUE_OPTIONAL
1298         );
1300         $result['conversations'] = new external_multiple_structure(new external_single_structure(
1301             array(
1302                 'id' => new external_value(PARAM_INT, 'Conversations id'),
1303                 'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1304                 'name' => new external_value(PARAM_TEXT, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1305                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1306             ), 'information about conversation', VALUE_OPTIONAL),
1307             'Conversations between users', VALUE_OPTIONAL
1308         );
1310         return new external_single_structure(
1311             $result
1312         );
1313     }
1315     /**
1316      * Return the structure of a message area message.
1317      *
1318      * @return external_single_structure
1319      * @since Moodle 3.6
1320      */
1321     private static function get_conversation_message_structure() {
1322         return new external_single_structure(
1323             array(
1324                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1325                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1326                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1327                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1328             )
1329         );
1330     }
1332     /**
1333      * Return the structure of a message area message.
1334      *
1335      * @return external_single_structure
1336      * @since Moodle 3.2
1337      */
1338     private static function get_messagearea_message_structure() {
1339         return new external_single_structure(
1340             array(
1341                 'id' => new external_value(PARAM_INT, 'The id of the message'),
1342                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1343                 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
1344                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
1345                 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
1346                 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
1347                 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
1348                 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
1349                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1350                 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
1351             )
1352         );
1353     }
1355     /**
1356      * Get messagearea search users in course parameters.
1357      *
1358      * @deprecated since 3.6
1359      *
1360      * @return external_function_parameters
1361      * @since 3.2
1362      */
1363     public static function data_for_messagearea_search_users_in_course_parameters() {
1364         return new external_function_parameters(
1365             array(
1366                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1367                 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
1368                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1369                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1370                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1371             )
1372         );
1373     }
1375     /**
1376      * Get messagearea search users in course results.
1377      *
1378      * @deprecated since 3.6
1379      *
1380      * @param int $userid The id of the user who is performing the search
1381      * @param int $courseid The id of the course
1382      * @param string $search The string being searched
1383      * @param int $limitfrom
1384      * @param int $limitnum
1385      * @return stdClass
1386      * @throws moodle_exception
1387      * @since 3.2
1388      */
1389     public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
1390                                                                        $limitnum = 0) {
1391         global $CFG, $PAGE, $USER;
1393         // Check if messaging is enabled.
1394         if (empty($CFG->messaging)) {
1395             throw new moodle_exception('disabled', 'message');
1396         }
1398         $systemcontext = context_system::instance();
1400         $params = array(
1401             'userid' => $userid,
1402             'courseid' => $courseid,
1403             'search' => $search,
1404             'limitfrom' => $limitfrom,
1405             'limitnum' => $limitnum
1406         );
1407         $params = self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
1408         self::validate_context($systemcontext);
1410         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1411             throw new moodle_exception('You do not have permission to perform this action.');
1412         }
1414         $users = \core_message\api::search_users_in_course(
1415             $params['userid'],
1416             $params['courseid'],
1417             $params['search'],
1418             $params['limitfrom'],
1419             $params['limitnum']
1420         );
1421         $results = new \core_message\output\messagearea\user_search_results($users);
1423         $renderer = $PAGE->get_renderer('core_message');
1424         return $results->export_for_template($renderer);
1425     }
1427     /**
1428      * Get messagearea search users in course returns.
1429      *
1430      * @deprecated since 3.6
1431      *
1432      * @return external_single_structure
1433      * @since 3.2
1434      */
1435     public static function data_for_messagearea_search_users_in_course_returns() {
1436         return new external_single_structure(
1437             array(
1438                 'contacts' => new external_multiple_structure(
1439                     self::get_messagearea_contact_structure()
1440                 ),
1441             )
1442         );
1443     }
1445     /**
1446      * Marking the method as deprecated.
1447      *
1448      * @return bool
1449      */
1450     public static function data_for_messagearea_search_users_in_course_is_deprecated() {
1451         return true;
1452     }
1454     /**
1455      * Get messagearea search users parameters.
1456      *
1457      * @deprecated since 3.6
1458      *
1459      * @return external_function_parameters
1460      * @since 3.2
1461      */
1462     public static function data_for_messagearea_search_users_parameters() {
1463         return new external_function_parameters(
1464             array(
1465                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1466                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1467                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1468             )
1469         );
1470     }
1472     /**
1473      * Get messagearea search users results.
1474      *
1475      * @deprecated since 3.6
1476      *
1477      * @param int $userid The id of the user who is performing the search
1478      * @param string $search The string being searched
1479      * @param int $limitnum
1480      * @return stdClass
1481      * @throws moodle_exception
1482      * @since 3.2
1483      */
1484     public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1485         global $CFG, $PAGE, $USER;
1487         // Check if messaging is enabled.
1488         if (empty($CFG->messaging)) {
1489             throw new moodle_exception('disabled', 'message');
1490         }
1492         $systemcontext = context_system::instance();
1494         $params = array(
1495             'userid' => $userid,
1496             'search' => $search,
1497             'limitnum' => $limitnum
1498         );
1499         $params = self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1500         self::validate_context($systemcontext);
1502         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1503             throw new moodle_exception('You do not have permission to perform this action.');
1504         }
1506         list($contacts, $courses, $noncontacts) = \core_message\api::search_users(
1507             $params['userid'],
1508             $params['search'],
1509             $params['limitnum']
1510         );
1512         $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1514         $renderer = $PAGE->get_renderer('core_message');
1515         return $search->export_for_template($renderer);
1516     }
1518     /**
1519      * Get messagearea search users returns.
1520      *
1521      * @deprecated since 3.6
1522      *
1523      * @return external_single_structure
1524      * @since 3.2
1525      */
1526     public static function data_for_messagearea_search_users_returns() {
1527         return new external_single_structure(
1528             array(
1529                 'contacts' => new external_multiple_structure(
1530                     self::get_messagearea_contact_structure()
1531                 ),
1532                 'courses' => new external_multiple_structure(
1533                     new external_single_structure(
1534                         array(
1535                             'id' => new external_value(PARAM_INT, 'The course id'),
1536                             'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1537                             'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1538                         )
1539                     )
1540                 ),
1541                 'noncontacts' => new external_multiple_structure(
1542                     self::get_messagearea_contact_structure()
1543                 )
1544             )
1545         );
1546     }
1548     /**
1549      * Marking the method as deprecated.
1550      *
1551      * @return bool
1552      */
1553     public static function data_for_messagearea_search_users_is_deprecated() {
1554         return true;
1555     }
1557     /**
1558      * Get messagearea message search users parameters.
1559      *
1560      * @return external_function_parameters
1561      * @since 3.6
1562      */
1563     public static function message_search_users_parameters() {
1564         return new external_function_parameters(
1565             array(
1566                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1567                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1568                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1569                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1570             )
1571         );
1572     }
1574     /**
1575      * Get search users results.
1576      *
1577      * @param int $userid The id of the user who is performing the search
1578      * @param string $search The string being searched
1579      * @param int $limitfrom
1580      * @param int $limitnum
1581      * @return array
1582      * @throws moodle_exception
1583      * @since 3.6
1584      */
1585     public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1586         global $USER;
1588         $systemcontext = context_system::instance();
1590         $params = array(
1591             'userid' => $userid,
1592             'search' => $search,
1593             'limitfrom' => $limitfrom,
1594             'limitnum' => $limitnum
1595         );
1596         $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1597         self::validate_context($systemcontext);
1599         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1600             throw new moodle_exception('You do not have permission to perform this action.');
1601         }
1603         list($contacts, $noncontacts) = \core_message\api::message_search_users(
1604             $params['userid'],
1605             $params['search'],
1606             $params['limitfrom'],
1607             $params['limitnum']);
1609         return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1610     }
1612     /**
1613      * Get messagearea message search users returns.
1614      *
1615      * @return external_single_structure
1616      * @since 3.2
1617      */
1618     public static function message_search_users_returns() {
1619         return new external_single_structure(
1620             array(
1621                 'contacts' => new external_multiple_structure(
1622                     self::get_conversation_member_structure()
1623                 ),
1624                 'noncontacts' => new external_multiple_structure(
1625                     self::get_conversation_member_structure()
1626                 )
1627             )
1628         );
1629     }
1631     /**
1632      * Get messagearea search messages parameters.
1633      *
1634      * @return external_function_parameters
1635      * @since 3.2
1636      */
1637     public static function data_for_messagearea_search_messages_parameters() {
1638         return new external_function_parameters(
1639             array(
1640                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1641                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1642                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1643                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1644             )
1645         );
1646     }
1648     /**
1649      * Get messagearea search messages results.
1650      *
1651      * @param int $userid The id of the user who is performing the search
1652      * @param string $search The string being searched
1653      * @param int $limitfrom
1654      * @param int $limitnum
1655      * @return stdClass
1656      * @throws moodle_exception
1657      * @since 3.2
1658      */
1659     public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1660         global $CFG, $USER;
1662         // Check if messaging is enabled.
1663         if (empty($CFG->messaging)) {
1664             throw new moodle_exception('disabled', 'message');
1665         }
1667         $systemcontext = context_system::instance();
1669         $params = array(
1670             'userid' => $userid,
1671             'search' => $search,
1672             'limitfrom' => $limitfrom,
1673             'limitnum' => $limitnum
1675         );
1676         $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1677         self::validate_context($systemcontext);
1679         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1680             throw new moodle_exception('You do not have permission to perform this action.');
1681         }
1683         $messages = \core_message\api::search_messages(
1684             $params['userid'],
1685             $params['search'],
1686             $params['limitfrom'],
1687             $params['limitnum']
1688         );
1690         $data = new \stdClass();
1691         $data->contacts = [];
1692         foreach ($messages as $message) {
1693             $contact = new \stdClass();
1694             $contact->userid = $message->userid;
1695             $contact->fullname = $message->fullname;
1696             $contact->profileimageurl = $message->profileimageurl;
1697             $contact->profileimageurlsmall = $message->profileimageurlsmall;
1698             $contact->messageid = $message->messageid;
1699             $contact->ismessaging = $message->ismessaging;
1700             $contact->sentfromcurrentuser = false;
1701             if ($message->lastmessage) {
1702                 if ($message->userid !== $message->useridfrom) {
1703                     $contact->sentfromcurrentuser = true;
1704                 }
1705                 $contact->lastmessage = shorten_text($message->lastmessage, 60);
1706             } else {
1707                 $contact->lastmessage = null;
1708             }
1709             $contact->lastmessagedate = $message->lastmessagedate;
1710             $contact->showonlinestatus = is_null($message->isonline) ? false : true;
1711             $contact->isonline = $message->isonline;
1712             $contact->isblocked = $message->isblocked;
1713             $contact->isread = $message->isread;
1714             $contact->unreadcount = $message->unreadcount;
1715             $contact->conversationid = $message->conversationid;
1717             $data->contacts[] = $contact;
1718         }
1720         return $data;
1721     }
1723     /**
1724      * Get messagearea search messages returns.
1725      *
1726      * @return external_single_structure
1727      * @since 3.2
1728      */
1729     public static function data_for_messagearea_search_messages_returns() {
1730         return new external_single_structure(
1731             array(
1732                 'contacts' => new external_multiple_structure(
1733                     self::get_messagearea_contact_structure()
1734                 )
1735             )
1736         );
1737     }
1739     /**
1740      * Get conversations parameters.
1741      *
1742      * @return external_function_parameters
1743      * @since 3.6
1744      */
1745     public static function get_conversations_parameters() {
1746         return new external_function_parameters(
1747             array(
1748                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1749                 'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1750                 'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1751                 'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1752                 'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1753                 conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1754                     VALUE_DEFAULT, null),
1755                 'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private
1756                     conversations (false) when private conversations are requested.',
1757                     VALUE_DEFAULT, false),
1758             )
1759         );
1760     }
1762     /**
1763      * Get the list of conversations for the user.
1764      *
1765      * @param int $userid The id of the user who is performing the search
1766      * @param int $limitfrom
1767      * @param int $limitnum
1768      * @param int|null $type
1769      * @param bool|null $favourites
1770      * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false)
1771      *             when private conversations are requested.
1772      * @return stdClass
1773      * @throws \moodle_exception if the messaging feature is disabled on the site.
1774      * @since 3.2
1775      */
1776     public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null,
1777             bool $mergeself = false) {
1778         global $CFG, $USER;
1780         // All the standard BL checks.
1781         if (empty($CFG->messaging)) {
1782             throw new moodle_exception('disabled', 'message');
1783         }
1785         $params = array(
1786             'userid' => $userid,
1787             'limitfrom' => $limitfrom,
1788             'limitnum' => $limitnum,
1789             'type' => $type,
1790             'favourites' => $favourites,
1791             'mergeself' => $mergeself
1792         );
1793         $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1795         $systemcontext = context_system::instance();
1796         self::validate_context($systemcontext);
1798         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1799             throw new moodle_exception('You do not have permission to perform this action.');
1800         }
1802         $conversations = \core_message\api::get_conversations(
1803             $params['userid'],
1804             $params['limitfrom'],
1805             $params['limitnum'],
1806             $params['type'],
1807             $params['favourites'],
1808             $params['mergeself']
1809         );
1811         return (object) ['conversations' => $conversations];
1812     }
1814     /**
1815      * Get conversations returns.
1816      *
1817      * @return external_single_structure
1818      * @since 3.6
1819      */
1820     public static function get_conversations_returns() {
1821         return new external_single_structure(
1822             [
1823                 'conversations' => new external_multiple_structure(
1824                     self::get_conversation_structure(true)
1825                 )
1826             ]
1827         );
1828     }
1830     /**
1831      * Get conversation parameters.
1832      *
1833      * @return external_function_parameters
1834      */
1835     public static function get_conversation_parameters() {
1836         return new external_function_parameters(
1837             array(
1838                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1839                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1840                 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1841                 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1842                 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1843                 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1844                 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1845                 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1846                 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1847             )
1848         );
1849     }
1851     /**
1852      * Get a single conversation.
1853      *
1854      * @param int $userid The user id to get the conversation for
1855      * @param int $conversationid The id of the conversation to fetch
1856      * @param bool $includecontactrequests Should contact requests be included between members
1857      * @param bool $includeprivacyinfo Should privacy info be included between members
1858      * @param int $memberlimit Limit number of members to load
1859      * @param int $memberoffset Offset members by this amount
1860      * @param int $messagelimit Limit number of messages to load
1861      * @param int $messageoffset Offset the messages
1862      * @param bool $newestmessagesfirst Order messages by newest first
1863      * @return stdClass
1864      * @throws \moodle_exception if the messaging feature is disabled on the site.
1865      */
1866     public static function get_conversation(
1867         int $userid,
1868         int $conversationid,
1869         bool $includecontactrequests = false,
1870         bool $includeprivacyinfo = false,
1871         int $memberlimit = 0,
1872         int $memberoffset = 0,
1873         int $messagelimit = 0,
1874         int $messageoffset = 0,
1875         bool $newestmessagesfirst = true
1876     ) {
1877         global $CFG, $DB, $USER;
1879         // All the standard BL checks.
1880         if (empty($CFG->messaging)) {
1881             throw new moodle_exception('disabled', 'message');
1882         }
1884         $params = [
1885             'userid' => $userid,
1886             'conversationid' => $conversationid,
1887             'includecontactrequests' => $includecontactrequests,
1888             'includeprivacyinfo' => $includeprivacyinfo,
1889             'memberlimit' => $memberlimit,
1890             'memberoffset' => $memberoffset,
1891             'messagelimit' => $messagelimit,
1892             'messageoffset' => $messageoffset,
1893             'newestmessagesfirst' => $newestmessagesfirst
1894         ];
1895         self::validate_parameters(self::get_conversation_parameters(), $params);
1897         $systemcontext = context_system::instance();
1898         self::validate_context($systemcontext);
1900         $conversation = \core_message\api::get_conversation(
1901             $params['userid'],
1902             $params['conversationid'],
1903             $params['includecontactrequests'],
1904             $params['includeprivacyinfo'],
1905             $params['memberlimit'],
1906             $params['memberoffset'],
1907             $params['messagelimit'],
1908             $params['messageoffset'],
1909             $params['newestmessagesfirst']
1910         );
1912         if ($conversation) {
1913             return $conversation;
1914         } else {
1915             // We have to throw an exception here because the external functions annoyingly
1916             // don't accept null to be returned for a single structure.
1917             throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1918         }
1919     }
1921     /**
1922      * Get conversation returns.
1923      *
1924      * @return external_single_structure
1925      */
1926     public static function get_conversation_returns() {
1927         return self::get_conversation_structure();
1928     }
1930     /**
1931      * Get conversation parameters.
1932      *
1933      * @return external_function_parameters
1934      */
1935     public static function get_conversation_between_users_parameters() {
1936         return new external_function_parameters(
1937             array(
1938                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1939                 'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1940                 'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1941                 'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1942                 'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1943                 'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1944                 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1945                 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1946                 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1947             )
1948         );
1949     }
1951     /**
1952      * Get a single conversation between users.
1953      *
1954      * @param int $userid The user id to get the conversation for
1955      * @param int $otheruserid The other user id
1956      * @param bool $includecontactrequests Should contact requests be included between members
1957      * @param bool $includeprivacyinfo Should privacy info be included between members
1958      * @param int $memberlimit Limit number of members to load
1959      * @param int $memberoffset Offset members by this amount
1960      * @param int $messagelimit Limit number of messages to load
1961      * @param int $messageoffset Offset the messages
1962      * @param bool $newestmessagesfirst Order messages by newest first
1963      * @return stdClass
1964      * @throws \moodle_exception if the messaging feature is disabled on the site.
1965      */
1966     public static function get_conversation_between_users(
1967         int $userid,
1968         int $otheruserid,
1969         bool $includecontactrequests = false,
1970         bool $includeprivacyinfo = false,
1971         int $memberlimit = 0,
1972         int $memberoffset = 0,
1973         int $messagelimit = 0,
1974         int $messageoffset = 0,
1975         bool $newestmessagesfirst = true
1976     ) {
1977         global $CFG, $DB, $USER;
1979         // All the standard BL checks.
1980         if (empty($CFG->messaging)) {
1981             throw new moodle_exception('disabled', 'message');
1982         }
1984         $params = [
1985             'userid' => $userid,
1986             'otheruserid' => $otheruserid,
1987             'includecontactrequests' => $includecontactrequests,
1988             'includeprivacyinfo' => $includeprivacyinfo,
1989             'memberlimit' => $memberlimit,
1990             'memberoffset' => $memberoffset,
1991             'messagelimit' => $messagelimit,
1992             'messageoffset' => $messageoffset,
1993             'newestmessagesfirst' => $newestmessagesfirst
1994         ];
1995         self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
1997         $systemcontext = context_system::instance();
1998         self::validate_context($systemcontext);
2000         $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
2001         $conversation = null;
2003         if ($conversationid) {
2004             $conversation = \core_message\api::get_conversation(
2005                 $params['userid'],
2006                 $conversationid,
2007                 $params['includecontactrequests'],
2008                 $params['includeprivacyinfo'],
2009                 $params['memberlimit'],
2010                 $params['memberoffset'],
2011                 $params['messagelimit'],
2012                 $params['messageoffset'],
2013                 $params['newestmessagesfirst']
2014             );
2015         }
2017         if ($conversation) {
2018             return $conversation;
2019         } else {
2020             // We have to throw an exception here because the external functions annoyingly
2021             // don't accept null to be returned for a single structure.
2022             throw new \moodle_exception('errorconversationdoesnotexist', 'message');
2023         }
2024     }
2026     /**
2027      * Get conversation returns.
2028      *
2029      * @return external_single_structure
2030      */
2031     public static function get_conversation_between_users_returns() {
2032         return self::get_conversation_structure(true);
2033     }
2035     /**
2036      * Get self-conversation parameters.
2037      *
2038      * @return external_function_parameters
2039      */
2040     public static function get_self_conversation_parameters() {
2041         return new external_function_parameters(
2042             array(
2043                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'),
2044                 'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
2045                 'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
2046                 'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
2047             )
2048         );
2049     }
2051     /**
2052      * Get a single self-conversation.
2053      *
2054      * @param int $userid The user id to get the self-conversation for
2055      * @param int $messagelimit Limit number of messages to load
2056      * @param int $messageoffset Offset the messages
2057      * @param bool $newestmessagesfirst Order messages by newest first
2058      * @return stdClass
2059      * @throws \moodle_exception if the messaging feature is disabled on the site.
2060      * @since Moodle 3.7
2061      */
2062     public static function get_self_conversation(
2063         int $userid,
2064         int $messagelimit = 0,
2065         int $messageoffset = 0,
2066         bool $newestmessagesfirst = true
2067     ) {
2068         global $CFG;
2070         // All the standard BL checks.
2071         if (empty($CFG->messaging)) {
2072             throw new moodle_exception('disabled', 'message');
2073         }
2075         $params = [
2076             'userid' => $userid,
2077             'messagelimit' => $messagelimit,
2078             'messageoffset' => $messageoffset,
2079             'newestmessagesfirst' => $newestmessagesfirst
2080         ];
2081         self::validate_parameters(self::get_self_conversation_parameters(), $params);
2083         $systemcontext = context_system::instance();
2084         self::validate_context($systemcontext);
2086         $conversation = \core_message\api::get_self_conversation($params['userid']);
2088         if ($conversation) {
2089             $conversation = \core_message\api::get_conversation(
2090                 $params['userid'],
2091                 $conversation->id,
2092                 false,
2093                 false,
2094                 0,
2095                 0,
2096                 $params['messagelimit'],
2097                 $params['messageoffset'],
2098                 $params['newestmessagesfirst']
2099             );
2100         }
2102         if ($conversation) {
2103             return $conversation;
2104         } else {
2105             // We have to throw an exception here because the external functions annoyingly
2106             // don't accept null to be returned for a single structure.
2107             throw new \moodle_exception('errorconversationdoesnotexist', 'message');
2108         }
2109     }
2111     /**
2112      * Get conversation returns.
2113      *
2114      * @return external_single_structure
2115      */
2116     public static function get_self_conversation_returns() {
2117         return self::get_conversation_structure();
2118     }
2120     /**
2121      * The messagearea conversations parameters.
2122      *
2123      * @deprecated since 3.6
2124      * @return external_function_parameters
2125      * @since 3.2
2126      */
2127     public static function data_for_messagearea_conversations_parameters() {
2128         return new external_function_parameters(
2129             array(
2130                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
2131                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2132                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
2133             )
2134         );
2135     }
2137     /**
2138      * Get messagearea conversations.
2139      *
2140      * NOTE FOR FINAL DEPRECATION:
2141      * When removing this method, please also consider removal of get_conversations_legacy_formatter()
2142      * from the \core_message\helper class. This helper method was used solely to format the new get_conversations() return data
2143      * into the old format used here, and in message/index.php. If we no longer need either of these, then that method can be
2144      * removed.
2145      *
2146      * @deprecated since 3.6
2147      * @param int $userid The id of the user who we are viewing conversations for
2148      * @param int $limitfrom
2149      * @param int $limitnum
2150      * @return stdClass
2151      * @throws moodle_exception
2152      * @since 3.2
2153      */
2154     public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
2155         global $CFG, $PAGE, $USER;
2157         // Check if messaging is enabled.
2158         if (empty($CFG->messaging)) {
2159             throw new moodle_exception('disabled', 'message');
2160         }
2162         $systemcontext = context_system::instance();
2164         $params = array(
2165             'userid' => $userid,
2166             'limitfrom' => $limitfrom,
2167             'limitnum' => $limitnum
2168         );
2169         $params = self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
2170         self::validate_context($systemcontext);
2172         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2173             throw new moodle_exception('You do not have permission to perform this action.');
2174         }
2176         $conversations = \core_message\api::get_conversations($params['userid'], $params['limitfrom'], $params['limitnum']);
2178         // Format the conversations in the legacy style, as the get_conversations method has since been changed.
2179         $conversations = \core_message\helper::get_conversations_legacy_formatter($conversations);
2181         $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
2183         $renderer = $PAGE->get_renderer('core_message');
2184         return $conversations->export_for_template($renderer);
2185     }
2187     /**
2188      * The messagearea conversations return structure.
2189      *
2190      * @deprecated since 3.6
2191      * @return external_single_structure
2192      * @since 3.2
2193      */
2194     public static function data_for_messagearea_conversations_returns() {
2195         return new external_single_structure(
2196             array(
2197                 'contacts' => new external_multiple_structure(
2198                     self::get_messagearea_contact_structure()
2199                 )
2200             )
2201         );
2202     }
2204     /**
2205      * Marking the method as deprecated.
2206      *
2207      * @return bool
2208      */
2209     public static function data_for_messagearea_conversations_is_deprecated() {
2210         return true;
2211     }
2213     /**
2214      * The messagearea contacts return parameters.
2215      *
2216      * @deprecated since 3.6
2217      * @return external_function_parameters
2218      * @since 3.2
2219      */
2220     public static function data_for_messagearea_contacts_parameters() {
2221         return self::data_for_messagearea_conversations_parameters();
2222     }
2224     /**
2225      * Get messagearea contacts parameters.
2226      *
2227      * @deprecated since 3.6
2228      * @param int $userid The id of the user who we are viewing conversations for
2229      * @param int $limitfrom
2230      * @param int $limitnum
2231      * @return stdClass
2232      * @throws moodle_exception
2233      * @since 3.2
2234      */
2235     public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
2236         global $CFG, $PAGE, $USER;
2238         // Check if messaging is enabled.
2239         if (empty($CFG->messaging)) {
2240             throw new moodle_exception('disabled', 'message');
2241         }
2243         $systemcontext = context_system::instance();
2245         $params = array(
2246             'userid' => $userid,
2247             'limitfrom' => $limitfrom,
2248             'limitnum' => $limitnum
2249         );
2250         $params = self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
2251         self::validate_context($systemcontext);
2253         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2254             throw new moodle_exception('You do not have permission to perform this action.');
2255         }
2257         $contacts = \core_message\api::get_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
2258         $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
2260         $renderer = $PAGE->get_renderer('core_message');
2261         return $contacts->export_for_template($renderer);
2262     }
2264     /**
2265      * The messagearea contacts return structure.
2266      *
2267      * @deprecated since 3.6
2268      * @return external_single_structure
2269      * @since 3.2
2270      */
2271     public static function data_for_messagearea_contacts_returns() {
2272         return self::data_for_messagearea_conversations_returns();
2273     }
2275     /**
2276      * Marking the method as deprecated.
2277      *
2278      * @return bool
2279      */
2280     public static function data_for_messagearea_contacts_is_deprecated() {
2281         return true;
2282     }
2284     /**
2285      * The messagearea messages parameters.
2286      *
2287      * @deprecated since 3.6
2288      * @return external_function_parameters
2289      * @since 3.2
2290      */
2291     public static function data_for_messagearea_messages_parameters() {
2292         return new external_function_parameters(
2293             array(
2294                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2295                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2296                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2297                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
2298                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
2299                 'timefrom' => new external_value(PARAM_INT,
2300                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
2301             )
2302         );
2303     }
2305     /**
2306      * Get messagearea messages.
2307      *
2308      * @deprecated since 3.6
2309      * @param int $currentuserid The current user's id
2310      * @param int $otheruserid The other user's id
2311      * @param int $limitfrom
2312      * @param int $limitnum
2313      * @param boolean $newest
2314      * @return stdClass
2315      * @throws moodle_exception
2316      * @since 3.2
2317      */
2318     public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
2319                                                          $newest = false, $timefrom = 0) {
2320         global $CFG, $PAGE, $USER;
2322         // Check if messaging is enabled.
2323         if (empty($CFG->messaging)) {
2324             throw new moodle_exception('disabled', 'message');
2325         }
2327         $systemcontext = context_system::instance();
2329         $params = array(
2330             'currentuserid' => $currentuserid,
2331             'otheruserid' => $otheruserid,
2332             'limitfrom' => $limitfrom,
2333             'limitnum' => $limitnum,
2334             'newest' => $newest,
2335             'timefrom' => $timefrom,
2336         );
2337         $params = self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
2338         self::validate_context($systemcontext);
2340         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2341             throw new moodle_exception('You do not have permission to perform this action.');
2342         }
2344         if ($params['newest']) {
2345             $sort = 'timecreated DESC';
2346         } else {
2347             $sort = 'timecreated ASC';
2348         }
2350         // We need to enforce a one second delay on messages to avoid race conditions of current
2351         // messages still being sent.
2352         //
2353         // There is a chance that we could request messages before the current time's
2354         // second has elapsed and while other messages are being sent in that same second. In which
2355         // case those messages will be lost.
2356         //
2357         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
2358         if (!empty($params['timefrom'])) {
2359             $timeto = time() - 1;
2360         } else {
2361             $timeto = 0;
2362         }
2364         // No requesting messages from the current time, as stated above.
2365         if ($params['timefrom'] == time()) {
2366             $messages = [];
2367         } else {
2368             $messages = \core_message\api::get_messages($params['currentuserid'], $params['otheruserid'], $params['limitfrom'],
2369                                                         $params['limitnum'], $sort, $params['timefrom'], $timeto);
2370         }
2372         $messages = new \core_message\output\messagearea\messages($params['currentuserid'], $params['otheruserid'], $messages);
2374         $renderer = $PAGE->get_renderer('core_message');
2375         return $messages->export_for_template($renderer);
2376     }
2378     /**
2379      * The messagearea messages return structure.
2380      *
2381      * @deprecated since 3.6
2382      * @return external_single_structure
2383      * @since 3.2
2384      */
2385     public static function data_for_messagearea_messages_returns() {
2386         return new external_single_structure(
2387             array(
2388                 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
2389                     the messages on behalf of?'),
2390                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2391                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2392                 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
2393                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2394                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2395                 'messages' => new external_multiple_structure(
2396                     self::get_messagearea_message_structure()
2397                 ),
2398                 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
2399             )
2400         );
2401     }
2403     /**
2404      * Marking the method as deprecated.
2405      *
2406      * @return bool
2407      */
2408     public static function data_for_messagearea_messages_is_deprecated() {
2409         return true;
2410     }
2412     /**
2413      * The conversation messages parameters.
2414      *
2415      * @return external_function_parameters
2416      * @since 3.6
2417      */
2418     public static function get_conversation_messages_parameters() {
2419         return new external_function_parameters(
2420             array(
2421                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2422                 'convid' => new external_value(PARAM_INT, 'The conversation id'),
2423                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2424                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
2425                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
2426                 'timefrom' => new external_value(PARAM_INT,
2427                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
2428             )
2429         );
2430     }
2432     /**
2433      * Get conversation messages.
2434      *
2435      * @param  int $currentuserid The current user's id.
2436      * @param  int $convid The conversation id.
2437      * @param  int $limitfrom Return a subset of records, starting at this point (optional).
2438      * @param  int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
2439      * @param  bool $newest True for getting first newest messages, false otherwise.
2440      * @param  int  $timefrom The time from the conversation messages to get.
2441      * @return stdClass The messages and members who have sent some of these messages.
2442      * @throws moodle_exception
2443      * @since 3.6
2444      */
2445     public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
2446                                                          bool $newest = false, int $timefrom = 0) {
2447         global $CFG, $PAGE, $USER;
2449         // Check if messaging is enabled.
2450         if (empty($CFG->messaging)) {
2451             throw new moodle_exception('disabled', 'message');
2452         }
2454         $systemcontext = context_system::instance();
2456         $params = array(
2457             'currentuserid' => $currentuserid,
2458             'convid' => $convid,
2459             'limitfrom' => $limitfrom,
2460             'limitnum' => $limitnum,
2461             'newest' => $newest,
2462             'timefrom' => $timefrom,
2463         );
2464         $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
2465         self::validate_context($systemcontext);
2467         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2468             throw new moodle_exception('You do not have permission to perform this action.');
2469         }
2471         $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
2473         // We need to enforce a one second delay on messages to avoid race conditions of current
2474         // messages still being sent.
2475         //
2476         // There is a chance that we could request messages before the current time's
2477         // second has elapsed and while other messages are being sent in that same second. In which
2478         // case those messages will be lost.
2479         //
2480         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
2481         $timeto = empty($params['timefrom']) ? 0 : time() - 1;
2483         // No requesting messages from the current time, as stated above.
2484         if ($params['timefrom'] == time()) {
2485             $messages = [];
2486         } else {
2487             $messages = \core_message\api::get_conversation_messages(
2488                 $params['currentuserid'],
2489                 $params['convid'],
2490                 $params['limitfrom'],
2491                 $params['limitnum'],
2492                 $sort,
2493                 $params['timefrom'],
2494                 $timeto);
2495         }
2497         return $messages;
2498     }
2500     /**
2501      * The messagearea messages return structure.
2502      *
2503      * @return external_single_structure
2504      * @since 3.6
2505      */
2506     public static function get_conversation_messages_returns() {
2507         return new external_single_structure(
2508             array(
2509                 'id' => new external_value(PARAM_INT, 'The conversation id'),
2510                 'members' => new external_multiple_structure(
2511                     self::get_conversation_member_structure()
2512                 ),
2513                 'messages' => new external_multiple_structure(
2514                     self::get_conversation_message_structure()
2515                 ),
2516             )
2517         );
2518     }
2520     /**
2521      * The user contacts return parameters.
2522      *
2523      * @return external_function_parameters
2524      */
2525     public static function get_user_contacts_parameters() {
2526         return new external_function_parameters(
2527             array(
2528                 'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
2529                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
2530                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
2531             )
2532         );
2533     }
2535     /**
2536      * Get user contacts.
2537      *
2538      * @param int $userid The id of the user who we are viewing conversations for
2539      * @param int $limitfrom
2540      * @param int $limitnum
2541      * @return array
2542      * @throws moodle_exception
2543      */
2544     public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
2545         global $CFG, $USER;
2547         // Check if messaging is enabled.
2548         if (empty($CFG->messaging)) {
2549             throw new moodle_exception('disabled', 'message');
2550         }
2552         $systemcontext = context_system::instance();
2554         $params = array(
2555             'userid' => $userid,
2556             'limitfrom' => $limitfrom,
2557             'limitnum' => $limitnum
2558         );
2559         $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
2560         self::validate_context($systemcontext);
2562         if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2563             throw new moodle_exception('You do not have permission to perform this action.');
2564         }
2566         return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
2567     }
2569     /**
2570      * The user contacts return structure.
2571      *
2572      * @return external_multiple_structure
2573      */
2574     public static function get_user_contacts_returns() {
2575         return new external_multiple_structure(
2576             self::get_conversation_member_structure()
2577         );
2578     }
2580     /**
2581      * The get most recent message return parameters.
2582      *
2583      * @deprecated since 3.6
2584      * @return external_function_parameters
2585      * @since 3.2
2586      */
2587     public static function data_for_messagearea_get_most_recent_message_parameters() {
2588         return new external_function_parameters(
2589             array(
2590                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2591                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
2592             )
2593         );
2594     }
2596     /**
2597      * Get the most recent message in a conversation.
2598      *
2599      * @deprecated since 3.6
2600      * @param int $currentuserid The current user's id
2601      * @param int $otheruserid The other user's id
2602      * @return stdClass
2603      * @throws moodle_exception
2604      * @since 3.2
2605      */
2606     public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
2607         global $CFG, $PAGE, $USER;
2609         // Check if messaging is enabled.
2610         if (empty($CFG->messaging)) {
2611             throw new moodle_exception('disabled', 'message');
2612         }
2614         $systemcontext = context_system::instance();
2616         $params = array(
2617             'currentuserid' => $currentuserid,
2618             'otheruserid' => $otheruserid
2619         );
2620         $params = self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
2621         self::validate_context($systemcontext);
2623         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2624             throw new moodle_exception('You do not have permission to perform this action.');
2625         }
2627         $message = \core_message\api::get_most_recent_message($params['currentuserid'], $params['otheruserid']);
2628         $message = new \core_message\output\messagearea\message($message);
2630         $renderer = $PAGE->get_renderer('core_message');
2631         return $message->export_for_template($renderer);
2632     }
2634     /**
2635      * The get most recent message return structure.
2636      *
2637      * @deprecated since 3.6
2638      * @return external_single_structure
2639      * @since 3.2
2640      */
2641     public static function data_for_messagearea_get_most_recent_message_returns() {
2642         return self::get_messagearea_message_structure();
2643     }
2645     /**
2646      * Marking the method as deprecated.
2647      *
2648      * @return bool
2649      */
2650     public static function data_for_messagearea_get_most_recent_message_is_deprecated() {
2651         return true;
2652     }
2654     /**
2655      * The get profile parameters.
2656      *
2657      * @deprecated since 3.6
2658      * @return external_function_parameters
2659      * @since 3.2
2660      */
2661     public static function data_for_messagearea_get_profile_parameters() {
2662         return new external_function_parameters(
2663             array(
2664                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
2665                 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
2666             )
2667         );
2668     }
2670     /**
2671      * Get the profile information for a contact.
2672      *
2673      * @deprecated since 3.6
2674      * @param int $currentuserid The current user's id
2675      * @param int $otheruserid The id of the user whose profile we are viewing
2676      * @return stdClass
2677      * @throws moodle_exception
2678      * @since 3.2
2679      */
2680     public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
2681         global $CFG, $PAGE, $USER;
2683         // Check if messaging is enabled.
2684         if (empty($CFG->messaging)) {
2685             throw new moodle_exception('disabled', 'message');
2686         }
2688         $systemcontext = context_system::instance();
2690         $params = array(
2691             'currentuserid' => $currentuserid,
2692             'otheruserid' => $otheruserid
2693         );
2694         $params = self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
2695         self::validate_context($systemcontext);
2697         if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
2698             throw new moodle_exception('You do not have permission to perform this action.');
2699         }
2701         $profile = \core_message\api::get_profile($params['currentuserid'], $params['otheruserid']);
2702         $profile = new \core_message\output\messagearea\profile($profile);
2704         $renderer = $PAGE->get_renderer('core_message');
2705         return $profile->export_for_template($renderer);
2706     }
2708     /**
2709      * The get profile return structure.
2710      *
2711      * @deprecated since 3.6
2712      * @return external_single_structure
2713      * @since 3.2
2714      */
2715     public static function data_for_messagearea_get_profile_returns() {
2716         return new external_single_structure(
2717             array(
2718                 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
2719                 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
2720                 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
2721                 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
2722                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
2723                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
2724                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
2725                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
2726                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
2727                 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
2728                 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
2729             )
2730         );
2731     }
2733     /**
2734      * Marking the method as deprecated.
2735      *
2736      * @return bool
2737      */
2738     public static function data_for_messagearea_get_profile_is_deprecated() {
2739         return true;
2740     }
2742     /**
2743      * Get contacts parameters description.
2744      *
2745      * @deprecated since 3.6
2746      * @return external_function_parameters
2747      * @since Moodle 2.5
2748      */
2749     public static function get_contacts_parameters() {
2750         return new external_function_parameters(array());
2751     }
2753     /**
2754      * Get contacts.
2755      *
2756      * @deprecated since 3.6
2757      * @return external_description
2758      * @since Moodle 2.5
2759      */
2760     public static function get_contacts() {
2761         global $CFG, $PAGE, $USER;
2763         // Check if messaging is enabled.
2764         if (empty($CFG->messaging)) {
2765             throw new moodle_exception('disabled', 'message');
2766         }
2768         require_once($CFG->dirroot . '/user/lib.php');
2770         $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
2771         $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
2772         foreach ($contacts as $contact) {
2773             // Set the mode.
2774             $mode = 'offline';
2775             if (\core_message\helper::is_online($contact->lastaccess)) {
2776                 $mode = 'online';
2777             }
2779             $newcontact = array(
2780                 'id' => $contact->id,
2781                 'fullname' => fullname($contact),
2782                 'unread' => $contact->messagecount
2783             );
2785             $userpicture = new user_picture($contact);
2786             $userpicture->size = 1; // Size f1.
2787             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2788             $userpicture->size = 0; // Size f2.
2789             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2791             $allcontacts[$mode][$contact->id] = $newcontact;
2792         }
2794         $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
2795         foreach ($strangers as $contact) {
2796             $newcontact = array(
2797                 'id' => $contact->id,
2798                 'fullname' => fullname($contact),
2799                 'unread' => $contact->messagecount
2800             );
2802             $userpicture = new user_picture($contact);
2803             $userpicture->size = 1; // Size f1.
2804             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2805             $userpicture->size = 0; // Size f2.
2806             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2808             $allcontacts['strangers'][$contact->id] = $newcontact;
2809         }
2811         // Add noreply user and support user to the list, if they don't exist.
2812         $supportuser = core_user::get_support_user();
2813         if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
2814             $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
2815             if ($supportuser->messagecount > 0) {
2816                 $supportuser->fullname = fullname($supportuser);
2817                 $supportuser->unread = $supportuser->messagecount;
2818                 $allcontacts['strangers'][$supportuser->id] = $supportuser;
2819             }
2820         }
2822         $noreplyuser = core_user::get_noreply_user();
2823         if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
2824             $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
2825             if ($noreplyuser->messagecount > 0) {
2826                 $noreplyuser->fullname = fullname($noreplyuser);
2827                 $noreplyuser->unread = $noreplyuser->messagecount;
2828                 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
2829             }
2830         }
2832         return $allcontacts;
2833     }
2835     /**
2836      * Get contacts return description.
2837      *
2838      * @deprecated since 3.6
2839      * @return external_description
2840      * @since Moodle 2.5
2841      */
2842     public static function get_contacts_returns() {
2843         return new external_single_structure(
2844             array(
2845                 'online' => new external_multiple_structure(
2846                     new external_single_structure(
2847                         array(
2848                             'id' => new external_value(PARAM_INT, 'User ID'),
2849                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2850                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2851                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2852                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2853                         )
2854                     ),
2855                     'List of online contacts'
2856                 ),
2857                 'offline' => new external_multiple_structure(
2858                     new external_single_structure(
2859                         array(
2860                             'id' => new external_value(PARAM_INT, 'User ID'),
2861                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2862                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2863                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2864                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2865                         )
2866                     ),
2867                     'List of offline contacts'
2868                 ),
2869                 'strangers' => new external_multiple_structure(
2870                     new external_single_structure(
2871                         array(
2872                             'id' => new external_value(PARAM_INT, 'User ID'),
2873                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2874                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2875                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
2876                             'unread' => new external_value(PARAM_INT, 'Unread message count')
2877                         )
2878                     ),
2879                     'List of users that are not in the user\'s contact list but have sent a message'
2880                 )
2881             )
2882         );
2883     }
2885     /**
2886      * Marking the method as deprecated.
2887      *
2888      * @return bool
2889      */
2890     public static function get_contacts_is_deprecated() {
2891         return true;
2892     }
2894     /**
2895      * Search contacts parameters description.
2896      *
2897      * @return external_function_parameters
2898      * @since Moodle 2.5
2899      */
2900     public static function search_contacts_parameters() {
2901         return new external_function_parameters(
2902             array(
2903                 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
2904                 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
2905                     VALUE_DEFAULT, false)
2906             )
2907         );
2908     }
2910     /**
2911      * Search contacts.
2912      *
2913      * @param string $searchtext query string.
2914      * @param bool $onlymycourses limit the search to the user's courses only.
2915      * @return external_description
2916      * @since Moodle 2.5
2917      */
2918     public static function search_contacts($searchtext, $onlymycourses = false) {
2919         global $CFG, $USER, $PAGE;
2920         require_once($CFG->dirroot . '/user/lib.php');
2922         // Check if messaging is enabled.
2923         if (empty($CFG->messaging)) {
2924             throw new moodle_exception('disabled', 'message');
2925         }
2927         require_once($CFG->libdir . '/enrollib.php');
2929         $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
2930         $params = self::validate_parameters(self::search_contacts_parameters(), $params);
2932         // Extra validation, we do not allow empty queries.
2933         if ($params['searchtext'] === '') {
2934             throw new moodle_exception('querystringcannotbeempty');
2935         }
2937         $courseids = array();
2938         if ($params['onlymycourses']) {
2939             $mycourses = enrol_get_my_courses(array('id'));
2940             foreach ($mycourses as $mycourse) {
2941                 $courseids[] = $mycourse->id;
2942             }
2943         } else {
2944             $courseids[] = SITEID;
2945         }
2947         // Retrieving the users matching the query.
2948         $users = message_search_users($courseids, $params['searchtext']);
2949         $results = array();
2950         foreach ($users as $user) {
2951             $results[$user->id] = $user;
2952         }
2954         // Reorganising information.
2955         foreach ($results as &$user) {
2956             $newuser = array(
2957                 'id' => $user->id,
2958                 'fullname' => fullname($user)
2959             );
2961             // Avoid undefined property notice as phone not specified.
2962             $user->phone1 = null;
2963             $user->phone2 = null;
2965             $userpicture = new user_picture($user);
2966             $userpicture->size = 1; // Size f1.
2967             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2968             $userpicture->size = 0; // Size f2.
2969             $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
2971             $user = $newuser;
2972         }
2974         return $results;
2975     }
2977     /**
2978      * Search contacts return description.
2979      *
2980      * @return external_description
2981      * @since Moodle 2.5
2982      */
2983     public static function search_contacts_returns() {
2984         return new external_multiple_structure(
2985             new external_single_structure(
2986                 array(
2987                     'id' => new external_value(PARAM_INT, 'User ID'),
2988                     'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2989                     'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
2990                     'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
2991                 )
2992             ),
2993             'List of contacts'
2994         );
2995     }
2997     /**
2998      * Get messages parameters description.
2999      *
3000      * @return external_function_parameters
3001      * @since 2.8
3002      */
3003     public static function get_messages_parameters() {
3004         return new external_function_parameters(
3005             array(
3006                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3007                 'useridfrom' => new external_value(
3008                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
3009                     VALUE_DEFAULT, 0),
3010                 'type' => new external_value(
3011                     PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
3012                     VALUE_DEFAULT, 'both'),
3013                 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
3014                 'newestfirst' => new external_value(
3015                     PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
3016                     VALUE_DEFAULT, true),
3017                 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
3018                 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
3019             )
3020         );
3021     }
3023     /**
3024      * Get messages function implementation.
3025      *
3026      * @since  2.8
3027      * @throws invalid_parameter_exception
3028      * @throws moodle_exception
3029      * @param  int      $useridto       the user id who received the message
3030      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
3031      * @param  string   $type           type of message to return, expected values: notifications, conversations and both
3032      * @param  bool     $read           true for retreiving read messages, false for unread
3033      * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
3034      * @param  int      $limitfrom      limit from
3035      * @param  int      $limitnum       limit num
3036      * @return external_description
3037      */
3038     public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
3039                                         $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
3040         global $CFG, $USER;
3042         $warnings = array();
3044         $params = array(
3045             'useridto' => $useridto,
3046             'useridfrom' => $useridfrom,
3047             'type' => $type,
3048             'read' => $read,
3049             'newestfirst' => $newestfirst,
3050             'limitfrom' => $limitfrom,
3051             'limitnum' => $limitnum
3052         );
3054         $params = self::validate_parameters(self::get_messages_parameters(), $params);
3056         $context = context_system::instance();
3057         self::validate_context($context);
3059         $useridto = $params['useridto'];
3060         $useridfrom = $params['useridfrom'];
3061         $type = $params['type'];
3062         $read = $params['read'];
3063         $newestfirst = $params['newestfirst'];
3064         $limitfrom = $params['limitfrom'];
3065         $limitnum = $params['limitnum'];
3067         $allowedvalues = array('notifications', 'conversations', 'both');
3068         if (!in_array($type, $allowedvalues)) {
3069             throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
3070                 'allowed values are: ' . implode(',', $allowedvalues));
3071         }
3073         // Check if private messaging between users is allowed.
3074         if (empty($CFG->messaging)) {
3075             // If we are retreiving only conversations, and messaging is disabled, throw an exception.
3076             if ($type == "conversations") {
3077                 throw new moodle_exception('disabled', 'message');
3078             }
3079             if ($type == "both") {
3080                 $warning = array();
3081                 $warning['item'] = 'message';
3082                 $warning['itemid'] = $USER->id;
3083                 $warning['warningcode'] = '1';
3084                 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
3085                     Only notifications will be returned';
3086                 $warnings[] = $warning;
3087             }
3088         }
3090         if (!empty($useridto)) {
3091             if (core_user::is_real_user($useridto)) {
3092                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3093             } else {
3094                 throw new moodle_exception('invaliduser');
3095             }
3096         }
3098         if (!empty($useridfrom)) {
3099             // We use get_user here because the from user can be the noreply or support user.
3100             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3101         }
3103         // Check if the current user is the sender/receiver or just a privileged user.
3104         if ($useridto != $USER->id and $useridfrom != $USER->id and
3105              !has_capability('moodle/site:readallmessages', $context)) {
3106             throw new moodle_exception('accessdenied', 'admin');
3107         }
3109         // Which type of messages to retrieve.
3110         $notifications = -1;
3111         if ($type != 'both') {
3112             $notifications = ($type == 'notifications') ? 1 : 0;
3113         }
3115         $orderdirection = $newestfirst ? 'DESC' : 'ASC';
3116         $sort = "mr.timecreated $orderdirection";
3118         if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
3119             $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
3121             // In some cases, we don't need to get the to/from user objects from the sql query.
3122             $userfromfullname = '';
3123             $usertofullname = '';
3125             // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
3126             if (!empty($useridto)) {
3127                 $usertofullname = fullname($userto, $canviewfullname);
3128                 // The user from may or may not be filled.
3129                 if (!empty($useridfrom)) {
3130                     $userfromfullname = fullname($userfrom, $canviewfullname);
3131                 }
3132             } else {
3133                 // If the useridto field is empty, the useridfrom must be filled.
3134                 $userfromfullname = fullname($userfrom, $canviewfullname);
3135             }
3136             foreach ($messages as $mid => $message) {
3138                 // Do not return deleted messages.
3139                 if (!$message->notification) {
3140                     if (($useridto == $USER->id and $message->timeusertodeleted) or
3141                         ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
3142                         unset($messages[$mid]);
3143                         continue;
3144                     }
3145                 }
3147                 // We need to get the user from the query.
3148                 if (empty($userfromfullname)) {
3149                     // Check for non-reply and support users.
3150                     if (core_user::is_real_user($message->useridfrom)) {
3151                         $user = new stdClass();
3152                         $user = username_load_fields_from_object($user, $message, 'userfrom');
3153                         $message->userfromfullname = fullname($user, $canviewfullname);
3154                     } else {
3155                         $user = core_user::get_user($message->useridfrom);
3156                         $message->userfromfullname = fullname($user, $canviewfullname);
3157                     }
3158                 } else {
3159                     $message->userfromfullname = $userfromfullname;
3160                 }
3162                 // We need to get the user from the query.
3163                 if (empty($usertofullname)) {
3164                     $user = new stdClass();
3165                     $user = username_load_fields_from_object($user, $message, 'userto');
3166                     $message->usertofullname = fullname($user, $canviewfullname);
3167                 } else {
3168                     $message->usertofullname = $usertofullname;
3169                 }
3171                 $message->text = message_format_message_text($message);
3172                 $messages[$mid] = (array) $message;
3173             }
3174         }
3176         $results = array(
3177             'messages' => $messages,
3178             'warnings' => $warnings
3179         );
3181         return $results;
3182     }
3184     /**
3185      * Get messages return description.
3186      *
3187      * @return external_single_structure
3188      * @since 2.8
3189      */
3190     public static function get_messages_returns() {
3191         return new external_single_structure(
3192             array(
3193                 'messages' => new external_multiple_structure(
3194                     new external_single_structure(
3195                         array(
3196                             'id' => new external_value(PARAM_INT, 'Message id'),
3197                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
3198                             'useridto' => new external_value(PARAM_INT, 'User to id'),
3199                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
3200                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
3201                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
3202                             'fullmessageformat' => new external_format_value('fullmessage'),
3203                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
3204                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
3205                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
3206                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
3207                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
3208                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
3209                             'timeread' => new external_value(PARAM_INT, 'Time read'),
3210                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
3211                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
3212                             'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
3213                                 VALUE_OPTIONAL),
3214                             'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
3215                             'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
3216                                 The data here is serialised using json_encode().', VALUE_OPTIONAL),
3217                         ), 'message'
3218                     )
3219                 ),
3220                 'warnings' => new external_warnings()
3221             )
3222         );
3223     }
3225     /**
3226      * Mark all notifications as read parameters description.
3227      *
3228      * @return external_function_parameters
3229      * @since 3.2
3230      */
3231     public static function mark_all_notifications_as_read_parameters() {
3232         return new external_function_parameters(
3233             array(
3234                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3235                 'useridfrom' => new external_value(
3236                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
3237                     VALUE_DEFAULT, 0),
3238             )
3239         );
3240     }
3242     /**
3243      * Mark all notifications as read function.
3244      *
3245      * @since  3.2
3246      * @throws invalid_parameter_exception
3247      * @throws moodle_exception
3248      * @param  int      $useridto       the user id who received the message
3249      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
3250      * @return external_description
3251      */
3252     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
3253         global $USER;
3255         $params = self::validate_parameters(
3256             self::mark_all_notifications_as_read_parameters(),
3257             array(
3258                 'useridto' => $useridto,
3259                 'useridfrom' => $useridfrom,
3260             )
3261         );
3263         $context = context_system::instance();
3264         self::validate_context($context);
3266         $useridto = $params['useridto'];
3267         $useridfrom = $params['useridfrom'];
3269         if (!empty($useridto)) {
3270             if (core_user::is_real_user($useridto)) {
3271                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3272             } else {
3273                 throw new moodle_exception('invaliduser');
3274             }
3275         }
3277         if (!empty($useridfrom)) {
3278             // We use get_user here because the from user can be the noreply or support user.
3279             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
3280         }
3282         // Check if the current user is the sender/receiver or just a privileged user.
3283         if ($useridto != $USER->id and $useridfrom != $USER->id and
3284             // The deleteanymessage cap seems more reasonable here than readallmessages.
3285              !has_capability('moodle/site:deleteanymessage', $context)) {
3286             throw new moodle_exception('accessdenied', 'admin');
3287         }
3289         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
3291         return true;
3292     }
3294     /**
3295      * Mark all notifications as read return description.
3296      *
3297      * @return external_single_structure
3298      * @since 3.2
3299      */
3300     public static function mark_all_notifications_as_read_returns() {
3301         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
3302     }
3304     /**
3305      * Get unread conversations count parameters description.
3306      *
3307      * @return external_function_parameters
3308      * @since 3.2
3309      */
3310     public static function get_unread_conversations_count_parameters() {
3311         return new external_function_parameters(
3312             array(
3313                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
3314             )
3315         );
3316     }
3318     /**
3319      * Get unread messages count function.
3320      *
3321      * @since  3.2
3322      * @throws invalid_parameter_exception
3323      * @throws moodle_exception
3324      * @param  int      $useridto       the user id who received the message
3325      * @return external_description
3326      */
3327     public static function get_unread_conversations_count($useridto) {
3328         global $USER, $CFG;
3330         // Check if messaging is enabled.
3331         if (empty($CFG->messaging)) {
3332             throw new moodle_exception('disabled', 'message');
3333         }
3335         $params = self::validate_parameters(
3336             self::get_unread_conversations_count_parameters(),
3337             array('useridto' => $useridto)
3338         );
3340         $context = context_system::instance();
3341         self::validate_context($context);
3343         $useridto = $params['useridto'];
3345         if (!empty($useridto)) {
3346             if (core_user::is_real_user($useridto)) {
3347                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
3348             } else {
3349                 throw new moodle_exception('invaliduser');
3350             }
3351         } else {
3352             $useridto = $USER->id;
3353         }
3355         // Check if the current user is the receiver or just a privileged user.
3356         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
3357             throw new moodle_exception('accessdenied', 'admin');
3358         }
3360         return \core_message\api::count_unread_conversations($userto);
3361     }
3363     /**
3364      * Get unread conversations count return description.
3365      *
3366      * @return external_single_structure
3367      * @since 3.2
3368      */
3369     public static function get_unread_conversations_count_returns() {
3370         return new external_value(PARAM_INT, 'The count of unread messages for the user');
3371     }
3373     /**
3374      * Get blocked users parameters description.
3375      *
3376      * @return external_function_parameters
3377      * @since 2.9
3378      */
3379     public static function get_blocked_users_parameters() {
3380         return new external_function_parameters(
3381             array(
3382                 'userid' => new external_value(PARAM_INT,
3383                                 'the user whose blocked users we want to retrieve',
3384                                 VALUE_REQUIRED),
3385             )
3386         );
3387     }
3389     /**
3390      * Retrieve a list of users blocked
3391      *
3392      * @param  int $userid the user whose blocked users we want to retrieve
3393      * @return external_description
3394      * @since 2.9
3395      */
3396     public static function get_blocked_users($userid) {
3397         global $CFG, $USER, $PAGE;
3399         // Warnings array, it can be empty at the end but is mandatory.
3400         $warnings = array();
3402         // Validate params.
3403         $params