MDL-63547 core_message: added delete_conversation_by_id web service
[moodle.git] / message / externallib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * External message API
20  *
21  * @package    core_message
22  * @category   external
23  * @copyright  2011 Jerome Mouneyrac
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die();
29 require_once("$CFG->libdir/externallib.php");
30 require_once($CFG->dirroot . "/message/lib.php");
32 /**
33  * Message external functions
34  *
35  * @package    core_message
36  * @category   external
37  * @copyright  2011 Jerome Mouneyrac
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  * @since Moodle 2.2
40  */
41 class core_message_external extends external_api {
43     /**
44      * Returns description of method parameters
45      *
46      * @return external_function_parameters
47      * @since Moodle 2.2
48      */
49     public static function send_instant_messages_parameters() {
50         return new external_function_parameters(
51             array(
52                 'messages' => new external_multiple_structure(
53                     new external_single_structure(
54                         array(
55                             'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
56                             'text' => new external_value(PARAM_RAW, 'the text of the message'),
57                             'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
58                             'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the message. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL),
59                         )
60                     )
61                 )
62             )
63         );
64     }
66     /**
67      * Send private messages from the current USER to other users
68      *
69      * @param array $messages An array of message to send.
70      * @return array
71      * @since Moodle 2.2
72      */
73     public static function send_instant_messages($messages = array()) {
74         global $CFG, $USER, $DB;
76         // Check if messaging is enabled.
77         if (empty($CFG->messaging)) {
78             throw new moodle_exception('disabled', 'message');
79         }
81         // Ensure the current user is allowed to run this function
82         $context = context_system::instance();
83         self::validate_context($context);
84         require_capability('moodle/site:sendmessage', $context);
86         $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
88         //retrieve all tousers of the messages
89         $receivers = array();
90         foreach($params['messages'] as $message) {
91             $receivers[] = $message['touserid'];
92         }
93         list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
94         $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
95         $blocklist   = array();
96         $contactlist = array();
97         $contactsqlparams = array_merge($sqlparams, [$USER->id], [$USER->id], $sqlparams);
98         $rs = $DB->get_recordset_sql("SELECT *
99                                         FROM {message_contacts}
100                                        WHERE (userid $sqluserids AND contactid = ?)
101                                           OR (userid = ? AND contactid $sqluserids)", $contactsqlparams);
102         foreach ($rs as $record) {
103             $useridtouse = $record->userid;
104             if ($record->userid == $USER->id) {
105                 $useridtouse = $record->contactid;
106             }
107             $contactlist[$useridtouse] = true;
108         }
109         $rs->close();
110         $blocksqlparams = array_merge($sqlparams, [$USER->id]);
111         $rs = $DB->get_recordset_sql("SELECT *
112                                         FROM {message_users_blocked}
113                                        WHERE userid $sqluserids
114                                          AND blockeduserid = ?", $blocksqlparams);
115         foreach ($rs as $record) {
116             $blocklist[$record->userid] = true;
117         }
118         $rs->close();
120         $canreadallmessages = has_capability('moodle/site:readallmessages', $context);
122         $resultmessages = array();
123         foreach ($params['messages'] as $message) {
124             $resultmsg = array(); //the infos about the success of the operation
126             //we are going to do some checking
127             //code should match /messages/index.php checks
128             $success = true;
130             //check the user exists
131             if (empty($tousers[$message['touserid']])) {
132                 $success = false;
133                 $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
134             }
136             //check that the touser is not blocking the current user
137             if ($success and !empty($blocklist[$message['touserid']]) and !$canreadallmessages) {
138                 $success = false;
139                 $errormessage = get_string('userisblockingyou', 'message');
140             }
142             // Check if the user is a contact
143             //TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
144             $blocknoncontacts = get_user_preferences('message_blocknoncontacts', NULL, $message['touserid']);
145             // message_blocknoncontacts option is on and current user is not in contact list
146             if ($success && empty($contactlist[$message['touserid']]) && !empty($blocknoncontacts)) {
147                 // The user isn't a contact and they have selected to block non contacts so this message won't be sent.
148                 $success = false;
149                 $errormessage = get_string('userisblockingyounoncontact', 'message',
150                         fullname(core_user::get_user($message['touserid'])));
151             }
153             //now we can send the message (at least try)
154             if ($success) {
155                 //TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object
156                 $success = message_post_message($USER, $tousers[$message['touserid']],
157                         $message['text'], external_validate_format($message['textformat']));
158             }
160             //build the resultmsg
161             if (isset($message['clientmsgid'])) {
162                 $resultmsg['clientmsgid'] = $message['clientmsgid'];
163             }
164             if ($success) {
165                 $resultmsg['msgid'] = $success;
166             } else {
167                 // WARNINGS: for backward compatibility we return this errormessage.
168                 //          We should have thrown exceptions as these errors prevent results to be returned.
169                 // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
170                 $resultmsg['msgid'] = -1;
171                 $resultmsg['errormessage'] = $errormessage;
172             }
174             $resultmessages[] = $resultmsg;
175         }
177         return $resultmessages;
178     }
180     /**
181      * Returns description of method result value
182      *
183      * @return external_description
184      * @since Moodle 2.2
185      */
186     public static function send_instant_messages_returns() {
187         return new external_multiple_structure(
188             new external_single_structure(
189                 array(
190                     'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
191                     'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
192                     'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
193                 )
194             )
195         );
196     }
198     /**
199      * Create contacts parameters description.
200      *
201      * @deprecated since Moodle 3.6
202      * @return external_function_parameters
203      * @since Moodle 2.5
204      */
205     public static function create_contacts_parameters() {
206         return new external_function_parameters(
207             array(
208                 'userids' => new external_multiple_structure(
209                     new external_value(PARAM_INT, 'User ID'),
210                     'List of user IDs'
211                 ),
212                 'userid' => new external_value(PARAM_INT, 'The id of the user we are creating the contacts for, 0 for the
213                     current user', VALUE_DEFAULT, 0)
214             )
215         );
216     }
218     /**
219      * Create contacts.
220      *
221      * @deprecated since Moodle 3.6
222      * @param array $userids array of user IDs.
223      * @param int $userid The id of the user we are creating the contacts for
224      * @return external_description
225      * @since Moodle 2.5
226      */
227     public static function create_contacts($userids, $userid = 0) {
228         global $CFG, $USER;
230         // Check if messaging is enabled.
231         if (empty($CFG->messaging)) {
232             throw new moodle_exception('disabled', 'message');
233         }
235         if (empty($userid)) {
236             $userid = $USER->id;
237         }
239         // Validate context.
240         $context = context_system::instance();
241         self::validate_context($context);
243         $capability = 'moodle/site:manageallmessaging';
244         if (($USER->id != $userid) && !has_capability($capability, $context)) {
245             throw new required_capability_exception($context, $capability, 'nopermissions', '');
246         }
248         $params = array('userids' => $userids, 'userid' => $userid);
249         $params = self::validate_parameters(self::create_contacts_parameters(), $params);
251         $warnings = array();
252         foreach ($params['userids'] as $id) {
253             if (!message_add_contact($id, 0, $userid)) {
254                 $warnings[] = array(
255                     'item' => 'user',
256                     'itemid' => $id,
257                     'warningcode' => 'contactnotcreated',
258                     'message' => 'The contact could not be created'
259                 );
260             }
261         }
262         return $warnings;
263     }
265     /**
266      * Create contacts return description.
267      *
268      * @deprecated since Moodle 3.6
269      * @return external_description
270      * @since Moodle 2.5
271      */
272     public static function create_contacts_returns() {
273         return new external_warnings();
274     }
276     /**
277      * Marking the method as deprecated.
278      *
279      * @return bool
280      */
281     public static function create_contacts_is_deprecated() {
282         return true;
283     }
285     /**
286      * Delete contacts parameters description.
287      *
288      * @return external_function_parameters
289      * @since Moodle 2.5
290      */
291     public static function delete_contacts_parameters() {
292         return new external_function_parameters(
293             array(
294                 'userids' => new external_multiple_structure(
295                     new external_value(PARAM_INT, 'User ID'),
296                     'List of user IDs'
297                 ),
298                 'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
299                     current user', VALUE_DEFAULT, 0)
300             )
301         );
302     }
304     /**
305      * Delete contacts.
306      *
307      * @param array $userids array of user IDs.
308      * @param int $userid The id of the user we are deleting the contacts for
309      * @return null
310      * @since Moodle 2.5
311      */
312     public static function delete_contacts($userids, $userid = 0) {
313         global $CFG, $USER;
315         // Check if messaging is enabled.
316         if (empty($CFG->messaging)) {
317             throw new moodle_exception('disabled', 'message');
318         }
320         if (empty($userid)) {
321             $userid = $USER->id;
322         }
324         // Validate context.
325         $context = context_system::instance();
326         self::validate_context($context);
328         $capability = 'moodle/site:manageallmessaging';
329         if (($USER->id != $userid) && !has_capability($capability, $context)) {
330             throw new required_capability_exception($context, $capability, 'nopermissions', '');
331         }
333         $params = array('userids' => $userids, 'userid' => $userid);
334         $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
336         foreach ($params['userids'] as $id) {
337             \core_message\api::remove_contact($userid, $id);
338         }
340         return null;
341     }
343     /**
344      * Delete contacts return description.
345      *
346      * @return external_description
347      * @since Moodle 2.5
348      */
349     public static function delete_contacts_returns() {
350         return null;
351     }
353     /**
354      * Block user parameters description.
355      *
356      * @return external_function_parameters
357      */
358     public static function block_user_parameters() {
359         return new external_function_parameters(
360             [
361                 'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
362                 'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
363             ]
364         );
365     }
367     /**
368      * Blocks a user.
369      *
370      * @param int $userid The id of the user who is blocking
371      * @param int $blockeduserid The id of the user being blocked
372      * @return external_description
373      */
374     public static function block_user(int $userid, int $blockeduserid) {
375         global $CFG, $USER;
377         // Check if messaging is enabled.
378         if (empty($CFG->messaging)) {
379             throw new moodle_exception('disabled', 'message');
380         }
382         // Validate context.
383         $context = context_system::instance();
384         self::validate_context($context);
386         $capability = 'moodle/site:manageallmessaging';
387         if (($USER->id != $userid) && !has_capability($capability, $context)) {
388             throw new required_capability_exception($context, $capability, 'nopermissions', '');
389         }
391         $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
392         $params = self::validate_parameters(self::block_user_parameters(), $params);
394         if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
395             \core_message\api::block_user($params['userid'], $params['blockeduserid']);
396         }
398         return [];
399     }
401     /**
402      * Block user return description.
403      *
404      * @return external_description
405      */
406     public static function block_user_returns() {
407         return new external_warnings();
408     }
410     /**
411      * Unblock user parameters description.
412      *
413      * @return external_function_parameters
414      */
415     public static function unblock_user_parameters() {
416         return new external_function_parameters(
417             [
418                 'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
419                 'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
420             ]
421         );
422     }
424     /**
425      * Unblock user.
426      *
427      * @param int $userid The id of the user who is unblocking
428      * @param int $unblockeduserid The id of the user being unblocked
429      */
430     public static function unblock_user(int $userid, int $unblockeduserid) {
431         global $CFG, $USER;
433         // Check if messaging is enabled.
434         if (empty($CFG->messaging)) {
435             throw new moodle_exception('disabled', 'message');
436         }
438         // Validate context.
439         $context = context_system::instance();
440         self::validate_context($context);
442         $capability = 'moodle/site:manageallmessaging';
443         if (($USER->id != $userid) && !has_capability($capability, $context)) {
444             throw new required_capability_exception($context, $capability, 'nopermissions', '');
445         }
447         $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
448         $params = self::validate_parameters(self::unblock_user_parameters(), $params);
450         \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
452         return [];
453     }
455     /**
456      * Unblock user return description.
457      *
458      * @return external_description
459      */
460     public static function unblock_user_returns() {
461         return new external_warnings();
462     }
464     /**
465      * Block contacts parameters description.
466      *
467      * @deprecated since Moodle 3.6
468      * @return external_function_parameters
469      * @since Moodle 2.5
470      */
471     public static function block_contacts_parameters() {
472         return new external_function_parameters(
473             array(
474                 'userids' => new external_multiple_structure(
475                     new external_value(PARAM_INT, 'User ID'),
476                     'List of user IDs'
477                 ),
478                 'userid' => new external_value(PARAM_INT, 'The id of the user we are blocking the contacts for, 0 for the
479                     current user', VALUE_DEFAULT, 0)
480             )
481         );
482     }
484     /**
485      * Block contacts.
486      *
487      * @deprecated since Moodle 3.6
488      * @param array $userids array of user IDs.
489      * @param int $userid The id of the user we are blocking the contacts for
490      * @return external_description
491      * @since Moodle 2.5
492      */
493     public static function block_contacts($userids, $userid = 0) {
494         global $CFG, $USER;
496         // Check if messaging is enabled.
497         if (empty($CFG->messaging)) {
498             throw new moodle_exception('disabled', 'message');
499         }
501         if (empty($userid)) {
502             $userid = $USER->id;
503         }
505         // Validate context.
506         $context = context_system::instance();
507         self::validate_context($context);
509         $capability = 'moodle/site:manageallmessaging';
510         if (($USER->id != $userid) && !has_capability($capability, $context)) {
511             throw new required_capability_exception($context, $capability, 'nopermissions', '');
512         }
514         $params = array('userids' => $userids, 'userid' => $userid);
515         $params = self::validate_parameters(self::block_contacts_parameters(), $params);
517         $warnings = array();
518         foreach ($params['userids'] as $id) {
519             if (!message_block_contact($id, $userid)) {
520                 $warnings[] = array(
521                     'item' => 'user',
522                     'itemid' => $id,
523                     'warningcode' => 'contactnotblocked',
524                     'message' => 'The contact could not be blocked'
525                 );
526             }
527         }
528         return $warnings;
529     }
531     /**
532      * Block contacts return description.
533      *
534      * @deprecated since Moodle 3.6
535      * @return external_description
536      * @since Moodle 2.5
537      */
538     public static function block_contacts_returns() {
539         return new external_warnings();
540     }
542     /**
543      * Marking the method as deprecated.
544      *
545      * @return bool
546      */
547     public static function block_contacts_is_deprecated() {
548         return true;
549     }
551     /**
552      * Unblock contacts parameters description.
553      *
554      * @deprecated since Moodle 3.6
555      * @return external_function_parameters
556      * @since Moodle 2.5
557      */
558     public static function unblock_contacts_parameters() {
559         return new external_function_parameters(
560             array(
561                 'userids' => new external_multiple_structure(
562                     new external_value(PARAM_INT, 'User ID'),
563                     'List of user IDs'
564                 ),
565                 'userid' => new external_value(PARAM_INT, 'The id of the user we are unblocking the contacts for, 0 for the
566                     current user', VALUE_DEFAULT, 0)
567             )
568         );
569     }
571     /**
572      * Unblock contacts.
573      *
574      * @deprecated since Moodle 3.6
575      * @param array $userids array of user IDs.
576      * @param int $userid The id of the user we are unblocking the contacts for
577      * @return null
578      * @since Moodle 2.5
579      */
580     public static function unblock_contacts($userids, $userid = 0) {
581         global $CFG, $USER;
583         // Check if messaging is enabled.
584         if (empty($CFG->messaging)) {
585             throw new moodle_exception('disabled', 'message');
586         }
588         if (empty($userid)) {
589             $userid = $USER->id;
590         }
592         // Validate context.
593         $context = context_system::instance();
594         self::validate_context($context);
596         $capability = 'moodle/site:manageallmessaging';
597         if (($USER->id != $userid) && !has_capability($capability, $context)) {
598             throw new required_capability_exception($context, $capability, 'nopermissions', '');
599         }
601         $params = array('userids' => $userids, 'userid' => $userid);
602         $params = self::validate_parameters(self::unblock_contacts_parameters(), $params);
604         foreach ($params['userids'] as $id) {
605             message_unblock_contact($id, $userid);
606         }
608         return null;
609     }
611     /**
612      * Unblock contacts return description.
613      *
614      * @deprecated since Moodle 3.6
615      * @return external_description
616      * @since Moodle 2.5
617      */
618     public static function unblock_contacts_returns() {
619         return null;
620     }
622     /**
623      * Marking the method as deprecated.
624      *
625      * @return bool
626      */
627     public static function unblock_contacts_is_deprecated() {
628         return true;
629     }
631     /**
632      * Returns contact requests parameters description.
633      *
634      * @return external_function_parameters
635      */
636     public static function get_contact_requests_parameters() {
637         return new external_function_parameters(
638             [
639                 'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for')
640             ]
641         );
642     }
644     /**
645      * Handles returning the contact requests for a user.
646      *
647      * This also includes the user data necessary to display information
648      * about the user.
649      *
650      * It will not include blocked users.
651      *
652      * @param int $userid The id of the user we want to get the contact requests for
653      */
654     public static function get_contact_requests(int $userid) {
655         global $CFG, $USER;
657         // Check if messaging is enabled.
658         if (empty($CFG->messaging)) {
659             throw new moodle_exception('disabled', 'message');
660         }
662         // Validate context.
663         $context = context_system::instance();
664         self::validate_context($context);
666         $capability = 'moodle/site:manageallmessaging';
667         if (($USER->id != $userid) && !has_capability($capability, $context)) {
668             throw new required_capability_exception($context, $capability, 'nopermissions', '');
669         }
671         $params = ['userid' => $userid];
672         $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
674         return \core_message\api::get_contact_requests($params['userid']);
675     }
677     /**
678      * Returns the contact requests return description.
679      *
680      * @return external_description
681      */
682     public static function get_contact_requests_returns() {
683         return new external_multiple_structure(
684             new external_single_structure(
685                 [
686                     'id' => new external_value(core_user::get_property_type('id'), 'ID of the user'),
687                     'contactrequestid' => new external_value(PARAM_INT, 'The ID of the contact request'),
688                     'picture' => new external_value(core_user::get_property_type('picture'), 'The picture'),
689                     'firstname' => new external_value(core_user::get_property_type('firstname'),
690                         'The first name(s) of the user'),
691                     'lastname' => new external_value(core_user::get_property_type('lastname'),
692                         'The family name of the user'),
693                     'firstnamephonetic' => new external_value(core_user::get_property_type('firstnamephonetic'),
694                         'The phonetic first name of the user'),
695                     'lastnamephonetic' => new external_value(core_user::get_property_type('lastnamephonetic'),
696                         'The phonetic last name of the user'),
697                     'middlename' => new external_value(core_user::get_property_type('middlename'),
698                         'The middle name of the user'),
699                     'alternatename' => new external_value(core_user::get_property_type('alternatename'),
700                         'The alternate name of the user'),
701                     'email' => new external_value(core_user::get_property_type('email'), 'An email address')
702                 ]
703             )
704         );
705     }
707     /**
708      * Creates a contact request parameters description.
709      *
710      * @return external_function_parameters
711      */
712     public static function create_contact_request_parameters() {
713         return new external_function_parameters(
714             [
715                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
716                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
717             ]
718         );
719     }
721     /**
722      * Creates a contact request.
723      *
724      * @param int $userid The id of the user who is creating the contact request
725      * @param int $requesteduserid The id of the user being requested
726      */
727     public static function create_contact_request(int $userid, int $requesteduserid) {
728         global $CFG, $USER;
730         // Check if messaging is enabled.
731         if (empty($CFG->messaging)) {
732             throw new moodle_exception('disabled', 'message');
733         }
735         // Validate context.
736         $context = context_system::instance();
737         self::validate_context($context);
739         $capability = 'moodle/site:manageallmessaging';
740         if (($USER->id != $userid) && !has_capability($capability, $context)) {
741             throw new required_capability_exception($context, $capability, 'nopermissions', '');
742         }
744         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
745         $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
747         if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
748             $warning[] = [
749                 'item' => 'user',
750                 'itemid' => $params['requesteduserid'],
751                 'warningcode' => 'cannotcreatecontactrequest',
752                 'message' => 'You are unable to create a contact request for this user'
753             ];
754             return $warning;
755         }
757         if (!\core_message\api::does_contact_request_exist($params['userid'], $params['requesteduserid'])) {
758             \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
759         }
761         return [];
762     }
764     /**
765      * Creates a contact request return description.
766      *
767      * @return external_description
768      */
769     public static function create_contact_request_returns() {
770         return new external_warnings();
771     }
773     /**
774      * Confirm a contact request parameters description.
775      *
776      * @return external_function_parameters
777      */
778     public static function confirm_contact_request_parameters() {
779         return new external_function_parameters(
780             [
781                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
782                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
783             ]
784         );
785     }
787     /**
788      * Confirm a contact request.
789      *
790      * @param int $userid The id of the user who is creating the contact request
791      * @param int $requesteduserid The id of the user being requested
792      */
793     public static function confirm_contact_request(int $userid, int $requesteduserid) {
794         global $CFG, $USER;
796         // Check if messaging is enabled.
797         if (empty($CFG->messaging)) {
798             throw new moodle_exception('disabled', 'message');
799         }
801         // Validate context.
802         $context = context_system::instance();
803         self::validate_context($context);
805         $capability = 'moodle/site:manageallmessaging';
806         if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
807             throw new required_capability_exception($context, $capability, 'nopermissions', '');
808         }
810         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
811         $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
813         \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
815         return [];
816     }
818     /**
819      * Confirm a contact request return description.
820      *
821      * @return external_description
822      */
823     public static function confirm_contact_request_returns() {
824         return new external_warnings();
825     }
827     /**
828      * Declines a contact request parameters description.
829      *
830      * @return external_function_parameters
831      */
832     public static function decline_contact_request_parameters() {
833         return new external_function_parameters(
834             [
835                 'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
836                 'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
837             ]
838         );
839     }
841     /**
842      * Declines a contact request.
843      *
844      * @param int $userid The id of the user who is creating the contact request
845      * @param int $requesteduserid The id of the user being requested
846      */
847     public static function decline_contact_request(int $userid, int $requesteduserid) {
848         global $CFG, $USER;
850         // Check if messaging is enabled.
851         if (empty($CFG->messaging)) {
852             throw new moodle_exception('disabled', 'message');
853         }
855         // Validate context.
856         $context = context_system::instance();
857         self::validate_context($context);
859         $capability = 'moodle/site:manageallmessaging';
860         if (($USER->id != $requesteduserid) && !has_capability($capability, $context)) {
861             throw new required_capability_exception($context, $capability, 'nopermissions', '');
862         }
864         $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
865         $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
867         \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
869         return [];
870     }
872     /**
873      * Declines a contact request return description.
874      *
875      * @return external_description
876      */
877     public static function decline_contact_request_returns() {
878         return new external_warnings();
879     }
881     /**
882      * Return the structure of a message area contact.
883      *
884      * @return external_single_structure
885      * @since Moodle 3.2
886      */
887     private static function get_messagearea_contact_structure() {
888         return new external_single_structure(
889             array(
890                 'userid' => new external_value(PARAM_INT, 'The user\'s id'),
891                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
892                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
893                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
894                 'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
895                 'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
896                 'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
897                 'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
898                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
899                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
900                 'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
901                 'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
902                 'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
903                     VALUE_DEFAULT, null),
904             )
905         );
906     }
908     /**
909      * Return the structure of a message area message.
910      *
911      * @return external_single_structure
912      * @since Moodle 3.2
913      */
914     private static function get_messagearea_message_structure() {
915         return new external_single_structure(
916             array(
917                 'id' => new external_value(PARAM_INT, 'The id of the message'),
918                 'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
919                 'useridto' => new external_value(PARAM_INT, 'The id of the user who received the message'),
920                 'text' => new external_value(PARAM_RAW, 'The text of the message'),
921                 'displayblocktime' => new external_value(PARAM_BOOL, 'Should we display the block time?'),
922                 'blocktime' => new external_value(PARAM_NOTAGS, 'The time to display above the message'),
923                 'position' => new external_value(PARAM_ALPHA, 'The position of the text'),
924                 'timesent' => new external_value(PARAM_NOTAGS, 'The time the message was sent'),
925                 'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
926                 'isread' => new external_value(PARAM_INT, 'Determines if the message was read or not'),
927             )
928         );
929     }
931     /**
932      * Get messagearea search users in course parameters.
933      *
934      * @return external_function_parameters
935      * @since 3.2
936      */
937     public static function data_for_messagearea_search_users_in_course_parameters() {
938         return new external_function_parameters(
939             array(
940                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
941                 'courseid' => new external_value(PARAM_INT, 'The id of the course'),
942                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
943                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
944                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
945             )
946         );
947     }
949     /**
950      * Get messagearea search users in course results.
951      *
952      * @param int $userid The id of the user who is performing the search
953      * @param int $courseid The id of the course
954      * @param string $search The string being searched
955      * @param int $limitfrom
956      * @param int $limitnum
957      * @return stdClass
958      * @throws moodle_exception
959      * @since 3.2
960      */
961     public static function data_for_messagearea_search_users_in_course($userid, $courseid, $search, $limitfrom = 0,
962                                                                        $limitnum = 0) {
963         global $CFG, $PAGE, $USER;
965         // Check if messaging is enabled.
966         if (empty($CFG->messaging)) {
967             throw new moodle_exception('disabled', 'message');
968         }
970         $systemcontext = context_system::instance();
972         $params = array(
973             'userid' => $userid,
974             'courseid' => $courseid,
975             'search' => $search,
976             'limitfrom' => $limitfrom,
977             'limitnum' => $limitnum
978         );
979         self::validate_parameters(self::data_for_messagearea_search_users_in_course_parameters(), $params);
980         self::validate_context($systemcontext);
982         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
983             throw new moodle_exception('You do not have permission to perform this action.');
984         }
986         $users = \core_message\api::search_users_in_course($userid, $courseid, $search, $limitfrom, $limitnum);
987         $results = new \core_message\output\messagearea\user_search_results($users);
989         $renderer = $PAGE->get_renderer('core_message');
990         return $results->export_for_template($renderer);
991     }
993     /**
994      * Get messagearea search users in course returns.
995      *
996      * @return external_single_structure
997      * @since 3.2
998      */
999     public static function data_for_messagearea_search_users_in_course_returns() {
1000         return new external_single_structure(
1001             array(
1002                 'contacts' => new external_multiple_structure(
1003                     self::get_messagearea_contact_structure()
1004                 ),
1005             )
1006         );
1007     }
1009     /**
1010      * Get messagearea search users parameters.
1011      *
1012      * @return external_function_parameters
1013      * @since 3.2
1014      */
1015     public static function data_for_messagearea_search_users_parameters() {
1016         return new external_function_parameters(
1017             array(
1018                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1019                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1020                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1021             )
1022         );
1023     }
1025     /**
1026      * Get messagearea search users results.
1027      *
1028      * @param int $userid The id of the user who is performing the search
1029      * @param string $search The string being searched
1030      * @param int $limitnum
1031      * @return stdClass
1032      * @throws moodle_exception
1033      * @since 3.2
1034      */
1035     public static function data_for_messagearea_search_users($userid, $search, $limitnum = 0) {
1036         global $CFG, $PAGE, $USER;
1038         // Check if messaging is enabled.
1039         if (empty($CFG->messaging)) {
1040             throw new moodle_exception('disabled', 'message');
1041         }
1043         $systemcontext = context_system::instance();
1045         $params = array(
1046             'userid' => $userid,
1047             'search' => $search,
1048             'limitnum' => $limitnum
1049         );
1050         self::validate_parameters(self::data_for_messagearea_search_users_parameters(), $params);
1051         self::validate_context($systemcontext);
1053         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1054             throw new moodle_exception('You do not have permission to perform this action.');
1055         }
1057         list($contacts, $courses, $noncontacts) = \core_message\api::search_users($userid, $search, $limitnum);
1058         $search = new \core_message\output\messagearea\user_search_results($contacts, $courses, $noncontacts);
1060         $renderer = $PAGE->get_renderer('core_message');
1061         return $search->export_for_template($renderer);
1062     }
1064     /**
1065      * Get messagearea search users returns.
1066      *
1067      * @return external_single_structure
1068      * @since 3.2
1069      */
1070     public static function data_for_messagearea_search_users_returns() {
1071         return new external_single_structure(
1072             array(
1073                 'contacts' => new external_multiple_structure(
1074                     self::get_messagearea_contact_structure()
1075                 ),
1076                 'courses' => new external_multiple_structure(
1077                     new external_single_structure(
1078                         array(
1079                             'id' => new external_value(PARAM_INT, 'The course id'),
1080                             'shortname' => new external_value(PARAM_TEXT, 'The course shortname'),
1081                             'fullname' => new external_value(PARAM_TEXT, 'The course fullname'),
1082                         )
1083                     )
1084                 ),
1085                 'noncontacts' => new external_multiple_structure(
1086                     self::get_messagearea_contact_structure()
1087                 )
1088             )
1089         );
1090     }
1092     /**
1093      * Get messagearea search messages parameters.
1094      *
1095      * @return external_function_parameters
1096      * @since 3.2
1097      */
1098     public static function data_for_messagearea_search_messages_parameters() {
1099         return new external_function_parameters(
1100             array(
1101                 'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1102                 'search' => new external_value(PARAM_RAW, 'The string being searched'),
1103                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1104                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1105             )
1106         );
1107     }
1109     /**
1110      * Get messagearea search messages results.
1111      *
1112      * @param int $userid The id of the user who is performing the search
1113      * @param string $search The string being searched
1114      * @param int $limitfrom
1115      * @param int $limitnum
1116      * @return stdClass
1117      * @throws moodle_exception
1118      * @since 3.2
1119      */
1120     public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1121         global $CFG, $PAGE, $USER;
1123         // Check if messaging is enabled.
1124         if (empty($CFG->messaging)) {
1125             throw new moodle_exception('disabled', 'message');
1126         }
1128         $systemcontext = context_system::instance();
1130         $params = array(
1131             'userid' => $userid,
1132             'search' => $search,
1133             'limitfrom' => $limitfrom,
1134             'limitnum' => $limitnum
1136         );
1137         self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1138         self::validate_context($systemcontext);
1140         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1141             throw new moodle_exception('You do not have permission to perform this action.');
1142         }
1144         $messages = \core_message\api::search_messages($userid, $search, $limitfrom, $limitnum);
1145         $results = new \core_message\output\messagearea\message_search_results($messages);
1147         $renderer = $PAGE->get_renderer('core_message');
1148         return $results->export_for_template($renderer);
1149     }
1151     /**
1152      * Get messagearea search messages returns.
1153      *
1154      * @return external_single_structure
1155      * @since 3.2
1156      */
1157     public static function data_for_messagearea_search_messages_returns() {
1158         return new external_single_structure(
1159             array(
1160                 'contacts' => new external_multiple_structure(
1161                     self::get_messagearea_contact_structure()
1162                 )
1163             )
1164         );
1165     }
1167     /**
1168      * The messagearea conversations parameters.
1169      *
1170      * @return external_function_parameters
1171      * @since 3.2
1172      */
1173     public static function data_for_messagearea_conversations_parameters() {
1174         return new external_function_parameters(
1175             array(
1176                 'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1177                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1178                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1179             )
1180         );
1181     }
1183     /**
1184      * Get messagearea conversations.
1185      *
1186      * @param int $userid The id of the user who we are viewing conversations for
1187      * @param int $limitfrom
1188      * @param int $limitnum
1189      * @return stdClass
1190      * @throws moodle_exception
1191      * @since 3.2
1192      */
1193     public static function data_for_messagearea_conversations($userid, $limitfrom = 0, $limitnum = 0) {
1194         global $CFG, $PAGE, $USER;
1196         // Check if messaging is enabled.
1197         if (empty($CFG->messaging)) {
1198             throw new moodle_exception('disabled', 'message');
1199         }
1201         $systemcontext = context_system::instance();
1203         $params = array(
1204             'userid' => $userid,
1205             'limitfrom' => $limitfrom,
1206             'limitnum' => $limitnum
1207         );
1208         self::validate_parameters(self::data_for_messagearea_conversations_parameters(), $params);
1209         self::validate_context($systemcontext);
1211         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1212             throw new moodle_exception('You do not have permission to perform this action.');
1213         }
1215         $conversations = \core_message\api::get_conversations($userid, $limitfrom, $limitnum);
1216         $conversations = new \core_message\output\messagearea\contacts(null, $conversations);
1218         $renderer = $PAGE->get_renderer('core_message');
1219         return $conversations->export_for_template($renderer);
1220     }
1222     /**
1223      * The messagearea conversations return structure.
1224      *
1225      * @return external_single_structure
1226      * @since 3.2
1227      */
1228     public static function data_for_messagearea_conversations_returns() {
1229         return new external_single_structure(
1230             array(
1231                 'contacts' => new external_multiple_structure(
1232                     self::get_messagearea_contact_structure()
1233                 )
1234             )
1235         );
1236     }
1238     /**
1239      * The messagearea contacts return parameters.
1240      *
1241      * @return external_function_parameters
1242      * @since 3.2
1243      */
1244     public static function data_for_messagearea_contacts_parameters() {
1245         return self::data_for_messagearea_conversations_parameters();
1246     }
1248     /**
1249      * Get messagearea contacts parameters.
1250      *
1251      * @param int $userid The id of the user who we are viewing conversations for
1252      * @param int $limitfrom
1253      * @param int $limitnum
1254      * @return stdClass
1255      * @throws moodle_exception
1256      * @since 3.2
1257      */
1258     public static function data_for_messagearea_contacts($userid, $limitfrom = 0, $limitnum = 0) {
1259         global $CFG, $PAGE, $USER;
1261         // Check if messaging is enabled.
1262         if (empty($CFG->messaging)) {
1263             throw new moodle_exception('disabled', 'message');
1264         }
1266         $systemcontext = context_system::instance();
1268         $params = array(
1269             'userid' => $userid,
1270             'limitfrom' => $limitfrom,
1271             'limitnum' => $limitnum
1272         );
1273         self::validate_parameters(self::data_for_messagearea_contacts_parameters(), $params);
1274         self::validate_context($systemcontext);
1276         if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1277             throw new moodle_exception('You do not have permission to perform this action.');
1278         }
1280         $contacts = \core_message\api::get_contacts($userid, $limitfrom, $limitnum);
1281         $contacts = new \core_message\output\messagearea\contacts(null, $contacts);
1283         $renderer = $PAGE->get_renderer('core_message');
1284         return $contacts->export_for_template($renderer);
1285     }
1287     /**
1288      * The messagearea contacts return structure.
1289      *
1290      * @return external_single_structure
1291      * @since 3.2
1292      */
1293     public static function data_for_messagearea_contacts_returns() {
1294         return self::data_for_messagearea_conversations_returns();
1295     }
1297     /**
1298      * The messagearea messages parameters.
1299      *
1300      * @return external_function_parameters
1301      * @since 3.2
1302      */
1303     public static function data_for_messagearea_messages_parameters() {
1304         return new external_function_parameters(
1305             array(
1306                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1307                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1308                 'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1309                 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1310                 'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1311                 'timefrom' => new external_value(PARAM_INT,
1312                     'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1313             )
1314         );
1315     }
1317     /**
1318      * Get messagearea messages.
1319      *
1320      * @param int $currentuserid The current user's id
1321      * @param int $otheruserid The other user's id
1322      * @param int $limitfrom
1323      * @param int $limitnum
1324      * @param boolean $newest
1325      * @return stdClass
1326      * @throws moodle_exception
1327      * @since 3.2
1328      */
1329     public static function data_for_messagearea_messages($currentuserid, $otheruserid, $limitfrom = 0, $limitnum = 0,
1330                                                          $newest = false, $timefrom = 0) {
1331         global $CFG, $PAGE, $USER;
1333         // Check if messaging is enabled.
1334         if (empty($CFG->messaging)) {
1335             throw new moodle_exception('disabled', 'message');
1336         }
1338         $systemcontext = context_system::instance();
1340         $params = array(
1341             'currentuserid' => $currentuserid,
1342             'otheruserid' => $otheruserid,
1343             'limitfrom' => $limitfrom,
1344             'limitnum' => $limitnum,
1345             'newest' => $newest,
1346             'timefrom' => $timefrom,
1347         );
1348         self::validate_parameters(self::data_for_messagearea_messages_parameters(), $params);
1349         self::validate_context($systemcontext);
1351         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1352             throw new moodle_exception('You do not have permission to perform this action.');
1353         }
1355         if ($newest) {
1356             $sort = 'timecreated DESC';
1357         } else {
1358             $sort = 'timecreated ASC';
1359         }
1361         // We need to enforce a one second delay on messages to avoid race conditions of current
1362         // messages still being sent.
1363         //
1364         // There is a chance that we could request messages before the current time's
1365         // second has elapsed and while other messages are being sent in that same second. In which
1366         // case those messages will be lost.
1367         //
1368         // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1369         if (!empty($timefrom)) {
1370             $timeto = time() - 1;
1371         } else {
1372             $timeto = 0;
1373         }
1375         // No requesting messages from the current time, as stated above.
1376         if ($timefrom == time()) {
1377             $messages = [];
1378         } else {
1379             $messages = \core_message\api::get_messages($currentuserid, $otheruserid, $limitfrom,
1380                                                         $limitnum, $sort, $timefrom, $timeto);
1381         }
1383         $messages = new \core_message\output\messagearea\messages($currentuserid, $otheruserid, $messages);
1385         $renderer = $PAGE->get_renderer('core_message');
1386         return $messages->export_for_template($renderer);
1387     }
1389     /**
1390      * The messagearea messages return structure.
1391      *
1392      * @return external_single_structure
1393      * @since 3.2
1394      */
1395     public static function data_for_messagearea_messages_returns() {
1396         return new external_single_structure(
1397             array(
1398                 'iscurrentuser' => new external_value(PARAM_BOOL, 'Is the currently logged in user the user we are viewing
1399                     the messages on behalf of?'),
1400                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1401                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1402                 'otheruserfullname' => new external_value(PARAM_NOTAGS, 'The other user\'s fullname'),
1403                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1404                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1405                 'messages' => new external_multiple_structure(
1406                     self::get_messagearea_message_structure()
1407                 ),
1408                 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
1409             )
1410         );
1411     }
1413     /**
1414      * The get most recent message return parameters.
1415      *
1416      * @return external_function_parameters
1417      * @since 3.2
1418      */
1419     public static function data_for_messagearea_get_most_recent_message_parameters() {
1420         return new external_function_parameters(
1421             array(
1422                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1423                 'otheruserid' => new external_value(PARAM_INT, 'The other user\'s id'),
1424             )
1425         );
1426     }
1428     /**
1429      * Get the most recent message in a conversation.
1430      *
1431      * @param int $currentuserid The current user's id
1432      * @param int $otheruserid The other user's id
1433      * @return stdClass
1434      * @throws moodle_exception
1435      * @since 3.2
1436      */
1437     public static function data_for_messagearea_get_most_recent_message($currentuserid, $otheruserid) {
1438         global $CFG, $PAGE, $USER;
1440         // Check if messaging is enabled.
1441         if (empty($CFG->messaging)) {
1442             throw new moodle_exception('disabled', 'message');
1443         }
1445         $systemcontext = context_system::instance();
1447         $params = array(
1448             'currentuserid' => $currentuserid,
1449             'otheruserid' => $otheruserid
1450         );
1451         self::validate_parameters(self::data_for_messagearea_get_most_recent_message_parameters(), $params);
1452         self::validate_context($systemcontext);
1454         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1455             throw new moodle_exception('You do not have permission to perform this action.');
1456         }
1458         $message = \core_message\api::get_most_recent_message($currentuserid, $otheruserid);
1459         $message = new \core_message\output\messagearea\message($message);
1461         $renderer = $PAGE->get_renderer('core_message');
1462         return $message->export_for_template($renderer);
1463     }
1465     /**
1466      * The get most recent message return structure.
1467      *
1468      * @return external_single_structure
1469      * @since 3.2
1470      */
1471     public static function data_for_messagearea_get_most_recent_message_returns() {
1472         return self::get_messagearea_message_structure();
1473     }
1475     /**
1476      * The get profile parameters.
1477      *
1478      * @return external_function_parameters
1479      * @since 3.2
1480      */
1481     public static function data_for_messagearea_get_profile_parameters() {
1482         return new external_function_parameters(
1483             array(
1484                 'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1485                 'otheruserid' => new external_value(PARAM_INT, 'The id of the user whose profile we want to view'),
1486             )
1487         );
1488     }
1490     /**
1491      * Get the profile information for a contact.
1492      *
1493      * @param int $currentuserid The current user's id
1494      * @param int $otheruserid The id of the user whose profile we are viewing
1495      * @return stdClass
1496      * @throws moodle_exception
1497      * @since 3.2
1498      */
1499     public static function data_for_messagearea_get_profile($currentuserid, $otheruserid) {
1500         global $CFG, $PAGE, $USER;
1502         // Check if messaging is enabled.
1503         if (empty($CFG->messaging)) {
1504             throw new moodle_exception('disabled', 'message');
1505         }
1507         $systemcontext = context_system::instance();
1509         $params = array(
1510             'currentuserid' => $currentuserid,
1511             'otheruserid' => $otheruserid
1512         );
1513         self::validate_parameters(self::data_for_messagearea_get_profile_parameters(), $params);
1514         self::validate_context($systemcontext);
1516         if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1517             throw new moodle_exception('You do not have permission to perform this action.');
1518         }
1520         $profile = \core_message\api::get_profile($currentuserid, $otheruserid);
1521         $profile = new \core_message\output\messagearea\profile($profile);
1523         $renderer = $PAGE->get_renderer('core_message');
1524         return $profile->export_for_template($renderer);
1525     }
1527     /**
1528      * The get profile return structure.
1529      *
1530      * @return external_single_structure
1531      * @since 3.2
1532      */
1533     public static function data_for_messagearea_get_profile_returns() {
1534         return new external_single_structure(
1535             array(
1536                 'userid' => new external_value(PARAM_INT, 'The id of the user whose profile we are viewing'),
1537                 'email' => new external_value(core_user::get_property_type('email'), 'An email address'),
1538                 'country' => new external_value(PARAM_TEXT, 'Home country of the user'),
1539                 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user'),
1540                 'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1541                 'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1542                 'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1543                 'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1544                 'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1545                 'isblocked' => new external_value(PARAM_BOOL, 'Is the user blocked?'),
1546                 'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
1547             )
1548         );
1549     }
1551     /**
1552      * Get contacts parameters description.
1553      *
1554      * @return external_function_parameters
1555      * @since Moodle 2.5
1556      */
1557     public static function get_contacts_parameters() {
1558         return new external_function_parameters(array());
1559     }
1561     /**
1562      * Get contacts.
1563      *
1564      * @return external_description
1565      * @since Moodle 2.5
1566      */
1567     public static function get_contacts() {
1568         global $CFG, $PAGE, $USER;
1570         // Check if messaging is enabled.
1571         if (empty($CFG->messaging)) {
1572             throw new moodle_exception('disabled', 'message');
1573         }
1575         require_once($CFG->dirroot . '/user/lib.php');
1577         $allcontacts = array('online' => [], 'offline' => [], 'strangers' => []);
1578         $contacts = \core_message\api::get_contacts_with_unread_message_count($USER->id);
1579         foreach ($contacts as $contact) {
1580             // Set the mode.
1581             $mode = 'offline';
1582             if (\core_message\helper::is_online($contact->lastaccess)) {
1583                 $mode = 'online';
1584             }
1586             $newcontact = array(
1587                 'id' => $contact->id,
1588                 'fullname' => fullname($contact),
1589                 'unread' => $contact->messagecount
1590             );
1592             $userpicture = new user_picture($contact);
1593             $userpicture->size = 1; // Size f1.
1594             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1595             $userpicture->size = 0; // Size f2.
1596             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1598             $allcontacts[$mode][$contact->id] = $newcontact;
1599         }
1601         $strangers = \core_message\api::get_non_contacts_with_unread_message_count($USER->id);
1602         foreach ($strangers as $contact) {
1603             $newcontact = array(
1604                 'id' => $contact->id,
1605                 'fullname' => fullname($contact),
1606                 'unread' => $contact->messagecount
1607             );
1609             $userpicture = new user_picture($contact);
1610             $userpicture->size = 1; // Size f1.
1611             $newcontact['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1612             $userpicture->size = 0; // Size f2.
1613             $newcontact['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1615             $allcontacts['strangers'][$contact->id] = $newcontact;
1616         }
1618         // Add noreply user and support user to the list, if they don't exist.
1619         $supportuser = core_user::get_support_user();
1620         if (!isset($strangers[$supportuser->id]) && !$supportuser->deleted) {
1621             $supportuser->messagecount = message_count_unread_messages($USER, $supportuser);
1622             if ($supportuser->messagecount > 0) {
1623                 $supportuser->fullname = fullname($supportuser);
1624                 $supportuser->unread = $supportuser->messagecount;
1625                 $allcontacts['strangers'][$supportuser->id] = $supportuser;
1626             }
1627         }
1629         $noreplyuser = core_user::get_noreply_user();
1630         if (!isset($strangers[$noreplyuser->id]) && !$noreplyuser->deleted) {
1631             $noreplyuser->messagecount = message_count_unread_messages($USER, $noreplyuser);
1632             if ($noreplyuser->messagecount > 0) {
1633                 $noreplyuser->fullname = fullname($noreplyuser);
1634                 $noreplyuser->unread = $noreplyuser->messagecount;
1635                 $allcontacts['strangers'][$noreplyuser->id] = $noreplyuser;
1636             }
1637         }
1639         return $allcontacts;
1640     }
1642     /**
1643      * Get contacts return description.
1644      *
1645      * @return external_description
1646      * @since Moodle 2.5
1647      */
1648     public static function get_contacts_returns() {
1649         return new external_single_structure(
1650             array(
1651                 'online' => new external_multiple_structure(
1652                     new external_single_structure(
1653                         array(
1654                             'id' => new external_value(PARAM_INT, 'User ID'),
1655                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1656                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1657                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1658                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1659                         )
1660                     ),
1661                     'List of online contacts'
1662                 ),
1663                 'offline' => new external_multiple_structure(
1664                     new external_single_structure(
1665                         array(
1666                             'id' => new external_value(PARAM_INT, 'User ID'),
1667                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1668                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1669                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1670                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1671                         )
1672                     ),
1673                     'List of offline contacts'
1674                 ),
1675                 'strangers' => new external_multiple_structure(
1676                     new external_single_structure(
1677                         array(
1678                             'id' => new external_value(PARAM_INT, 'User ID'),
1679                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1680                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1681                             'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL),
1682                             'unread' => new external_value(PARAM_INT, 'Unread message count')
1683                         )
1684                     ),
1685                     'List of users that are not in the user\'s contact list but have sent a message'
1686                 )
1687             )
1688         );
1689     }
1691     /**
1692      * Search contacts parameters description.
1693      *
1694      * @return external_function_parameters
1695      * @since Moodle 2.5
1696      */
1697     public static function search_contacts_parameters() {
1698         return new external_function_parameters(
1699             array(
1700                 'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1701                 'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1702                     VALUE_DEFAULT, false)
1703             )
1704         );
1705     }
1707     /**
1708      * Search contacts.
1709      *
1710      * @param string $searchtext query string.
1711      * @param bool $onlymycourses limit the search to the user's courses only.
1712      * @return external_description
1713      * @since Moodle 2.5
1714      */
1715     public static function search_contacts($searchtext, $onlymycourses = false) {
1716         global $CFG, $USER, $PAGE;
1717         require_once($CFG->dirroot . '/user/lib.php');
1719         // Check if messaging is enabled.
1720         if (empty($CFG->messaging)) {
1721             throw new moodle_exception('disabled', 'message');
1722         }
1724         require_once($CFG->libdir . '/enrollib.php');
1726         $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1727         $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1729         // Extra validation, we do not allow empty queries.
1730         if ($params['searchtext'] === '') {
1731             throw new moodle_exception('querystringcannotbeempty');
1732         }
1734         $courseids = array();
1735         if ($params['onlymycourses']) {
1736             $mycourses = enrol_get_my_courses(array('id'));
1737             foreach ($mycourses as $mycourse) {
1738                 $courseids[] = $mycourse->id;
1739             }
1740         } else {
1741             $courseids[] = SITEID;
1742         }
1744         // Retrieving the users matching the query.
1745         $users = message_search_users($courseids, $params['searchtext']);
1746         $results = array();
1747         foreach ($users as $user) {
1748             $results[$user->id] = $user;
1749         }
1751         // Reorganising information.
1752         foreach ($results as &$user) {
1753             $newuser = array(
1754                 'id' => $user->id,
1755                 'fullname' => fullname($user)
1756             );
1758             // Avoid undefined property notice as phone not specified.
1759             $user->phone1 = null;
1760             $user->phone2 = null;
1762             $userpicture = new user_picture($user);
1763             $userpicture->size = 1; // Size f1.
1764             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1765             $userpicture->size = 0; // Size f2.
1766             $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1768             $user = $newuser;
1769         }
1771         return $results;
1772     }
1774     /**
1775      * Search contacts return description.
1776      *
1777      * @return external_description
1778      * @since Moodle 2.5
1779      */
1780     public static function search_contacts_returns() {
1781         return new external_multiple_structure(
1782             new external_single_structure(
1783                 array(
1784                     'id' => new external_value(PARAM_INT, 'User ID'),
1785                     'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1786                     'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1787                     'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1788                 )
1789             ),
1790             'List of contacts'
1791         );
1792     }
1794     /**
1795      * Get messages parameters description.
1796      *
1797      * @return external_function_parameters
1798      * @since 2.8
1799      */
1800     public static function get_messages_parameters() {
1801         return new external_function_parameters(
1802             array(
1803                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1804                 'useridfrom' => new external_value(
1805                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1806                     VALUE_DEFAULT, 0),
1807                 'type' => new external_value(
1808                     PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1809                     VALUE_DEFAULT, 'both'),
1810                 'read' => new external_value(PARAM_BOOL, 'true for getting read messages, false for unread', VALUE_DEFAULT, true),
1811                 'newestfirst' => new external_value(
1812                     PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1813                     VALUE_DEFAULT, true),
1814                 'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1815                 'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1816             )
1817         );
1818     }
1820     /**
1821      * Get messages function implementation.
1822      *
1823      * @since  2.8
1824      * @throws invalid_parameter_exception
1825      * @throws moodle_exception
1826      * @param  int      $useridto       the user id who received the message
1827      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
1828      * @param  string   $type           type of message to return, expected values: notifications, conversations and both
1829      * @param  bool     $read           true for retreiving read messages, false for unread
1830      * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
1831      * @param  int      $limitfrom      limit from
1832      * @param  int      $limitnum       limit num
1833      * @return external_description
1834      */
1835     public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = true,
1836                                         $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
1837         global $CFG, $USER;
1839         $warnings = array();
1841         $params = array(
1842             'useridto' => $useridto,
1843             'useridfrom' => $useridfrom,
1844             'type' => $type,
1845             'read' => $read,
1846             'newestfirst' => $newestfirst,
1847             'limitfrom' => $limitfrom,
1848             'limitnum' => $limitnum
1849         );
1851         $params = self::validate_parameters(self::get_messages_parameters(), $params);
1853         $context = context_system::instance();
1854         self::validate_context($context);
1856         $useridto = $params['useridto'];
1857         $useridfrom = $params['useridfrom'];
1858         $type = $params['type'];
1859         $read = $params['read'];
1860         $newestfirst = $params['newestfirst'];
1861         $limitfrom = $params['limitfrom'];
1862         $limitnum = $params['limitnum'];
1864         $allowedvalues = array('notifications', 'conversations', 'both');
1865         if (!in_array($type, $allowedvalues)) {
1866             throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
1867                 'allowed values are: ' . implode(',', $allowedvalues));
1868         }
1870         // Check if private messaging between users is allowed.
1871         if (empty($CFG->messaging)) {
1872             // If we are retreiving only conversations, and messaging is disabled, throw an exception.
1873             if ($type == "conversations") {
1874                 throw new moodle_exception('disabled', 'message');
1875             }
1876             if ($type == "both") {
1877                 $warning = array();
1878                 $warning['item'] = 'message';
1879                 $warning['itemid'] = $USER->id;
1880                 $warning['warningcode'] = '1';
1881                 $warning['message'] = 'Private messages (conversations) are not enabled in this site.
1882                     Only notifications will be returned';
1883                 $warnings[] = $warning;
1884             }
1885         }
1887         if (!empty($useridto)) {
1888             if (core_user::is_real_user($useridto)) {
1889                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
1890             } else {
1891                 throw new moodle_exception('invaliduser');
1892             }
1893         }
1895         if (!empty($useridfrom)) {
1896             // We use get_user here because the from user can be the noreply or support user.
1897             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
1898         }
1900         // Check if the current user is the sender/receiver or just a privileged user.
1901         if ($useridto != $USER->id and $useridfrom != $USER->id and
1902              !has_capability('moodle/site:readallmessages', $context)) {
1903             throw new moodle_exception('accessdenied', 'admin');
1904         }
1906         // Which type of messages to retrieve.
1907         $notifications = -1;
1908         if ($type != 'both') {
1909             $notifications = ($type == 'notifications') ? 1 : 0;
1910         }
1912         $orderdirection = $newestfirst ? 'DESC' : 'ASC';
1913         $sort = "mr.timecreated $orderdirection";
1915         if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
1916             $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
1918             // In some cases, we don't need to get the to/from user objects from the sql query.
1919             $userfromfullname = '';
1920             $usertofullname = '';
1922             // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
1923             if (!empty($useridto)) {
1924                 $usertofullname = fullname($userto, $canviewfullname);
1925                 // The user from may or may not be filled.
1926                 if (!empty($useridfrom)) {
1927                     $userfromfullname = fullname($userfrom, $canviewfullname);
1928                 }
1929             } else {
1930                 // If the useridto field is empty, the useridfrom must be filled.
1931                 $userfromfullname = fullname($userfrom, $canviewfullname);
1932             }
1933             foreach ($messages as $mid => $message) {
1935                 // Do not return deleted messages.
1936                 if (!$message->notification) {
1937                     if (($useridto == $USER->id and $message->timeusertodeleted) or
1938                         ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
1939                         unset($messages[$mid]);
1940                         continue;
1941                     }
1942                 }
1944                 // We need to get the user from the query.
1945                 if (empty($userfromfullname)) {
1946                     // Check for non-reply and support users.
1947                     if (core_user::is_real_user($message->useridfrom)) {
1948                         $user = new stdClass();
1949                         $user = username_load_fields_from_object($user, $message, 'userfrom');
1950                         $message->userfromfullname = fullname($user, $canviewfullname);
1951                     } else {
1952                         $user = core_user::get_user($message->useridfrom);
1953                         $message->userfromfullname = fullname($user, $canviewfullname);
1954                     }
1955                 } else {
1956                     $message->userfromfullname = $userfromfullname;
1957                 }
1959                 // We need to get the user from the query.
1960                 if (empty($usertofullname)) {
1961                     $user = new stdClass();
1962                     $user = username_load_fields_from_object($user, $message, 'userto');
1963                     $message->usertofullname = fullname($user, $canviewfullname);
1964                 } else {
1965                     $message->usertofullname = $usertofullname;
1966                 }
1968                 $message->text = message_format_message_text($message);
1969                 $messages[$mid] = (array) $message;
1970             }
1971         }
1973         $results = array(
1974             'messages' => $messages,
1975             'warnings' => $warnings
1976         );
1978         return $results;
1979     }
1981     /**
1982      * Get messages return description.
1983      *
1984      * @return external_single_structure
1985      * @since 2.8
1986      */
1987     public static function get_messages_returns() {
1988         return new external_single_structure(
1989             array(
1990                 'messages' => new external_multiple_structure(
1991                     new external_single_structure(
1992                         array(
1993                             'id' => new external_value(PARAM_INT, 'Message id'),
1994                             'useridfrom' => new external_value(PARAM_INT, 'User from id'),
1995                             'useridto' => new external_value(PARAM_INT, 'User to id'),
1996                             'subject' => new external_value(PARAM_TEXT, 'The message subject'),
1997                             'text' => new external_value(PARAM_RAW, 'The message text formated'),
1998                             'fullmessage' => new external_value(PARAM_RAW, 'The message'),
1999                             'fullmessageformat' => new external_format_value('fullmessage'),
2000                             'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2001                             'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2002                             'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2003                             'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2004                             'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2005                             'timecreated' => new external_value(PARAM_INT, 'Time created'),
2006                             'timeread' => new external_value(PARAM_INT, 'Time read'),
2007                             'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2008                             'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
2009                         ), 'message'
2010                     )
2011                 ),
2012                 'warnings' => new external_warnings()
2013             )
2014         );
2015     }
2017     /**
2018      * Mark all notifications as read parameters description.
2019      *
2020      * @return external_function_parameters
2021      * @since 3.2
2022      */
2023     public static function mark_all_notifications_as_read_parameters() {
2024         return new external_function_parameters(
2025             array(
2026                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2027                 'useridfrom' => new external_value(
2028                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2029                     VALUE_DEFAULT, 0),
2030             )
2031         );
2032     }
2034     /**
2035      * Mark all notifications as read function.
2036      *
2037      * @since  3.2
2038      * @throws invalid_parameter_exception
2039      * @throws moodle_exception
2040      * @param  int      $useridto       the user id who received the message
2041      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2042      * @return external_description
2043      */
2044     public static function mark_all_notifications_as_read($useridto, $useridfrom) {
2045         global $USER;
2047         $params = self::validate_parameters(
2048             self::mark_all_notifications_as_read_parameters(),
2049             array(
2050                 'useridto' => $useridto,
2051                 'useridfrom' => $useridfrom,
2052             )
2053         );
2055         $context = context_system::instance();
2056         self::validate_context($context);
2058         $useridto = $params['useridto'];
2059         $useridfrom = $params['useridfrom'];
2061         if (!empty($useridto)) {
2062             if (core_user::is_real_user($useridto)) {
2063                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2064             } else {
2065                 throw new moodle_exception('invaliduser');
2066             }
2067         }
2069         if (!empty($useridfrom)) {
2070             // We use get_user here because the from user can be the noreply or support user.
2071             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2072         }
2074         // Check if the current user is the sender/receiver or just a privileged user.
2075         if ($useridto != $USER->id and $useridfrom != $USER->id and
2076             // The deleteanymessage cap seems more reasonable here than readallmessages.
2077              !has_capability('moodle/site:deleteanymessage', $context)) {
2078             throw new moodle_exception('accessdenied', 'admin');
2079         }
2081         \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom);
2083         return true;
2084     }
2086     /**
2087      * Mark all notifications as read return description.
2088      *
2089      * @return external_single_structure
2090      * @since 3.2
2091      */
2092     public static function mark_all_notifications_as_read_returns() {
2093         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2094     }
2096     /**
2097      * Get unread conversations count parameters description.
2098      *
2099      * @return external_function_parameters
2100      * @since 3.2
2101      */
2102     public static function get_unread_conversations_count_parameters() {
2103         return new external_function_parameters(
2104             array(
2105                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2106             )
2107         );
2108     }
2110     /**
2111      * Get unread messages count function.
2112      *
2113      * @since  3.2
2114      * @throws invalid_parameter_exception
2115      * @throws moodle_exception
2116      * @param  int      $useridto       the user id who received the message
2117      * @return external_description
2118      */
2119     public static function get_unread_conversations_count($useridto) {
2120         global $USER, $CFG;
2122         // Check if messaging is enabled.
2123         if (empty($CFG->messaging)) {
2124             throw new moodle_exception('disabled', 'message');
2125         }
2127         $params = self::validate_parameters(
2128             self::get_unread_conversations_count_parameters(),
2129             array('useridto' => $useridto)
2130         );
2132         $context = context_system::instance();
2133         self::validate_context($context);
2135         $useridto = $params['useridto'];
2137         if (!empty($useridto)) {
2138             if (core_user::is_real_user($useridto)) {
2139                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2140             } else {
2141                 throw new moodle_exception('invaliduser');
2142             }
2143         } else {
2144             $useridto = $USER->id;
2145         }
2147         // Check if the current user is the receiver or just a privileged user.
2148         if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2149             throw new moodle_exception('accessdenied', 'admin');
2150         }
2152         return \core_message\api::count_unread_conversations($userto);
2153     }
2155     /**
2156      * Get unread conversations count return description.
2157      *
2158      * @return external_single_structure
2159      * @since 3.2
2160      */
2161     public static function get_unread_conversations_count_returns() {
2162         return new external_value(PARAM_INT, 'The count of unread messages for the user');
2163     }
2165     /**
2166      * Get blocked users parameters description.
2167      *
2168      * @return external_function_parameters
2169      * @since 2.9
2170      */
2171     public static function get_blocked_users_parameters() {
2172         return new external_function_parameters(
2173             array(
2174                 'userid' => new external_value(PARAM_INT,
2175                                 'the user whose blocked users we want to retrieve',
2176                                 VALUE_REQUIRED),
2177             )
2178         );
2179     }
2181     /**
2182      * Retrieve a list of users blocked
2183      *
2184      * @param  int $userid the user whose blocked users we want to retrieve
2185      * @return external_description
2186      * @since 2.9
2187      */
2188     public static function get_blocked_users($userid) {
2189         global $CFG, $USER, $PAGE;
2191         // Warnings array, it can be empty at the end but is mandatory.
2192         $warnings = array();
2194         // Validate params.
2195         $params = array(
2196             'userid' => $userid
2197         );
2198         $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2199         $userid = $params['userid'];
2201         // Validate context.
2202         $context = context_system::instance();
2203         self::validate_context($context);
2205         // Check if private messaging between users is allowed.
2206         if (empty($CFG->messaging)) {
2207             throw new moodle_exception('disabled', 'message');
2208         }
2210         $user = core_user::get_user($userid, '*', MUST_EXIST);
2211         core_user::require_active_user($user);
2213         // Check if we have permissions for retrieve the information.
2214         $capability = 'moodle/site:manageallmessaging';
2215         if (($USER->id != $userid) && !has_capability($capability, $context)) {
2216             throw new required_capability_exception($context, $capability, 'nopermissions', '');
2217         }
2219         // Now, we can get safely all the blocked users.
2220         $users = \core_message\api::get_blocked_users($user->id);
2222         $blockedusers = array();
2223         foreach ($users as $user) {
2224             $newuser = array(
2225                 'id' => $user->id,
2226                 'fullname' => fullname($user),
2227             );
2229             $userpicture = new user_picture($user);
2230             $userpicture->size = 1; // Size f1.
2231             $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2233             $blockedusers[] = $newuser;
2234         }
2236         $results = array(
2237             'users' => $blockedusers,
2238             'warnings' => $warnings
2239         );
2240         return $results;
2241     }
2243     /**
2244      * Get blocked users return description.
2245      *
2246      * @return external_single_structure
2247      * @since 2.9
2248      */
2249     public static function get_blocked_users_returns() {
2250         return new external_single_structure(
2251             array(
2252                 'users' => new external_multiple_structure(
2253                     new external_single_structure(
2254                         array(
2255                             'id' => new external_value(PARAM_INT, 'User ID'),
2256                             'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2257                             'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2258                         )
2259                     ),
2260                     'List of blocked users'
2261                 ),
2262                 'warnings' => new external_warnings()
2263             )
2264         );
2265     }
2267     /**
2268      * Returns description of method parameters
2269      *
2270      * @return external_function_parameters
2271      * @since 2.9
2272      */
2273     public static function mark_message_read_parameters() {
2274         return new external_function_parameters(
2275             array(
2276                 'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2277                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2278                     VALUE_DEFAULT, 0)
2279             )
2280         );
2281     }
2283     /**
2284      * Mark a single message as read, trigger message_viewed event
2285      *
2286      * @param  int $messageid id of the message (in the message table)
2287      * @param  int $timeread timestamp for when the message should be marked read
2288      * @return external_description
2289      * @throws invalid_parameter_exception
2290      * @throws moodle_exception
2291      * @since 2.9
2292      */
2293     public static function mark_message_read($messageid, $timeread) {
2294         global $CFG, $DB, $USER;
2296         // Check if private messaging between users is allowed.
2297         if (empty($CFG->messaging)) {
2298             throw new moodle_exception('disabled', 'message');
2299         }
2301         // Warnings array, it can be empty at the end but is mandatory.
2302         $warnings = array();
2304         // Validate params.
2305         $params = array(
2306             'messageid' => $messageid,
2307             'timeread' => $timeread
2308         );
2309         $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2311         if (empty($params['timeread'])) {
2312             $timeread = time();
2313         } else {
2314             $timeread = $params['timeread'];
2315         }
2317         // Validate context.
2318         $context = context_system::instance();
2319         self::validate_context($context);
2321         $sql = "SELECT m.*, mcm.userid as useridto
2322                   FROM {messages} m
2323             INNER JOIN {message_conversations} mc
2324                     ON m.conversationid = mc.id
2325             INNER JOIN {message_conversation_members} mcm
2326                     ON mcm.conversationid = mc.id
2327              LEFT JOIN {message_user_actions} mua
2328                     ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2329                  WHERE mua.id is NULL
2330                    AND mcm.userid != m.useridfrom
2331                    AND m.id = ?";
2332         $messageparams = [];
2333         $messageparams[] = $USER->id;
2334         $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2335         $messageparams[] = $params['messageid'];
2336         $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2338         if ($message->useridto != $USER->id) {
2339             throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2340         }
2342         \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2344         $results = array(
2345             'messageid' => $message->id,
2346             'warnings' => $warnings
2347         );
2348         return $results;
2349     }
2351     /**
2352      * Returns description of method result value
2353      *
2354      * @return external_description
2355      * @since 2.9
2356      */
2357     public static function mark_message_read_returns() {
2358         return new external_single_structure(
2359             array(
2360                 'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2361                 'warnings' => new external_warnings()
2362             )
2363         );
2364     }
2366     /**
2367      * Returns description of method parameters
2368      *
2369      * @return external_function_parameters
2370      */
2371     public static function mark_notification_read_parameters() {
2372         return new external_function_parameters(
2373             array(
2374                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2375                 'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2376                     VALUE_DEFAULT, 0)
2377             )
2378         );
2379     }
2381     /**
2382      * Mark a single notification as read.
2383      *
2384      * This will trigger a 'notification_viewed' event.
2385      *
2386      * @param int $notificationid id of the notification
2387      * @param int $timeread timestamp for when the notification should be marked read
2388      * @return external_description
2389      * @throws invalid_parameter_exception
2390      * @throws moodle_exception
2391      */
2392     public static function mark_notification_read($notificationid, $timeread) {
2393         global $CFG, $DB, $USER;
2395         // Check if private messaging between users is allowed.
2396         if (empty($CFG->messaging)) {
2397             throw new moodle_exception('disabled', 'message');
2398         }
2400         // Warnings array, it can be empty at the end but is mandatory.
2401         $warnings = array();
2403         // Validate params.
2404         $params = array(
2405             'notificationid' => $notificationid,
2406             'timeread' => $timeread
2407         );
2408         $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2410         if (empty($params['timeread'])) {
2411             $timeread = time();
2412         } else {
2413             $timeread = $params['timeread'];
2414         }
2416         // Validate context.
2417         $context = context_system::instance();
2418         self::validate_context($context);
2420         $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2422         if ($notification->useridto != $USER->id) {
2423             throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2424                 'notification as read');
2425         }
2427         \core_message\api::mark_notification_as_read($notification, $timeread);
2429         $results = array(
2430             'notificationid' => $notification->id,
2431             'warnings' => $warnings
2432         );
2434         return $results;
2435     }
2437     /**
2438      * Returns description of method result value
2439      *
2440      * @return external_description
2441      */
2442     public static function mark_notification_read_returns() {
2443         return new external_single_structure(
2444             array(
2445                 'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2446                 'warnings' => new external_warnings()
2447             )
2448         );
2449     }
2451     /**
2452      * Mark all messages as read parameters description.
2453      *
2454      * @return external_function_parameters
2455      * @since 3.2
2456      */
2457     public static function mark_all_messages_as_read_parameters() {
2458         return new external_function_parameters(
2459             array(
2460                 'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2461                 'useridfrom' => new external_value(
2462                     PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2463                     VALUE_DEFAULT, 0),
2464             )
2465         );
2466     }
2468     /**
2469      * Mark all notifications as read function.
2470      *
2471      * @since  3.2
2472      * @throws invalid_parameter_exception
2473      * @throws moodle_exception
2474      * @param  int      $useridto       the user id who received the message
2475      * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2476      * @return external_description
2477      */
2478     public static function mark_all_messages_as_read($useridto, $useridfrom) {
2479         global $USER, $CFG;
2481         // Check if messaging is enabled.
2482         if (empty($CFG->messaging)) {
2483             throw new moodle_exception('disabled', 'message');
2484         }
2486         $params = self::validate_parameters(
2487             self::mark_all_messages_as_read_parameters(),
2488             array(
2489                 'useridto' => $useridto,
2490                 'useridfrom' => $useridfrom,
2491             )
2492         );
2494         $context = context_system::instance();
2495         self::validate_context($context);
2497         $useridto = $params['useridto'];
2498         $useridfrom = $params['useridfrom'];
2500         if (!empty($useridto)) {
2501             if (core_user::is_real_user($useridto)) {
2502                 $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2503             } else {
2504                 throw new moodle_exception('invaliduser');
2505             }
2506         }
2508         if (!empty($useridfrom)) {
2509             // We use get_user here because the from user can be the noreply or support user.
2510             $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2511         }
2513         // Check if the current user is the sender/receiver or just a privileged user.
2514         if ($useridto != $USER->id and $useridfrom != $USER->id and
2515             // The deleteanymessage cap seems more reasonable here than readallmessages.
2516              !has_capability('moodle/site:deleteanymessage', $context)) {
2517             throw new moodle_exception('accessdenied', 'admin');
2518         }
2520         if ($useridfrom) {
2521             if ($conversationid = \core_message\api::get_conversation_between_users([$useridto, $useridfrom])) {
2522                 \core_message\api::mark_all_messages_as_read($useridto, $conversationid);
2523             }
2524         } else {
2525             \core_message\api::mark_all_messages_as_read($useridto);
2526         }
2528         return true;
2529     }
2531     /**
2532      * Mark all notifications as read return description.
2533      *
2534      * @return external_single_structure
2535      * @since 3.2
2536      */
2537     public static function mark_all_messages_as_read_returns() {
2538         return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2539     }
2541     /**
2542      * Returns description of method parameters.
2543      *
2544      * @deprecated since 3.6
2545      * @return external_function_parameters
2546      * @since 3.2
2547      */
2548     public static function delete_conversation_parameters() {
2549         return new external_function_parameters(
2550             array(
2551                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2552                 'otheruserid' => new external_value(PARAM_INT, 'The user id of the other user in the conversation'),
2553             )
2554         );
2555     }
2557     /**
2558      * Deletes a conversation.
2559      *
2560      * @deprecated since 3.6
2561      * @param int $userid The user id of who we want to delete the conversation for
2562      * @param int $otheruserid The user id of the other user in the conversation
2563      * @return array
2564      * @throws moodle_exception
2565      * @since 3.2
2566      */
2567     public static function delete_conversation($userid, $otheruserid) {
2568         global $CFG;
2570         // Check if private messaging between users is allowed.
2571         if (empty($CFG->messaging)) {
2572             throw new moodle_exception('disabled', 'message');
2573         }
2575         // Warnings array, it can be empty at the end but is mandatory.
2576         $warnings = array();
2578         // Validate params.
2579         $params = array(
2580             'userid' => $userid,
2581             'otheruserid' => $otheruserid,
2582         );
2583         $params = self::validate_parameters(self::delete_conversation_parameters(), $params);
2585         // Validate context.
2586         $context = context_system::instance();
2587         self::validate_context($context);
2589         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2590         core_user::require_active_user($user);
2592         if (!$conversationid = \core_message\api::get_conversation_between_users([$userid, $otheruserid])) {
2593             return [];
2594         }
2596         if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2597             \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2598             $status = true;
2599         } else {
2600             throw new moodle_exception('You do not have permission to delete messages');
2601         }
2603         $results = array(
2604             'status' => $status,
2605             'warnings' => $warnings
2606         );
2608         return $results;
2609     }
2611     /**
2612      * Returns description of method result value.
2613      *
2614      * @deprecated since 3.6
2615      * @return external_description
2616      * @since 3.2
2617      */
2618     public static function delete_conversation_returns() {
2619         return new external_single_structure(
2620             array(
2621                 'status' => new external_value(PARAM_BOOL, 'True if the conversation was deleted, false otherwise'),
2622                 'warnings' => new external_warnings()
2623             )
2624         );
2625     }
2627     /**
2628      * Marking the method as deprecated.
2629      *
2630      * @return bool
2631      */
2632     public static function delete_conversation_is_deprecated() {
2633         return true;
2634     }
2636     /**
2637      * Returns description of method parameters.
2638      *
2639      * @return external_function_parameters
2640      * @since 3.6
2641      */
2642     public static function delete_conversation_by_id_parameters() {
2643         return new external_function_parameters(
2644             array(
2645                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2646                 'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
2647             )
2648         );
2649     }
2651     /**
2652      * Deletes a conversation.
2653      *
2654      * @param int $userid The user id of who we want to delete the conversation for
2655      * @param int $conversationid The id of the conversation
2656      * @return array
2657      * @throws moodle_exception
2658      * @since 3.6
2659      */
2660     public static function delete_conversation_by_id($userid, $conversationid) {
2661         global $CFG;
2663         // Check if private messaging between users is allowed.
2664         if (empty($CFG->messaging)) {
2665             throw new moodle_exception('disabled', 'message');
2666         }
2668         // Validate params.
2669         $params = [
2670             'userid' => $userid,
2671             'conversationid' => $conversationid,
2672         ];
2673         $params = self::validate_parameters(self::delete_conversation_by_id_parameters(), $params);
2675         // Validate context.
2676         $context = context_system::instance();
2677         self::validate_context($context);
2679         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2680         core_user::require_active_user($user);
2682         if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2683             \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2684         } else {
2685             throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2686         }
2688         return [];
2689     }
2691     /**
2692      * Returns description of method result value.
2693      *
2694      * @return external_description
2695      * @since 3.6
2696      */
2697     public static function delete_conversation_by_id_returns() {
2698         return new external_warnings();
2699     }
2701     /**
2702      * Returns description of method parameters
2703      *
2704      * @return external_function_parameters
2705      * @since 3.1
2706      */
2707     public static function delete_message_parameters() {
2708         return new external_function_parameters(
2709             array(
2710                 'messageid' => new external_value(PARAM_INT, 'The message id'),
2711                 'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2712                 'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2713             )
2714         );
2715     }
2717     /**
2718      * Deletes a message
2719      *
2720      * @param  int $messageid the message id
2721      * @param  int $userid the user id of who we want to delete the message for
2722      * @param  bool $read if is a message read (default to true)
2723      * @return external_description
2724      * @throws moodle_exception
2725      * @since 3.1
2726      */
2727     public static function delete_message($messageid, $userid, $read = true) {
2728         global $CFG;
2730         // Check if private messaging between users is allowed.
2731         if (empty($CFG->messaging)) {
2732             throw new moodle_exception('disabled', 'message');
2733         }
2735         // Warnings array, it can be empty at the end but is mandatory.
2736         $warnings = array();
2738         // Validate params.
2739         $params = array(
2740             'messageid' => $messageid,
2741             'userid' => $userid,
2742             'read' => $read
2743         );
2744         $params = self::validate_parameters(self::delete_message_parameters(), $params);
2746         // Validate context.
2747         $context = context_system::instance();
2748         self::validate_context($context);
2750         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2751         core_user::require_active_user($user);
2753         if (\core_message\api::can_delete_message($user->id, $messageid)) {
2754             $status = \core_message\api::delete_message($user->id, $messageid);
2755         } else {
2756             throw new moodle_exception('You do not have permission to delete this message');
2757         }
2759         $results = array(
2760             'status' => $status,
2761             'warnings' => $warnings
2762         );
2763         return $results;
2764     }
2766     /**
2767      * Returns description of method result value
2768      *
2769      * @return external_description
2770      * @since 3.1
2771      */
2772     public static function delete_message_returns() {
2773         return new external_single_structure(
2774             array(
2775                 'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2776                 'warnings' => new external_warnings()
2777             )
2778         );
2779     }
2781     /**
2782      * Returns description of method parameters
2783      *
2784      * @return external_function_parameters
2785      * @since 3.2
2786      */
2787     public static function message_processor_config_form_parameters() {
2788         return new external_function_parameters(
2789             array(
2790                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2791                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor'),
2792                 'formvalues' => new external_multiple_structure(
2793                     new external_single_structure(
2794                         array(
2795                             'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2796                             'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2797                         )
2798                     ),
2799                     'Config form values',
2800                     VALUE_REQUIRED
2801                 ),
2802             )
2803         );
2804     }
2806     /**
2807      * Processes a message processor config form.
2808      *
2809      * @param  int $userid the user id
2810      * @param  string $name the name of the processor
2811      * @param  array $formvalues the form values
2812      * @return external_description
2813      * @throws moodle_exception
2814      * @since 3.2
2815      */
2816     public static function message_processor_config_form($userid, $name, $formvalues) {
2817         global $USER, $CFG;
2819         // Check if messaging is enabled.
2820         if (empty($CFG->messaging)) {
2821             throw new moodle_exception('disabled', 'message');
2822         }
2824         $params = self::validate_parameters(
2825             self::message_processor_config_form_parameters(),
2826             array(
2827                 'userid' => $userid,
2828                 'name' => $name,
2829                 'formvalues' => $formvalues,
2830             )
2831         );
2833         $user = self::validate_preferences_permissions($params['userid']);
2835         $processor = get_message_processor($name);
2836         $preferences = [];
2837         $form = new stdClass();
2839         foreach ($formvalues as $formvalue) {
2840             // Curly braces to ensure interpretation is consistent between
2841             // php 5 and php 7.
2842             $form->{$formvalue['name']} = $formvalue['value'];
2843         }
2845         $processor->process_form($form, $preferences);
2847         if (!empty($preferences)) {
2848             set_user_preferences($preferences, $userid);
2849         }
2850     }
2852     /**
2853      * Returns description of method result value
2854      *
2855      * @return external_description
2856      * @since 3.2
2857      */
2858     public static function message_processor_config_form_returns() {
2859         return null;
2860     }
2862     /**
2863      * Returns description of method parameters
2864      *
2865      * @return external_function_parameters
2866      * @since 3.2
2867      */
2868     public static function get_message_processor_parameters() {
2869         return new external_function_parameters(
2870             array(
2871                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2872                 'name' => new external_value(PARAM_TEXT, 'The name of the message processor', VALUE_REQUIRED),
2873             )
2874         );
2875     }
2877     /**
2878      * Get a message processor.
2879      *
2880      * @param int $userid
2881      * @param string $name the name of the processor
2882      * @return external_description
2883      * @throws moodle_exception
2884      * @since 3.2
2885      */
2886     public static function get_message_processor($userid = 0, $name) {
2887         global $USER, $PAGE, $CFG;
2889         // Check if messaging is enabled.
2890         if (empty($CFG->messaging)) {
2891             throw new moodle_exception('disabled', 'message');
2892         }
2894         $params = self::validate_parameters(
2895             self::get_message_processor_parameters(),
2896             array(
2897                 'userid' => $userid,
2898                 'name' => $name,
2899             )
2900         );
2902         if (empty($params['userid'])) {
2903             $params['userid'] = $USER->id;
2904         }
2906         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2907         core_user::require_active_user($user);
2908         self::validate_context(context_user::instance($params['userid']));
2910         $processor = get_message_processor($name);
2912         $processoroutput = new \core_message\output\processor($processor, $user);
2913         $renderer = $PAGE->get_renderer('core_message');
2915         return $processoroutput->export_for_template($renderer);
2916     }
2918     /**
2919      * Returns description of method result value
2920      *
2921      * @return external_description
2922      * @since 3.2
2923      */
2924     public static function get_message_processor_returns() {
2925         return new external_function_parameters(
2926             array(
2927                 'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2928                 'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2929             )
2930         );
2931     }
2933     /**
2934      * Check that the user has enough permission to retrieve message or notifications preferences.
2935      *
2936      * @param  int $userid the user id requesting the preferences
2937      * @return stdClass full user object
2938      * @throws moodle_exception
2939      * @since  Moodle 3.2
2940      */
2941     protected static function validate_preferences_permissions($userid) {
2942         global $USER;
2944         if (empty($userid)) {
2945             $user = $USER;
2946         } else {
2947             $user = core_user::get_user($userid, '*', MUST_EXIST);
2948             core_user::require_active_user($user);
2949         }
2951         $systemcontext = context_system::instance();
2952         self::validate_context($systemcontext);
2954         // Check access control.
2955         if ($user->id == $USER->id) {
2956             // Editing own message profile.
2957             require_capability('moodle/user:editownmessageprofile', $systemcontext);
2958         } else {
2959             // Teachers, parents, etc.
2960             $personalcontext = context_user::instance($user->id);
2961             require_capability('moodle/user:editmessageprofile', $personalcontext);
2962         }
2963         return $user;
2964     }
2966     /**
2967      * Returns a notification or message preference structure.
2968      *
2969      * @return external_single_structure the structure
2970      * @since  Moodle 3.2
2971      */
2972     protected static function get_preferences_structure() {
2973         return new external_single_structure(
2974             array(
2975                 'userid' => new external_value(PARAM_INT, 'User id'),
2976                 'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
2977                 'processors' => new external_multiple_structure(
2978                     new external_single_structure(
2979                         array(
2980                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2981                             'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
2982                             'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
2983                             'contextid' => new external_value(PARAM_INT, 'Context id'),
2984                             'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
2985                         )
2986                     ),
2987                     'Config form values'
2988                 ),
2989                 'components' => new external_multiple_structure(
2990                     new external_single_structure(
2991                         array(
2992                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2993                             'notifications' => new external_multiple_structure(
2994                                 new external_single_structure(
2995                                     array(
2996                                         'displayname' => new external_value(PARAM_TEXT, 'Display name'),
2997                                         'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
2998                                         'processors' => new external_multiple_structure(
2999                                             new external_single_structure(
3000                                                 array(
3001                                                     'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3002                                                     'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3003                                                     'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3004                                                     'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3005                                                     'loggedin' => new external_single_structure(
3006                                                         array(
3007                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
3008                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3009                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3010                                                         )
3011                                                     ),
3012                                                     'loggedoff' => new external_single_structure(
3013                                                         array(
3014                                                             'name' => new external_value(PARAM_NOTAGS, 'Name'),
3015                                                             'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3016                                                             'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3017                                                         )
3018                                                     ),
3019                                                 )
3020                                             ),
3021                                             'Processors values for this notification'
3022                                         ),
3023                                     )
3024                                 ),
3025                                 'List of notificaitons for the component'
3026                             ),
3027                         )
3028                     ),
3029                     'Available components'
3030                 ),
3031             )
3032         );
3033     }
3035     /**
3036      * Returns description of method parameters
3037      *
3038      * @return external_function_parameters
3039      * @since 3.2
3040      */
3041     public static function get_user_notification_preferences_parameters() {
3042         return new external_function_parameters(
3043             array(
3044                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3045             )
3046         );
3047     }
3049     /**
3050      * Get the notification preferences for a given user.
3051      *
3052      * @param int $userid id of the user, 0 for current user
3053      * @return external_description
3054      * @throws moodle_exception
3055      * @since 3.2
3056      */
3057     public static function get_user_notification_preferences($userid = 0) {
3058         global $PAGE;
3060         $params = self::validate_parameters(
3061             self::get_user_notification_preferences_parameters(),
3062             array(
3063                 'userid' => $userid,
3064             )
3065         );
3066         $user = self::validate_preferences_permissions($params['userid']);
3068         $processors = get_message_processors();
3069         $providers = message_get_providers_for_user($user->id);
3070         $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3071         $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3073         $renderer = $PAGE->get_renderer('core_message');
3075         $result = array(
3076             'warnings' => array(),
3077             'preferences' => $notificationlist->export_for_template($renderer)
3078         );
3079         return $result;
3080     }
3082     /**
3083      * Returns description of method result value
3084      *
3085      * @return external_description
3086      * @since 3.2
3087      */
3088     public static function get_user_notification_preferences_returns() {
3089         return new external_function_parameters(
3090             array(
3091                 'preferences' => self::get_preferences_structure(),
3092                 'warnings' => new external_warnings(),
3093             )
3094         );
3095     }
3097     /**
3098      * Returns description of method parameters
3099      *
3100      * @return external_function_parameters
3101      * @since 3.2
3102      */
3103     public static function get_user_message_preferences_parameters() {
3104         return new external_function_parameters(
3105             array(
3106                 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3107             )
3108         );
3109     }
3111     /**
3112      * Get the notification preferences for a given user.
3113      *
3114      * @param int $userid id of the user, 0 for current user
3115      * @return external_description
3116      * @throws moodle_exception
3117      * @since 3.2
3118      */
3119     public static function get_user_message_preferences($userid = 0) {
3120         global $PAGE;
3122         $params = self::validate_parameters(
3123             self::get_user_message_preferences_parameters(),
3124             array(
3125                 'userid' => $userid,
3126             )
3127         );
3129         $user = self::validate_preferences_permissions($params['userid']);
3131         // Filter out enabled, available system_configured and user_configured processors only.
3132         $readyprocessors = array_filter(get_message_processors(), function($processor) {
3133             return $processor->enabled &&
3134                 $processor->configured &&
3135                 $processor->object->is_user_configured() &&
3136                 // Filter out processors that don't have and message preferences to configure.
3137                 $processor->object->has_message_preferences();
3138         });
3140         $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
3141             return $provider->component === 'moodle';
3142         });
3143         $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
3144         $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
3145             $providers, $preferences, $user);
3147         $renderer = $PAGE->get_renderer('core_message');
3149         $result = array(
3150             'warnings' => array(),
3151             'preferences' => $notificationlistoutput->export_for_template($renderer),
3152             'blocknoncontacts' => get_user_preferences('message_blocknoncontacts', '', $user->id) ? true : false,
3153         );
3154         return $result;
3155     }
3157     /**
3158      * Returns description of method result value
3159      *
3160      * @return external_description
3161      * @since 3.2
3162      */
3163     public static function get_user_message_preferences_returns() {
3164         return new external_function_parameters(
3165             array(
3166                 'preferences' => self::get_preferences_structure(),
3167                 'blocknoncontacts' => new external_value(PARAM_BOOL, 'Whether to block or not messages from non contacts'),
3168                 'warnings' => new external_warnings(),
3169             )
3170         );
3171     }